diff options
Diffstat (limited to 'src/electronics/port.cpp')
-rw-r--r-- | src/electronics/port.cpp | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/src/electronics/port.cpp b/src/electronics/port.cpp new file mode 100644 index 0000000..541195b --- /dev/null +++ b/src/electronics/port.cpp @@ -0,0 +1,514 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "port.h" + +#include <kdebug.h> + +#include <errno.h> +#include <fcntl.h> +#include <linux/ppdev.h> +#include <sys/ioctl.h> +#include <unistd.h> + +//BEGIN class Port +Port::Port() +{ +} + + +Port::~Port() +{ +} + + +QStringList Port::ports( unsigned probeResult ) +{ + return SerialPort::ports(probeResult) + ParallelPort::ports(probeResult); +} +//END class Port + + + +//BEGIN class SerialPort +SerialPort::SerialPort() +{ + m_file = -1; +} + + +SerialPort::~SerialPort() +{ + closePort(); +} + + +void SerialPort::setPinState( Pin pin, bool state ) +{ + if ( m_file == -1 ) + return; + + int flags = -1; + + switch ( pin ) + { + case TD: + ioctl( m_file, state ? TIOCSBRK : TIOCCBRK, 0 ); + return; + + case DTR: + flags = TIOCM_DTR; + break; + + case DSR: + flags = TIOCM_DSR; + break; + + case RTS: + flags = TIOCM_RTS; + break; + + case CD: + case RD: + case GND: + case CTS: + case RI: + break; + }; + + if ( flags == -1 ) + { + kdError() << k_funcinfo << "Bad pin " << pin << endl; + return; + } + + if ( ioctl( m_file, state ? TIOCMBIS : TIOCMBIC, & flags ) == -1 ) + kdError() << k_funcinfo << "Could not set pin " << pin << " errno = " << errno << endl; +} + + +bool SerialPort::pinState( Pin pin ) +{ + if ( m_file == -1 ) + return false; + + int mask = 0; + + switch ( pin ) + { + case CD: + mask = TIOCM_CD; + break; + + case RD: + mask = TIOCM_SR; + break; + + case CTS: + mask = TIOCM_CTS; + break; + + case RI: + mask = TIOCM_RI; + break; + + case TD: + case DTR: + case GND: + case DSR: + case RTS: + break; + } + + if ( mask == 0 ) + { + kdError() << k_funcinfo << "Bad pin " << pin << endl; + return false; + } + + int bits = 0; + if ( ioctl( m_file, TIOCMGET, & bits ) == -1 ) + { + kdError() << k_funcinfo << "Could not read pin" << pin << " errno = " << errno << endl; + return false; + } + + return bits & mask; +} + + +Port::ProbeResult SerialPort::probe( const QString & port ) +{ + int file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDONLY ); + if ( file == -1 ) + return Port::DoesntExist; + + close(file); + + file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR ); + if ( file == -1 ) + return Port::ExistsButNotRW; + close(file); + + return Port::ExistsAndRW; +} + + +bool SerialPort::openPort( const QString & port, speed_t baudRate ) +{ + closePort(); + + m_file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR ); + if ( m_file == -1 ) + { + kdError() << k_funcinfo << "Could not open port " << port << endl; + return false; + } + + termios state; + tcgetattr( m_file, & state ); + + // Save the previous state for restoration in close. + m_previousState = state; + + state.c_iflag = IGNBRK | IGNPAR; + state.c_oflag = 0; + state.c_cflag = baudRate | CS8 | CREAD | CLOCAL; + state.c_lflag = 0; + tcsetattr( m_file, TCSANOW, & state ); + + return true; +} + + +void SerialPort::closePort() +{ + if ( m_file == -1 ) + return; + + ioctl( m_file, TIOCCBRK, 0 ); + usleep(1); + tcsetattr( m_file, TCSANOW, & m_previousState ); + close( m_file ); + m_file = -1; +} + + +QStringList SerialPort::ports( unsigned probeResult ) +{ + QStringList list; + + for ( int i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/ttyS%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/tts/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/ttyUSB%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/usb/tts/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + return list; +} +//END class SerialPort + + + +//BEGIN class ParallelPort +const int IRQ_MODE_BIT = 1 << 20; // Controls if pin 10 (Ack) causes interrupts +const int INPUT_MODE_BIT = 1 << 21; // Controls if the data pins are input or output +const int ALWAYS_INPUT_PINS = ParallelPort::STATUS_PINS; + +const int IOCTL_REG_READ[3] = { + PPRDATA, + PPRSTATUS, + PPRCONTROL, +}; + +const int IOCTL_REG_WRITE[3] = { + PPWDATA, + 0, + PPWCONTROL, +}; + +const int INVERT_MASK[3] = { + 0x0, + 0x80, // 10000000 + 0x0b, // 00001011 +}; + +ParallelPort::ParallelPort() +{ + reset(); +} + + +ParallelPort::~ParallelPort() +{ +} + + +void ParallelPort::reset() +{ + m_file = -1; + m_reg[Data] = 0; + m_reg[Status] = 0; + m_reg[Control] = 0; + m_outputPins = INPUT_MODE_BIT | IRQ_MODE_BIT; + m_inputPins = ALWAYS_INPUT_PINS | INPUT_MODE_BIT | IRQ_MODE_BIT; +} + + +//BEGIN Pin-oriented operations +void ParallelPort::setPinState( int pins, bool state ) +{ + // only allow writing to output pins + pins &= m_outputPins; + + if ( pins & DATA_PINS ) + setDataState( (pins & DATA_PINS) >> 0, state ); + + if ( pins & CONTROL_PINS ) + setControlState( (pins & CONTROL_PINS) >> 16, state ); +} + + +int ParallelPort::pinState( int pins ) +{ + int value = 0; + + // only allow reading from input pins + pins &= m_inputPins; + + if ( pins & DATA_PINS ) + value |= ((readFromRegister( Data ) & ((pins & DATA_PINS) >> 0)) << 0); + + if ( pins & STATUS_PINS ) + value |= ((readFromRegister( Status ) & ((pins & STATUS_PINS) >> 8)) << 8); + + if ( pins & CONTROL_PINS ) + value |= ((readFromRegister( Control ) & ((pins & CONTROL_PINS) >> 16)) << 16); + + return value; +} + + +void ParallelPort::setDataState( uchar pins, bool state ) +{ + uchar value = readFromRegister( Data ); + + if ( state ) + value |= pins; + else + value &= ~pins; + + writeToData( value ); +} + + +void ParallelPort::setControlState( uchar pins, bool state ) +{ + uchar value = readFromRegister( Control ); + + if ( state ) + value |= pins; + else + value &= ~pins; + + writeToControl( value ); +} +//END Pin-oriented operations + + + +//BEGIN Register-oriented operations +uchar ParallelPort::readFromRegister( Register reg ) +{ + if ( m_file == -1 ) + return 0; + +// uchar value = inb( m_lpBase + reg ) ^ INVERT_MASK[reg]; + uchar value = 0; + if ( ioctl( m_file, IOCTL_REG_READ[reg], &value ) ) + kdError() << k_funcinfo << "errno=" << errno << endl; + else + m_reg[reg] = value; + return value; +} + + +void ParallelPort::writeToRegister( Register reg, uchar value ) +{ + if ( m_file == -1 ) + return; + +// outb( value ^ INVERT_MASK[reg], m_lpBase + reg ); + if ( ioctl( m_file, IOCTL_REG_WRITE[reg], & value ) ) + kdError() << k_funcinfo << "errno=" << errno << endl; + else + m_reg[reg] = value; +} + + +void ParallelPort::writeToData( uchar value ) +{ + writeToRegister( Data, value ); +} + + +void ParallelPort::writeToControl( uchar value ) +{ + // Set all inputs to ones + value |= ((m_inputPins & CONTROL_PINS) >> 16); + + writeToRegister( Control, value ); +} +//END Register-oriented operations + + +//BEGIN Changing pin directions +void ParallelPort::setDataDirection( Direction dir ) +{ + if ( dir == Input ) + { + m_inputPins |= DATA_PINS; + m_outputPins &= ~DATA_PINS; + } + else + { + m_inputPins &= DATA_PINS; + m_outputPins |= ~DATA_PINS; + } + + setPinState( INPUT_MODE_BIT, dir == Input ); +} + + +void ParallelPort::setControlDirection( int pins, Direction dir ) +{ + pins &= CONTROL_PINS; + + if ( dir == Input ) + { + m_inputPins |= pins; + m_outputPins &= ~pins; + } + else + { + m_inputPins &= pins; + m_outputPins |= ~pins; + } + + setControlState( 0, true ); +} +//END Changing pin directions + + +Port::ProbeResult ParallelPort::probe( const QString & port ) +{ + int file = open( port.ascii(), O_RDWR ); + if ( file == -1 ) + return Port::DoesntExist; + + if ( ioctl( file, PPCLAIM ) != 0 ) + { + close(file); + return Port::ExistsButNotRW; + } + + ioctl( file, PPRELEASE ); + close(file); + return Port::ExistsAndRW; +} + + +QStringList ParallelPort::ports( unsigned probeResult ) +{ + QStringList list; + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/parport%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/parports/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + return list; +} + + +bool ParallelPort::openPort( const QString & port ) +{ + if ( m_file != -1 ) + { + kdWarning() << k_funcinfo << "Port already open" << endl; + return false; + } + + m_file = open( port.ascii(), O_RDWR ); + + if ( m_file == -1 ) + { + kdError() << k_funcinfo << "Could not open port \"" << port << "\": errno="<<errno<<endl; + return false; + } + + if ( ioctl( m_file, PPCLAIM ) ) + { + kdError() << k_funcinfo << "Port " << port << " must be RW" << endl; + close( m_file ); + m_file = -1; + return false; + } + + return true; +} + + +void ParallelPort::closePort() +{ + if ( m_file == -1 ) + return; + + int res = ioctl( m_file, PPRELEASE ); + close( m_file ); + + if ( res ) + kdError() << k_funcinfo << "res="<<res<<endl; + + m_file = -1; +} +//END class ParallelPort + |