* Copyright 2002-2004, Marcus Overhagen, Stefano Ceccherini.
* All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <List.h>
#include <SerialPort.h>
#include <new>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#define SERIAL_DIR "/dev/ports"
static int32
scan_directory(const char *directory, BList *list)
{
BEntry entry;
BDirectory dir(SERIAL_DIR);
char buf[B_OS_NAME_LENGTH];
ASSERT(list != NULL);
while (dir.GetNextEntry(&entry) == B_OK) {
entry.GetName(buf);
list->AddItem(strdup(buf));
};
return list->CountItems();
}
Query the driver, and builds a list of the available
serial ports.
The BSerialPort object is initialized to these values:
- \c B_19200_BPS
- \c B_DATA_BITS_8
- \c B_STOP_BIT_1
- \c B_NO_PARITY
- \c B_HARDWARE_CONTROL
- \c B_INFINITE_TIMEOUT
- Blocking mode
*/
BSerialPort::BSerialPort()
:
ffd(-1),
fBaudRate(B_19200_BPS),
fDataBits(B_DATA_BITS_8),
fStopBits(B_STOP_BIT_1),
fParityMode(B_NO_PARITY),
fFlow(B_HARDWARE_CONTROL),
fTimeout(B_INFINITE_TIMEOUT),
fBlocking(true),
fDevices(new(std::nothrow) BList)
{
_ScanDevices();
}
Closes the port, if it's open, and deletes the devices list.
*/
BSerialPort::~BSerialPort()
{
if (ffd >= 0)
close(ffd);
if (fDevices != NULL) {
for (int32 count = fDevices->CountItems() - 1; count >= 0; count--)
free(fDevices->RemoveItem(count));
delete fDevices;
}
}
\param portName A valid port name
(i.e."/dev/ports/serial2", "serial2", ...)
\return
- A positive number if the serialport has been succesfully opened.
- An errorcode (negative integer) if not.
*/
status_t
BSerialPort::Open(const char *portName)
{
char buf[64];
if (portName == NULL)
return B_BAD_VALUE;
if (portName[0] != '/')
snprintf(buf, 64, SERIAL_DIR"/%s", portName);
else
snprintf(buf, 64, "%s", portName);
if (ffd >= 0)
close(ffd);
ffd = open(buf, O_RDWR | O_NONBLOCK | O_EXCL);
if (ffd >= 0) {
int flags = fcntl(ffd, F_GETFL);
fcntl(ffd, F_SETFL, flags & ~O_NONBLOCK);
_DriverControl();
}
return (ffd >= 0) ? ffd : errno;
}
*/
void
BSerialPort::Close(void)
{
if (ffd >= 0)
close(ffd);
ffd = -1;
}
\param buf The buffer where to copy the data.
\param count The maximum amount of bytes to read.
\return The amount of data read.
*/
ssize_t
BSerialPort::Read(void *buf, size_t count)
{
ssize_t err = read(ffd, buf, count);
return (err >= 0) ? err : errno;
}
\param buf The buffer which copy the data from.
\param count The amount of bytes to write.
*/
ssize_t
BSerialPort::Write(const void *buf, size_t count)
{
ssize_t err = write(ffd, buf, count);
return (err >= 0) ? err : errno;
}
\param Blocking If true, enables the blocking mode. If false, disables it.
*/
void
BSerialPort::SetBlocking(bool Blocking)
{
fBlocking = Blocking;
_DriverControl();
}
\param microSeconds The timeout for the port.
Valid values are:
- \c B_INFINITE_TIMEOUT
- Any value between 0 and 25,000,000, but remember that the granularity
of the serial driver is 100,000 microseconds.
*/
status_t
BSerialPort::SetTimeout(bigtime_t microSeconds)
{
status_t err = B_BAD_VALUE;
if (microSeconds == B_INFINITE_TIMEOUT || microSeconds <= 25000000) {
fTimeout = microSeconds;
_DriverControl();
err = B_OK;
}
return err;
}
\param bitsPerSeconds The baud rate.
Valid values:
- \c B_0_BPS
- \c B_50_BPS
- \c B_75_BPS
- \c B_110_BPS
- \c B_134_BPS
- \c B_150_BPS
- \c B_200_BPS
- \c B_300_BPS
- \c B_600_BPS
- \c B_1200_BPS
- \c B_1800_BPS
- \c B_2400_BPS
- \c B_4800_BPS
- \c B_9600_BPS
- \c B_19200_BPS
- \c B_38400_BPS
- \c B_57600_BPS
- \c B_115200_BPS
- \c B_230400_BPS
- \c B_31250_BPS
\return
- \c B_OK if all goes fine,
- an error code if something goes wrong.
*/
status_t
BSerialPort::SetDataRate(data_rate bitsPerSecond)
{
fBaudRate = bitsPerSecond;
return _DriverControl();
}
\return The current Baud Rate.
*/
data_rate
BSerialPort::DataRate(void)
{
return fBaudRate;
}
*/
void
BSerialPort::SetDataBits(data_bits numBits)
{
fDataBits = numBits;
_DriverControl();
}
\return The current data bits.
*/
data_bits
BSerialPort::DataBits(void)
{
return fDataBits;
}
\param numBits The number of stop bits
Valid values:
- \c B_STOP_BITS_1 (or \c B_STOP_BIT_1)
- \c B_STOP_BITS_2
*/
void
BSerialPort::SetStopBits(stop_bits numBits)
{
fStopBits = numBits;
_DriverControl();
}
\return The current stop bits.
*/
stop_bits
BSerialPort::StopBits(void)
{
return fStopBits;
}
\param which The parity mode to set.
Valid values:
- \c B_ODD_PARITY
- \c B_EVEN_PARITY
- \c B_NO_PARITY
*/
void
BSerialPort::SetParityMode(parity_mode which)
{
fParityMode = which;
_DriverControl();
}
\return The current parity mode.
*/
parity_mode
BSerialPort::ParityMode(void)
{
return fParityMode;
}
*/
void
BSerialPort::ClearInput(void)
{
tcflush(ffd, TCIFLUSH);
}
*/
void
BSerialPort::ClearOutput(void)
{
tcflush(ffd, TCOFLUSH);
}
\param method The type of flow control.
Valid values:
- \c B_HARDWARE_CONTROL
- \c B_SOFTWARE_CONTROL
- \c B_NOFLOW_CONTROL
*/
void
BSerialPort::SetFlowControl(uint32 method)
{
fFlow = method;
_DriverControl();
}
\return The flow control for the current open port.
*/
uint32
BSerialPort::FlowControl(void)
{
return fFlow;
}
status_t
BSerialPort::SetDTR(bool asserted)
{
status_t status = ioctl(ffd, TCSETDTR, &asserted, sizeof(asserted));
return (status >= 0) ? status : errno;
}
status_t
BSerialPort::SetRTS(bool asserted)
{
status_t status = ioctl(ffd, TCSETRTS, &asserted, sizeof(asserted));
return (status >= 0) ? status : errno;
}
\param numChars A pointer to an int32 where you want
that value stored.
\return ?
*/
status_t
BSerialPort::NumCharsAvailable(int32 *numChars)
{
if (ffd < 0)
return B_NO_INIT;
if (numChars)
*numChars = 0;
return B_OK;
}
\return true if CTS is asserted, false if not.
*/
bool
BSerialPort::IsCTS(void)
{
unsigned int bits = ioctl(ffd, TCGETBITS, 0);
if (bits & TCGB_CTS)
return true;
return false;
}
\return true if DSR is asserted, false if not.
*/
bool
BSerialPort::IsDSR(void)
{
unsigned int bits = ioctl(ffd, TCGETBITS, 0);
if (bits & TCGB_DSR)
return true;
return false;
}
\return true if RI is asserted, false if not.
*/
bool
BSerialPort::IsRI(void)
{
unsigned int bits = ioctl(ffd, TCGETBITS, 0);
if (bits & TCGB_RI)
return true;
return false;
}
\return true if DCD is asserted, false if not.
*/
bool
BSerialPort::IsDCD(void)
{
unsigned int bits = ioctl(ffd, TCGETBITS, 0);
if (bits & TCGB_DCD)
return true;
return false;
}
If no data is ready, it will always block, ignoring the
value of SetBlocking(); however, it respects the timeout
set by SetTimeout().
\return The number of bytes available to be read.
*/
ssize_t
BSerialPort::WaitForInput(void)
{
object_wait_info info[1];
info[0].type = B_OBJECT_TYPE_FD;
info[0].object = ffd;
info[0].events = B_EVENT_READ | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
status_t status = wait_for_objects_etc(info, 1, B_RELATIVE_TIMEOUT, fTimeout);
if (status < 0)
return status;
int size;
if (ioctl(ffd, FIONREAD, &size, sizeof(size)) < 0)
return errno;
return size;
}
\return An integer which represents the number of available
serial ports.
*/
int32
BSerialPort::CountDevices()
{
int32 count = 0;
_ScanDevices();
if (fDevices != NULL)
count = fDevices->CountItems();
return count;
}
\param n Number of the device you want to know the name of.
\param name The buffer where you want to store the name.
\param bufSize The size of the buffer.
\return
- \c B_ERROR if something goes wrong
- \c B_OK if all goes fine.
*/
status_t
BSerialPort::GetDeviceName(int32 n, char *name, size_t bufSize)
{
status_t result = B_ERROR;
const char *dev = NULL;
if (fDevices != NULL)
dev = static_cast<char*>(fDevices->ItemAt(n));
if (dev != NULL && name != NULL) {
strncpy(name, dev, bufSize);
name[bufSize - 1] = '\0';
result = B_OK;
}
return result;
}
Query the serial driver about the available devices,
and build a list of them.
*/
void
BSerialPort::_ScanDevices()
{
if (fDevices != NULL) {
for (int32 count = fDevices->CountItems() - 1; count >= 0; count--)
free(fDevices->RemoveItem(count));
scan_directory(SERIAL_DIR, fDevices);
}
}
\return
- \c B_OK if all goes fine,
- an error code if something goes wrong.
*/
int
BSerialPort::_DriverControl()
{
struct termios options;
int err;
if (ffd < 0)
return B_NO_INIT;
err = tcgetattr(ffd, &options);
if (err < 0)
return errno;
options.c_iflag &= ~(IXON | IXOFF | IXANY | INPCK);
options.c_cflag &= ~(CRTSCTS | CSIZE | CSTOPB | PARODD | PARENB);
options.c_lflag &= ~(ECHO | ECHONL | ISIG | ICANON);
options.c_cflag |= CLOCAL;
if (fFlow & B_HARDWARE_CONTROL)
options.c_cflag |= CRTSCTS;
if (fFlow & B_SOFTWARE_CONTROL)
options.c_iflag |= (IXON | IXOFF);
if (fStopBits & B_STOP_BITS_2)
options.c_cflag |= CSTOPB;
if (fDataBits & B_DATA_BITS_8)
options.c_cflag |= CS8;
if (fParityMode != B_NO_PARITY) {
options.c_cflag |= PARENB;
if (fParityMode == B_ODD_PARITY)
options.c_cflag |= PARODD;
}
cfsetispeed(&options, fBaudRate);
cfsetospeed(&options, fBaudRate);
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 0;
if (fBlocking) {
if (fTimeout == B_INFINITE_TIMEOUT) {
options.c_cc[VMIN] = 1;
} else if (fTimeout != 0) {
int timeout = fTimeout / 100000;
options.c_cc[VTIME] = (timeout == 0) ? 1 : timeout;
}
}
err = tcsetattr(ffd, TCSANOW, &options);
return (err >= 0) ? err : errno;
}
void BSerialPort::_ReservedSerialPort1() {}
void BSerialPort::_ReservedSerialPort2() {}
void BSerialPort::_ReservedSerialPort3() {}
void BSerialPort::_ReservedSerialPort4() {}