30.11.2013 - New PICollection namespace, Android support, my own PIVector implementation
This commit is contained in:
395
piserial.cpp
395
piserial.cpp
@@ -19,39 +19,49 @@
|
||||
|
||||
#include "piserial.h"
|
||||
#include "piconfig.h"
|
||||
#include "pidir.h"
|
||||
|
||||
|
||||
PISerial::PISerial(const PIString & device, void * data_, ReadRetFunc slot): PIIODevice(device, ReadWrite) {
|
||||
/*! \class PISerial
|
||||
* \brief Serial device
|
||||
*
|
||||
* \section PISerial_sec0 Synopsis
|
||||
* This class provide access to serial device, e.g. COM port. It can read,
|
||||
* write, wait for write. There are several read and write functions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
||||
piMonitor.serials++;
|
||||
setPriority(piHigh);
|
||||
path_ = device;
|
||||
data = data_;
|
||||
fd = -1;
|
||||
headerPtr = 0;
|
||||
block_read = true;
|
||||
params = 0;
|
||||
ispeed = ospeed = S115200;
|
||||
vtime = 1;
|
||||
ret_func_ = slot;
|
||||
#ifdef WINDOWS
|
||||
hCom = 0;
|
||||
#endif
|
||||
ispeed = ospeed = S115200;
|
||||
dbits = 8;
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
PISerial::PISerial(void * data_, ReadRetFunc slot): PIIODevice("", ReadWrite) {
|
||||
PISerial::PISerial(const PIString & device_, PISerial::Speed speed_, PIFlags<PISerial::Parameters> params_): PIIODevice(device_, ReadWrite) {
|
||||
piMonitor.serials++;
|
||||
setPriority(piHigh);
|
||||
data = data_;
|
||||
path_ = device_;
|
||||
fd = -1;
|
||||
headerPtr = 0;
|
||||
params = 0;
|
||||
block_read = true;
|
||||
params = params_;
|
||||
ispeed = ospeed = speed_;
|
||||
vtime = 1;
|
||||
ret_func_ = slot;
|
||||
#ifdef WINDOWS
|
||||
hCom = 0;
|
||||
#endif
|
||||
ispeed = ospeed = S115200;
|
||||
dbits = 8;
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -104,16 +114,16 @@ bool PISerial::isPin(int number) const {
|
||||
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
||||
#ifndef WINDOWS
|
||||
if (fd < 0) {
|
||||
piCoutObj << "set" << bname << " error: \"" << path_ << "\" is not opened!";
|
||||
piCoutObj << "setBit" << bname << " error: \"" << path_ << "\" is not opened!";
|
||||
return false;
|
||||
}
|
||||
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
|
||||
piCoutObj << "set" << bname << " error: " << errorString();
|
||||
piCoutObj << "setBit" << bname << " error: " << errorString();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
piCoutObj << "set" << bname << " doesn`t implemented on Windows, sorry :-(";
|
||||
piCoutObj << "setBit" << bname << " doesn`t implemented on Windows, sorry :-(";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -122,15 +132,15 @@ bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
||||
bool PISerial::isBit(int bit, const PIString & bname) const {
|
||||
#ifndef WINDOWS
|
||||
if (fd < 0) {
|
||||
piCoutObj << "is" << bname << " error: \"" << path_ << "\" is not opened!";
|
||||
piCoutObj << "isBit" << bname << " error: \"" << path_ << "\" is not opened!";
|
||||
return false;
|
||||
}
|
||||
int ret = 0;
|
||||
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
||||
piCoutObj << "is" << bname << " error: " << errorString();
|
||||
piCoutObj << "isBit" << bname << " error: " << errorString();
|
||||
return ret & bit;
|
||||
#else
|
||||
piCoutObj << "set" << bname << " doesn`t implemented on Windows, sorry :-(";
|
||||
piCoutObj << "isBit" << bname << " doesn`t implemented on Windows, sorry :-(";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -142,20 +152,18 @@ bool PISerial::closeDevice() {
|
||||
stop();
|
||||
PIThread::terminate();
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
if (fd != -1) {
|
||||
#ifdef WINDOWS
|
||||
SetCommState(hCom, &sdesc);
|
||||
SetCommMask(hCom, mask);
|
||||
CloseHandle(hCom);
|
||||
fd = -1;
|
||||
}
|
||||
hCom = 0;
|
||||
#else
|
||||
if (fd != -1) {
|
||||
tcsetattr(fd, TCSANOW, &sdesc);
|
||||
::close(fd);
|
||||
#endif
|
||||
fd = -1;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -187,8 +195,16 @@ int PISerial::convertSpeed(PISerial::Speed speed) {
|
||||
}
|
||||
|
||||
|
||||
/** \brief Advanced read function
|
||||
* \details Read to pointer "read_to" no more than "max_size" and no longer
|
||||
* than "timeout_ms" milliseconds. If "timeout_ms" < 0 function will be
|
||||
* wait forever until "max_size" will be readed. If size <= 0 function
|
||||
* immediate returns \b false. For read data with unknown size use function
|
||||
* \a readData().
|
||||
* \returns \b True if readed bytes count = "max_size", else \b false
|
||||
* \sa \a readData() */
|
||||
bool PISerial::read(void * data, int size, double timeout_ms) {
|
||||
if (data == 0) return false;
|
||||
if (data == 0 || size <= 0) return false;
|
||||
int ret, all = 0;
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
@@ -215,50 +231,19 @@ bool PISerial::read(void * data, int size, double timeout_ms) {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PISerial::readData(int size, double timeout_ms) {
|
||||
int ret, all = 0;
|
||||
uchar td[1024];
|
||||
PIByteArray str;
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
timer.reset();
|
||||
if (size <= 0) {
|
||||
while (timer.elapsed_m() < timeout_ms) {
|
||||
ret = ::read(fd, td, 1024);
|
||||
if (ret <= 0) msleep(1);
|
||||
else str << PIByteArray(td, ret);
|
||||
}
|
||||
} else {
|
||||
while (all < size && timer.elapsed_m() < timeout_ms) {
|
||||
ret = ::read(fd, td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str << PIByteArray(td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setReadIsBlocking(true);
|
||||
all = ::read(fd, td, 1);
|
||||
str << PIByteArray(td, all);
|
||||
while (all < size) {
|
||||
ret = ::read(fd, td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str << PIByteArray(td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Advanced read function
|
||||
* \details Read all or no more than "size" and no longer than
|
||||
* "timeout_ms" milliseconds. If "timeout_ms" < 0 function will be
|
||||
* wait forever until "size" will be readed. If "size" <= 0
|
||||
* function will be read all until "timeout_ms" elaped. \n If size <= 0
|
||||
* and "timeout_ms" <= 0 function immediate returns empty string.
|
||||
* \n This function similar to \a readData() but returns data as string.
|
||||
* \sa \a readData() */
|
||||
PIString PISerial::read(int size, double timeout_ms) {
|
||||
PIString str;
|
||||
if (size <= 0 && timeout_ms <= 0.) return str;
|
||||
int ret, all = 0;
|
||||
uchar td[1024];
|
||||
PIString str;
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
timer.reset();
|
||||
@@ -291,6 +276,57 @@ PIString PISerial::read(int size, double timeout_ms) {
|
||||
}
|
||||
}
|
||||
}
|
||||
received(str.data(), str.size_s());
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Advanced read function
|
||||
* \details Read all or no more than "size" and no longer than
|
||||
* "timeout_ms" milliseconds. If "timeout_ms" < 0 function will be
|
||||
* wait forever until "size" will be readed. If "size" <= 0
|
||||
* function will be read all until "timeout_ms" elaped. \n If size <= 0
|
||||
* and "timeout_ms" <= 0 function immediate returns empty byte array.
|
||||
* \n This function similar to \a read() but returns data as byte array.
|
||||
* \sa \a read() */
|
||||
PIByteArray PISerial::readData(int size, double timeout_ms) {
|
||||
PIByteArray str;
|
||||
if (size <= 0 && timeout_ms <= 0.) return str;
|
||||
int ret, all = 0;
|
||||
uchar td[1024];
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
timer.reset();
|
||||
if (size <= 0) {
|
||||
while (timer.elapsed_m() < timeout_ms) {
|
||||
ret = ::read(fd, td, 1024);
|
||||
if (ret <= 0) msleep(1);
|
||||
else str.append(td, ret);
|
||||
}
|
||||
} else {
|
||||
while (all < size && timer.elapsed_m() < timeout_ms) {
|
||||
ret = ::read(fd, td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str.append(td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setReadIsBlocking(true);
|
||||
all = ::read(fd, td, 1);
|
||||
str.append(td, all);
|
||||
while (all < size) {
|
||||
ret = ::read(fd, td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str.append(td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
received(str.data(), str.size_s());
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -301,41 +337,12 @@ bool PISerial::openDevice() {
|
||||
if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;}
|
||||
if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;}
|
||||
hCom = CreateFileA(path_.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
if(hCom == INVALID_HANDLE_VALUE) {
|
||||
if (hCom == INVALID_HANDLE_VALUE) {
|
||||
piCoutObj << "Unable to open \"" << path_ << "\"";
|
||||
fd = -1;
|
||||
return false;
|
||||
}
|
||||
fd = 0;
|
||||
COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = vtime;
|
||||
times.ReadTotalTimeoutConstant = 1;
|
||||
times.ReadTotalTimeoutMultiplier = 0;
|
||||
times.WriteTotalTimeoutConstant = 1;
|
||||
times.WriteTotalTimeoutMultiplier = 0;
|
||||
if (SetCommTimeouts(hCom, ×) == -1) {
|
||||
piCoutObj << "Unable to set timeouts for \"" << path_ << "\"";
|
||||
CloseHandle(hCom);
|
||||
fd = -1;
|
||||
return false;
|
||||
}
|
||||
GetCommMask(hCom, &mask);
|
||||
SetCommMask(hCom, EV_RXCHAR);
|
||||
GetCommState(hCom, &sdesc);
|
||||
desc = sdesc;
|
||||
desc.DCBlength = sizeof(desc);
|
||||
desc.BaudRate = convertSpeed(ispeed);
|
||||
desc.ByteSize = 8;
|
||||
if (params[PISerial::ParityControl]) {
|
||||
desc.fParity = 1;
|
||||
desc.Parity = params[PISerial::ParityOdd] ? 1 : 2;
|
||||
}
|
||||
desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
|
||||
if (SetCommState(hCom, &desc) == -1) {
|
||||
piCoutObj << "Unable to set comm state for \"" << path_ << "\"";
|
||||
CloseHandle(hCom);
|
||||
fd = -1;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int om = 0;
|
||||
switch (mode_) {
|
||||
@@ -345,17 +352,62 @@ bool PISerial::openDevice() {
|
||||
}
|
||||
//cout << "init ser " << path_ << " mode " << om << " param " << params << endl;
|
||||
fd = ::open(path_.data(), O_NOCTTY | om);
|
||||
if(fd == -1) {
|
||||
if (fd == -1) {
|
||||
piCoutObj << "Unable to open \"" << path_ << "\"";
|
||||
return false;
|
||||
}
|
||||
|
||||
tcgetattr(fd, &desc);
|
||||
sdesc = desc;
|
||||
desc.c_iflag = desc.c_oflag = desc.c_lflag = desc.c_cflag = 0;
|
||||
desc.c_cflag = CLOCAL | CSIZE | CS8;
|
||||
//piCoutObj << "Initialized " << path_;
|
||||
#endif
|
||||
applySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PISerial::applySettings() {
|
||||
#ifdef WINDOWS
|
||||
if (fd == -1) return;
|
||||
COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = block_read ? vtime : MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = block_read ? 1 : 0;
|
||||
times.ReadTotalTimeoutMultiplier = 0;
|
||||
times.WriteTotalTimeoutConstant = 1;
|
||||
times.WriteTotalTimeoutMultiplier = 0;
|
||||
if (SetCommTimeouts(hCom, ×) == -1)
|
||||
piCoutObj << "Unable to set timeouts for \"" << path_ << "\"";
|
||||
GetCommMask(hCom, &mask);
|
||||
SetCommMask(hCom, EV_RXCHAR);
|
||||
GetCommState(hCom, &sdesc);
|
||||
desc = sdesc;
|
||||
desc.DCBlength = sizeof(desc);
|
||||
desc.BaudRate = convertSpeed(ispeed);
|
||||
if (dbits >= 5 && dbits <= 8)
|
||||
desc.ByteSize = dbits;
|
||||
else
|
||||
desc.ByteSize = 8;
|
||||
if (params[PISerial::ParityControl]) {
|
||||
desc.fParity = 1;
|
||||
desc.Parity = params[PISerial::ParityOdd] ? 1 : 2;
|
||||
}
|
||||
desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
|
||||
if (SetCommState(hCom, &desc) == -1) {
|
||||
piCoutObj << "Unable to set comm state for \"" << path_ << "\"";
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (fd == -1) return;
|
||||
tcgetattr(fd, &desc);
|
||||
desc.c_oflag = desc.c_lflag = desc.c_cflag = 0;
|
||||
desc.c_iflag = IGNBRK;
|
||||
desc.c_cflag = CLOCAL | HUPCL;
|
||||
switch (dbits) {
|
||||
case 5: desc.c_cflag |= (CSIZE & CS5); break;
|
||||
case 6: desc.c_cflag |= (CSIZE & CS6); break;
|
||||
case 7: desc.c_cflag |= (CSIZE & CS7); break;
|
||||
case 8: default: desc.c_cflag |= (CSIZE & CS8); break;
|
||||
};
|
||||
if (isReadable()) desc.c_cflag |= CREAD;
|
||||
if (params[PISerial::HardwareFlowControl]) desc.c_cflag |= CRTSCTS;
|
||||
if (params[PISerial::TwoStopBits]) desc.c_cflag |= CSTOPB;
|
||||
if (params[PISerial::ParityControl]) {
|
||||
desc.c_iflag |= INPCK;
|
||||
@@ -369,19 +421,37 @@ bool PISerial::openDevice() {
|
||||
cfsetospeed(&desc, convertSpeed(ospeed));
|
||||
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
fcntl(fd, F_SETFL, 0);
|
||||
fcntl(fd, F_SETFL, block_read ? 0 : O_NONBLOCK);
|
||||
|
||||
if(tcsetattr(fd, TCSANOW, &desc) < 0) {
|
||||
piCoutObj << "Can`t set attributes for \"" << path_ << "\"";
|
||||
::close(fd);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
//piCoutObj << "Initialized " << path_;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PISerial::setReadIsBlocking(bool yes) {
|
||||
block_read = yes;
|
||||
#ifdef WINDOWS
|
||||
COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = yes ? vtime : MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = yes ? 1 : 0;
|
||||
times.ReadTotalTimeoutMultiplier = 0;
|
||||
times.WriteTotalTimeoutConstant = 1;
|
||||
times.WriteTotalTimeoutMultiplier = 0;
|
||||
if (isOpened()) SetCommTimeouts(hCom, ×);
|
||||
#else
|
||||
if (isOpened()) fcntl(fd, F_SETFL, yes ? 0 : O_NONBLOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Basic read function
|
||||
* \details Read to pointer "read_to" no more than "max_size". If read is
|
||||
* set to blocking this function will be wait at least one byte.
|
||||
* \returns Readed bytes count
|
||||
* \sa \a readData() */
|
||||
int PISerial::read(void * read_to, int max_size) {
|
||||
#ifdef WINDOWS
|
||||
if (!canRead()) return -1;
|
||||
@@ -426,8 +496,121 @@ bool PISerial::configureDevice(const void * e_main, const void * e_parent) {
|
||||
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
||||
setDevice(readDeviceSetting<PIString>("device", device(), em, ep));
|
||||
setSpeed((PISerial::Speed)(readDeviceSetting<int>("speed", (int)ospeed, em, ep)));
|
||||
setDataBitsCount(readDeviceSetting<int>("dataBitsCount", dataBitsCount(), em, ep));
|
||||
setParameter(PISerial::ParityControl, readDeviceSetting<bool>("parityControl", isParameterSet(PISerial::ParityControl), em, ep));
|
||||
setParameter(PISerial::ParityOdd, readDeviceSetting<bool>("parityOdd", isParameterSet(PISerial::ParityOdd), em, ep));
|
||||
setParameter(PISerial::TwoStopBits, readDeviceSetting<bool>("twoStopBits", isParameterSet(PISerial::TwoStopBits), em, ep));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIVector<int> PISerial::availableSpeeds() {
|
||||
PIVector<int> spds;
|
||||
spds << 50 << 75 << 110 << 300 << 600 << 1200 << 2400 << 4800 <<
|
||||
9600 << 19200 << 38400 << 57600 << 115200 << 1500000 <<
|
||||
2000000 << 2500000 << 3000000 << 3500000 << 4000000;
|
||||
return spds;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PISerial::availableDevices(bool test) {
|
||||
PIStringList dl;
|
||||
#ifdef WINDOWS
|
||||
HKEY key = 0;
|
||||
RegOpenKey(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", &key);
|
||||
if (key != 0) {
|
||||
char name[256], data[1024];
|
||||
DWORD name_len = 256, data_len = 1024, type = 0, index = 0;
|
||||
while (RegEnumValue(key, index, name, &name_len, NULL, &type, (uchar * )data, &data_len) == ERROR_SUCCESS) {
|
||||
dl << PIString(data);
|
||||
index++;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
#else
|
||||
# ifndef ANDROID
|
||||
PIStringList prefixes;
|
||||
# ifdef QNX
|
||||
prefixes << "ser";
|
||||
# else
|
||||
prefixes << "ttyS" << "ttyO" << "ttyUSB" << "ttyACM" << "ttyGS"
|
||||
<< "ttyMI" << "ttymxc" << "ttyAMA" << "rfcomm" << "ircomm";
|
||||
# ifdef FREE_BSD
|
||||
prefixes << "cu";
|
||||
# endif
|
||||
PIFile file_prefixes("/proc/tty/drivers", PIIODevice::ReadOnly);
|
||||
if (file_prefixes.open()) {
|
||||
PIString fc = file_prefixes.readAll(true), line, cpref;
|
||||
PIStringList words;
|
||||
file_prefixes.close();
|
||||
while (!fc.isEmpty()) {
|
||||
words.clear();
|
||||
line = fc.takeLine();
|
||||
if (line.isEmpty()) break;
|
||||
while (!line.isEmpty())
|
||||
words << line.takeWord();
|
||||
if (words.size_s() < 2) break;
|
||||
if (words.back() != "serial") continue;
|
||||
cpref = words[1];
|
||||
int li = cpref.findLast("/");
|
||||
if (li > 0) cpref.cutLeft(li + 1);
|
||||
prefixes << cpref;
|
||||
}
|
||||
prefixes.removeDuplicates();
|
||||
}
|
||||
# endif
|
||||
PIDir dir("/dev");
|
||||
PIVector<PIDir::DirEntry> de = dir.entries();
|
||||
piForeachC (PIDir::DirEntry & e, de) {
|
||||
piForeachC (PIString & p, prefixes) {
|
||||
if (e.name.left(p.size_s()) != p) continue;
|
||||
dl << "/dev/" + e.name;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (test) {
|
||||
for (int i = 0; i < dl.size_s(); ++i) {
|
||||
#ifdef WINDOWS
|
||||
void * hCom = CreateFileA(dl[i].data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
if (hCom == INVALID_HANDLE_VALUE) {
|
||||
#else
|
||||
int fd = ::open(dl[i].data(), O_NOCTTY | O_RDONLY);
|
||||
if (fd == -1) {
|
||||
#endif
|
||||
dl.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
int void_ = 0;
|
||||
bool rok = true;
|
||||
#ifdef WINDOWS
|
||||
/*COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = 0;
|
||||
times.ReadTotalTimeoutMultiplier = 0;
|
||||
times.WriteTotalTimeoutConstant = 1;
|
||||
times.WriteTotalTimeoutMultiplier = 0;
|
||||
SetCommTimeouts(hCom, ×);
|
||||
if (ReadFile(hCom, &void_, 1, &readed_, 0) == 0)
|
||||
rok = GetLastError() == ;*/
|
||||
#else
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
if (::read(fd, &void_, 1) == -1)
|
||||
rok = errno != EIO;
|
||||
|
||||
#endif
|
||||
if (!rok) {
|
||||
dl.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
CloseHandle(hCom);
|
||||
#else
|
||||
::close(fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return dl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user