Rivendellaudio/lib/rdttydevice.cpp
Fred Gleason fa894996a9 2020-02-14 Fred Gleason <fredg@paravelsystems.com>
* Fixed a regression in the BroadcastTools SS16.4 switcher driver
	that could cause deadlocks and intermittent operation.
2020-02-14 17:28:24 -05:00

612 lines
8.7 KiB
C++

// rdttydevice.cpp
//
// A Qt driver for tty ports.
//
// (C) Copyright 2010-1018 Fred Gleason <fredg@paravelsystems.com>
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library 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 <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "rdttydevice.h"
RDTTYDevice::RDTTYDevice(QObject *parent)
: QIODevice(parent)
{
tty_speed=9600;
tty_length=8;
tty_parity=RDTTYDevice::None;
tty_flow_control=RDTTYDevice::FlowNone;
tty_open=false;
tty_notifier=NULL;
tty_write_timer=new QTimer(this);
tty_write_timer->setSingleShot(false);
connect(tty_write_timer,SIGNAL(timeout()),this,SLOT(writeTtyData()));
}
RDTTYDevice::~RDTTYDevice()
{
close();
delete tty_write_timer;
}
bool RDTTYDevice::open(QIODevice::OpenMode mode)
{
int flags=O_NONBLOCK|O_NOCTTY;
struct termios term;
QIODevice::open(mode);
tty_mode=mode;
if((mode&QIODevice::ReadWrite)==QIODevice::ReadWrite) {
flags|=O_RDWR;
}
else {
if(((mode&QIODevice::WriteOnly)!=0)) {
flags|=O_WRONLY;
}
if(((mode&QIODevice::ReadOnly)!=0)) {
flags|=O_RDONLY;
}
}
if((mode&QIODevice::Append)!=0) {
flags|=O_APPEND;
}
if((mode&QIODevice::Truncate)!=0) {
flags|=O_TRUNC;
}
if((tty_fd=::open(tty_name.toAscii(),flags))<0) {
return false;
}
tty_open=true;
tcgetattr(tty_fd,&term);
//
// Set Speed
//
//cfsetispeed(&term,B0);
cfsetispeed(&term,tty_speed);
cfsetospeed(&term,tty_speed);
//
// Set Mode
//
cfmakeraw(&term);
term.c_iflag |= IGNBRK;
//
// Set Parity
//
switch(tty_parity) {
case RDTTYDevice::None:
term.c_iflag |= IGNPAR;
break;
case RDTTYDevice::Even:
term.c_cflag |= PARENB;
break;
case RDTTYDevice::Odd:
term.c_cflag |= PARENB|PARODD;
break;
}
//
// Set Word Length
//
//term.c_cflag &= ~CSIZE;
switch(tty_length) {
case 5:
term.c_cflag |= CS5;
break;
case 6:
term.c_cflag |= CS6;
break;
case 7:
term.c_cflag |= CS7;
break;
case 8:
term.c_cflag |= CS8;
break;
}
//
// Set Flow Control
//
switch(tty_flow_control) {
case RDTTYDevice::FlowNone:
term.c_cflag &= ~CRTSCTS;
term.c_iflag &= ~IXON;
term.c_iflag &= ~IXOFF;
break;
case RDTTYDevice::FlowRtsCts:
term.c_cflag |= CRTSCTS;
term.c_iflag &= ~IXON;
term.c_iflag &= ~IXOFF;
break;
case RDTTYDevice::FlowXonXoff:
term.c_cflag &= ~CRTSCTS;
term.c_iflag |= IXON;
term.c_iflag |= IXOFF;
break;
}
tcsetattr(tty_fd,TCSADRAIN,&term);
tty_notifier=new QSocketNotifier(tty_fd,QSocketNotifier::Read,this);
connect(tty_notifier,SIGNAL(activated(int)),this,SLOT(readTtyData(int)));
tty_write_timer->start(10);
return true;
}
void RDTTYDevice::close()
{
if(tty_open) {
emit aboutToClose();
tty_write_timer->stop();
delete tty_notifier;
tty_notifier=NULL;
::close(tty_fd);
if((tty_mode&QIODevice::ReadOnly)!=0) {
emit readChannelFinished();
}
}
tty_open=false;
}
QString RDTTYDevice::name() const
{
return tty_name;
}
void RDTTYDevice::setName(const QString &str)
{
tty_name=str;
}
qint64 RDTTYDevice::read(char *data,qint64 maxlen)
{
return readData(data,maxlen);
}
QByteArray RDTTYDevice::read(qint64 maxlen)
{
qint64 n=0;
char *data=new char[maxlen];
n=readData(data,maxlen);
QByteArray ret(data,n);
delete data;
return ret;
}
QByteArray RDTTYDevice::readAll()
{
return read(bytesAvailable());
}
qint64 RDTTYDevice::readBlock(char *data,qint64 maxlen)
{
return readData(data,maxlen);
}
qint64 RDTTYDevice::write(const char *data,qint64 len)
{
return writeData(data,len);
}
qint64 RDTTYDevice::write(const QByteArray &array)
{
return write(array.constData(),array.size());
}
bool RDTTYDevice::getChar(char *ch)
{
return readData(ch,1)==1;
}
bool RDTTYDevice::putChar(char ch)
{
return writeData(&ch,1)==1;
}
qint64 RDTTYDevice::size() const
{
return bytesAvailable();
}
qint64 RDTTYDevice::bytesAvailable() const
{
int val=0;
if(tty_open) {
ioctl(tty_fd,FIONREAD,&val);
}
return val;
}
qint64 RDTTYDevice::bytesToWrite() const
{
int val=0;
if(tty_open) {
ioctl(tty_fd,TIOCOUTQ,&val);
}
return val;
}
bool RDTTYDevice::isSequential() const
{
return true;
}
bool RDTTYDevice::isReadable() const
{
return((tty_mode&QIODevice::ReadOnly)!=0)||
((tty_mode&QIODevice::ReadWrite)!=0);
}
bool RDTTYDevice::isWritable() const
{
return ((tty_mode&QIODevice::WriteOnly)!=0)||
((tty_mode&QIODevice::ReadWrite)!=0);
}
bool RDTTYDevice::isOpen() const
{
return tty_open;
}
QString RDTTYDevice::deviceName() const
{
return tty_name;
}
void RDTTYDevice::setDeviceName(QString name)
{
tty_name=name;
}
int RDTTYDevice::speed() const
{
switch(tty_speed) {
case B0:
return 0;
break;
case B50:
return 50;
break;
case B75:
return 75;
break;
case B110:
return 110;
break;
case B134:
return 134;
break;
case B150:
return 150;
break;
case B200:
return 200;
break;
case B300:
return 300;
break;
case B600:
return 600;
break;
case B1200:
return 1200;
break;
case B1800:
return 1800;
break;
case B2400:
return 2400;
break;
case B4800:
return 4800;
break;
case B9600:
return 9600;
break;
case B19200:
return 19200;
break;
case B38400:
return 38400;
break;
case B57600:
return 57600;
break;
case B115200:
return 115200;
break;
case B230400:
return 230400;
break;
}
return 0;
}
void RDTTYDevice::setSpeed(int speed)
{
switch(speed) {
case 0:
tty_speed=B0;
break;
case 50:
tty_speed=B50;
break;
case 75:
tty_speed=B75;
break;
case 110:
tty_speed=B110;
break;
case 134:
tty_speed=B134;
break;
case 150:
tty_speed=B150;
break;
case 200:
tty_speed=B200;
break;
case 300:
tty_speed=B300;
break;
case 600:
tty_speed=B600;
break;
case 1200:
tty_speed=B1200;
break;
case 1800:
tty_speed=B1800;
break;
case 2400:
tty_speed=B2400;
break;
case 4800:
tty_speed=B4800;
break;
case 9600:
tty_speed=B9600;
break;
case 19200:
tty_speed=B19200;
break;
case 38400:
tty_speed=B38400;
break;
case 57600:
tty_speed=B57600;
break;
case 115200:
tty_speed=B115200;
break;
case 230400:
tty_speed=B230400;
break;
default:
tty_speed=B9600;
break;
}
}
int RDTTYDevice::wordLength() const
{
switch(tty_length) {
case CS5:
return 5;
break;
case CS6:
return 6;
break;
case CS7:
return 7;
break;
case CS8:
return 8;
break;
}
return 0;
}
void RDTTYDevice::setWordLength(int length)
{
switch(length) {
case 5:
tty_length=CS5;
break;
case 6:
tty_length=CS6;
break;
case 7:
tty_length=CS7;
break;
case 8:
tty_length=CS8;
break;
default:
tty_length=CS8;
break;
}
}
RDTTYDevice::Parity RDTTYDevice::parity() const
{
return tty_parity;
}
void RDTTYDevice::setParity(Parity parity)
{
tty_parity=parity;
}
RDTTYDevice::FlowControl RDTTYDevice::flowControl() const
{
return tty_flow_control;
}
void RDTTYDevice::setFlowControl(FlowControl ctrl)
{
tty_flow_control=ctrl;
}
int RDTTYDevice::fileDescriptor() const
{
return tty_fd;
}
qint64 RDTTYDevice::readData(char *data,qint64 maxlen)
{
qint64 n;
if((n=::read(tty_fd,data,(size_t)maxlen))<0) {
return 0;
}
return n;
}
qint64 RDTTYDevice::writeData(const char *data,qint64 len)
{
for(qint64 i=0;i<len;i++) {
tty_write_queue.push(data[i]);
}
emit bytesWritten(len);
return len;
}
void RDTTYDevice::readTtyData(int sock)
{
emit readyRead();
}
void RDTTYDevice::writeTtyData()
{
char data[2048];
int bytes=0;
ioctl(tty_fd,TIOCOUTQ,&bytes);
int n=2048-bytes;
if((int)tty_write_queue.size()<n) {
n=tty_write_queue.size();
}
if(n==0) {
return;
}
for(ssize_t i=0;i<n;i++) {
data[i]=tty_write_queue.front();
tty_write_queue.pop();
}
::write(tty_fd,data,n);
}