nidas  v1.2-1520
Public Member Functions | Protected Attributes | List of all members
nidas::core::SerialPortIODevice Class Reference

A serial port. More...

#include <SerialPortIODevice.h>

Inheritance diagram for nidas::core::SerialPortIODevice:
Inheritance graph
[legend]

Public Member Functions

 SerialPortIODevice ()
 Constructor. More...
 
 SerialPortIODevice (const std::string &name)
 Constructor, passing the name of the device. More...
 
 ~SerialPortIODevice ()
 Destructor. More...
 
void open (int flags) throw (nidas::util::IOException)
 open the device. More...
 
void applyTermios () throw (nidas::util::IOException)
 Apply the current Termios to an opened port. More...
 
nidas::util::Termiostermios ()
 
int getUsecsPerByte () const
 Calculate the transmission time of each byte from this serial port. More...
 
void setRTS485 (int val) throw (nidas::util::IOException)
 Is this a RS485 half-duplex device, and if so, can the transmitter on the data system be enabled/disabled by setting/clearing RTS? If so, then RTS will be cleared when the device is opened, and set while writing to the device. More...
 
size_t write (const void *buf, size_t len) throw (nidas::util::IOException)
 Write to the device. More...
 
int getReadFd () const
 The file descriptor used when reading from this device. More...
 
int getWriteFd () const
 The file descriptor used when writing to this device. More...
 
size_t read (void *buf, size_t len) throw (nidas::util::IOException)
 Read from the device. More...
 
size_t read (void *buf, size_t len, int msecTimeout) throw (nidas::util::IOException)
 Read from the device with a timeout in milliseconds. More...
 
void ioctl (int request, void *buf, size_t) throw (nidas::util::IOException)
 
void close () throw (nidas::util::IOException)
 close the device More...
 
virtual void setName (const std::string &val)
 Set the device name to be opened for this sensor. More...
 
virtual const std::string & getName () const
 
virtual size_t getBytesAvailable () const throw (nidas::util::IOException)
 Return how many bytes are available to read on this IODevice. More...
 

Protected Attributes

nidas::util::Termios _termios
 
int _rts485
 
unsigned int _usecsperbyte
 
int _fd
 

Detailed Description

A serial port.

Constructor & Destructor Documentation

nidas::core::SerialPortIODevice::SerialPortIODevice ( )
inline
nidas::core::SerialPortIODevice::SerialPortIODevice ( const std::string &  name)
inline

Constructor, passing the name of the device.

Does not open the device.

References _termios, nidas::util::Termios::setRaw(), nidas::util::Termios::setRawLength(), and nidas::util::Termios::setRawTimeout().

nidas::core::SerialPortIODevice::~SerialPortIODevice ( )
inline

Destructor.

Does not close the device.

Member Function Documentation

void nidas::core::SerialPortIODevice::applyTermios ( )
throw (nidas::util::IOException
)
inline
void nidas::core::UnixIODevice::close ( )
throw (nidas::util::IOException
)
inlinevirtualinherited
virtual size_t nidas::core::IODevice::getBytesAvailable ( ) const
throw (nidas::util::IOException
)
inlinevirtualinherited

Return how many bytes are available to read on this IODevice.

This method is only useful when ioctl FIONREAD is supported on this this IODevice, as for example with a UDP socket. It is not available, and not necessary, on most other devices, like serial ports, TCP sockets, or devices with nidas driver module support, in which case it will return an nidas::util::IOException. It is an optimization for use with UDP sockets, where after select determines that data is available on the socket file descriptor, a read will only read one datagram, even if there are more than one packet available, which would not be optimal if a sensor generated many small packets. Rather than returning back to select, we check if there are more datagrams to read. This is not necessary on other types of IODevices, where it is just a matter of using a big enough buffer to get all (or most) available data after a select.

According to man udp(7), FIONREAD will return 0 if the size of the next packet is 0. So, if select/poll indicate there is data available, one read at least should be done, just in case a sensor sends a datagram of length 0, otherwise it will never be consumed.

References err, nidas::core::IODevice::getName(), nidas::core::IODevice::getReadFd(), and nidas::core::IODevice::ioctl().

Referenced by nidas::core::DSMSensor::getBytesAvailable().

virtual const std::string& nidas::core::IODevice::getName ( ) const
inlinevirtualinherited
int nidas::core::UnixIODevice::getReadFd ( ) const
inlinevirtualinherited

The file descriptor used when reading from this device.

Implements nidas::core::IODevice.

References nidas::core::UnixIODevice::_fd.

int SerialPortIODevice::getUsecsPerByte ( ) const

Calculate the transmission time of each byte from this serial port.

