nidas
v1.2-1520
|
A serial port. More...
#include <SerialPortIODevice.h>
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::Termios & | termios () |
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 |
A serial port.
|
inline |
Constructor.
Does not open any actual device.
References _termios, nidas::util::Termios::setRaw(), nidas::util::Termios::setRawLength(), and nidas::util::Termios::setRawTimeout().
|
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().
|
inline |
Destructor.
Does not close the device.
|
inline |
Apply the current Termios to an opened port.
References nidas::core::UnixIODevice::_fd, _termios, nidas::util::Termios::apply(), and nidas::core::IODevice::getName().
Referenced by nidas::core::SerialSensor::applyTermios().
|
inlinevirtualinherited |
close the device
Implements nidas::core::IODevice.
References nidas::core::UnixIODevice::_fd, fd, and nidas::core::IODevice::getName().
|
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().
|
inlinevirtualinherited |
References nidas::core::IODevice::_devname.
Referenced by applyTermios(), nidas::core::TCPSocketIODevice::close(), nidas::core::UDPSocketIODevice::close(), nidas::core::ServerSocketIODevice::close(), nidas::core::UnixIODevice::close(), nidas::core::IODevice::getBytesAvailable(), nidas::core::SocketIODevice::ioctl(), nidas::core::ServerSocketIODevice::ioctl(), nidas::core::UnixIODevice::ioctl(), nidas::core::SocketIODevice::open(), nidas::core::ServerSocketIODevice::open(), nidas::core::UnixIODevice::open(), nidas::core::UnixIODevice::read(), and nidas::core::UnixIODevice::write().
|
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().
|
inlinevirtualinherited |
The file descriptor used when writing to this device.
Implements nidas::core::IODevice.
References nidas::core::UnixIODevice::_fd.
|
inlinevirtualinherited |
Implements nidas::core::IODevice.
References nidas::core::UnixIODevice::_fd, and nidas::core::IODevice::getName().
|
virtual |
open the device.
Implements nidas::core::IODevice.
|
inlinevirtualinherited |
Read from the device.
Implements nidas::core::IODevice.
References nidas::core::UnixIODevice::_fd, nidas::core::IODevice::getName(), and len.
|
virtualinherited |
Read from the device with a timeout in milliseconds.
Implements nidas::core::IODevice.
References len, MSECS_PER_SEC, and NSECS_PER_MSEC.
|
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().
|
inline |
References _termios.
Referenced by nidas::core::SerialSensor::applyTermios(), and nidas::core::SerialSensor::buildIODevice().
|
virtual |
|
protectedinherited |
|
protected |
|
protected |
Referenced by applyTermios(), SerialPortIODevice(), and termios().
|
protected |