For RS232/485/422 serial ports is it simply calculated as (databits + stopbits + 1) / baudrate converted to microseconds. This value is used by MessageStreamScanners to guess at the time that the first byte of a buffer was sent, knowing the arrival time of that buffer of characters. In the absence of further information, this corrected transmission time is then used as the sample time.

This method checks if the underlying IODevice is a tty, returning a value of 0 usecs if it is not a tty, such as for a socket. Therefore the IODevice should exist and be open for this method to work correctly. In Sensor::open(), the IODevice is built, then opened, and then the SampleScanner is created, which is when this method should be called.

It will return 0 for socket devices.

References nidas::util::Termios::EVEN, nidas::util::Termios::NONE, nidas::util::Termios::ODD, and USECS_PER_SEC.

Referenced by nidas::core::SerialSensor::getUsecsPerByte().

int nidas::core::UnixIODevice::getWriteFd ( ) const
inlinevirtualinherited

The file descriptor used when writing to this device.

Implements nidas::core::IODevice.

References nidas::core::UnixIODevice::_fd.

void nidas::core::UnixIODevice::ioctl ( int  request,
void *  buf,
size_t   
)
throw (nidas::util::IOException
)
inlinevirtualinherited
void SerialPortIODevice::open ( int  flags)
throw (nidas::util::IOException
)
virtual

open the device.

Implements nidas::core::IODevice.

size_t nidas::core::UnixIODevice::read ( void *  buf,
size_t  len 
)
throw (nidas::util::IOException
)
inlinevirtualinherited
size_t UnixIODevice::read ( void *  buf,
size_t  len,
int  msecTimeout 
)
throw (nidas::util::IOException
)
virtualinherited

Read from the device with a timeout in milliseconds.

Implements nidas::core::IODevice.

References len, MSECS_PER_SEC, and NSECS_PER_MSEC.

virtual void nidas::core::IODevice::setName ( const std::string &  val)
inlinevirtualinherited

Set the device name to be opened for this sensor.

References nidas::core::IODevice::_devname.

Referenced by nidas::core::UnixIODevice::UnixIODevice().

void SerialPortIODevice::setRTS485 ( int  val)
throw (nidas::util::IOException
)

Is this a RS485 half-duplex device, and if so, can the transmitter on the data system be enabled/disabled by setting/clearing RTS? If so, then RTS will be cleared when the device is opened, and set while writing to the device.

If is often the case that one must disable the local transmitter in order to receive characters over half-duplex 485, otherwise the transmitter clobbers the signal levels. On serial interfaces that support rs232,422 and 485 protocols, it is common that that the transmitter can be enabled/disabled with RTS from the UART when the interface is configured for 485 mode.

This RTS control of the transmitter in 485 mode is available on port 4 of Eurotech Vipers and Titans, and on all ports of the Diamond Emerald cards.

The best situation is if automatic control of RTS on 485 accesses is supported on the UART and supported for that UART in the kernel. This provides precise timing, so that the transmitter is enabled precisely while bit transmits are taking place.

Automatic RTS control is available on the Exar XR16C285x UARTS of the Eurotech Vipers and Titans. It is not available on the ST16C554 on the Diamond Emerald serial card. However, I don't see kernel support for this on Exars in the mainline kernel, even as recent as 3.8.2. Patches are floating around.

If automatic RTS control is available in the kernel, there will be ioctl macros TIOCGRS485/TIOCSRS485 in /usr/include/asm-generic/ioctls.h, and struct serial_rs485 in /usr/include/linux/serial.h. Presumably if the request is not supported on a given UART, you'll get an EINVAL.

See the kernel documentation: Documentation/serial/serial-rs485.txt

Since kernel support is not available for this on the kernels and UARTs we are using, code for the above ioctls is not yet in NIDAS.

Without hardware and kernel support for automatic RTS control with 485, we have to resort to inexact control of RTS from user space code. This will probably result in loss of data if the remote device answers back too quickly after a write to the device. Since this software control is not great, 485 is best used for read-only devices. Use 232 or 422 if you need read/write.

Referenced by nidas::core::SerialSensor::buildIODevice().

nidas::util::Termios& nidas::core::SerialPortIODevice::termios ( )
inline
size_t SerialPortIODevice::write ( const void *  buf,
size_t  len 
)
throw (nidas::util::IOException
)
virtual

Write to the device.

Implements nidas::core::IODevice.

References len.

Member Data Documentation

int nidas::core::UnixIODevice::_fd
protectedinherited
int nidas::core::SerialPortIODevice::_rts485
protected
nidas::util::Termios nidas::core::SerialPortIODevice::_termios
protected
unsigned int nidas::core::SerialPortIODevice::_usecsperbyte
protected

The documentation for this class was generated from the following files: