665 lines
18 KiB
C++
665 lines
18 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
COM
|
|
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
|
|
|
|
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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "piserial.h"
|
|
#include "piconfig.h"
|
|
#include "pidir.h"
|
|
|
|
|
|
/*! \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.
|
|
*
|
|
*
|
|
*/
|
|
|
|
REGISTER_DEVICE(PISerial);
|
|
|
|
|
|
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
|
_init();
|
|
}
|
|
|
|
|
|
PISerial::PISerial(const PIString & device_, PISerial::Speed speed_, PIFlags<PISerial::Parameters> params_): PIIODevice(device_, ReadWrite) {
|
|
_init();
|
|
setPath(device_);
|
|
setSpeed(speed_);
|
|
setParameters(params_);
|
|
}
|
|
|
|
|
|
PISerial::~PISerial() {
|
|
piMonitor.serials--;
|
|
}
|
|
|
|
|
|
void PISerial::_init() {
|
|
fd = -1;
|
|
piMonitor.serials++;
|
|
setPriority(piHigh);
|
|
block_read = true;
|
|
vtime = 1;
|
|
#ifdef WINDOWS
|
|
block_write = true;
|
|
hCom = 0;
|
|
#endif
|
|
setParameters(0);
|
|
setSpeed(S115200);
|
|
setDataBitsCount(8);
|
|
//init();
|
|
}
|
|
|
|
|
|
void PISerial::setParameter(PISerial::Parameters parameter, bool on) {
|
|
PIFlags<Parameters> cp = (PIFlags<Parameters>)(property("parameters").toInt());
|
|
cp.setFlag(parameter, on);
|
|
setParameters(cp);
|
|
}
|
|
|
|
|
|
bool PISerial::isParameterSet(PISerial::Parameters parameter) const {
|
|
PIFlags<Parameters> cp = (PIFlags<Parameters>)(property("parameters").toInt());
|
|
return cp[parameter];
|
|
}
|
|
|
|
|
|
bool PISerial::setPin(int number, bool on) {
|
|
switch (number) {
|
|
case 1: return setCAR(on); break;
|
|
case 2: return setSR(on); break;
|
|
case 3: return setST(on); break;
|
|
case 4: return setDTR(on); break;
|
|
case 5:
|
|
piCoutObj << "Pin number 5 is ground";
|
|
return false;
|
|
case 6: return setDSR(on); break;
|
|
case 7: return setRTS(on); break;
|
|
case 8: return setCTS(on); break;
|
|
case 9: return setRNG(on); break;
|
|
default:
|
|
piCoutObj << "Pin number " << number << " doesn`t exists!";
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool PISerial::isPin(int number) const {
|
|
switch (number) {
|
|
case 1: return isCAR(); break;
|
|
case 2: return isSR(); break;
|
|
case 3: return isST(); break;
|
|
case 4: return isDTR(); break;
|
|
case 5: return false;
|
|
case 6: return isDSR(); break;
|
|
case 7: return isRTS(); break;
|
|
case 8: return isCTS(); break;
|
|
case 9: return isRNG(); break;
|
|
default:
|
|
piCoutObj << "Pin number " << number << " doesn`t exists!";
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
|
#ifndef WINDOWS
|
|
if (fd < 0) {
|
|
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
|
|
return false;
|
|
}
|
|
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
|
|
piCoutObj << "setBit" << bname << " error: " << errorString();
|
|
return false;
|
|
}
|
|
return true;
|
|
#else
|
|
piCoutObj << "setBit" << bname << " doesn`t implemented on Windows, sorry :-(";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
|
|
bool PISerial::isBit(int bit, const PIString & bname) const {
|
|
#ifndef WINDOWS
|
|
if (fd < 0) {
|
|
piCoutObj << "isBit" << bname << " error: \"" << path() << "\" is not opened!";
|
|
return false;
|
|
}
|
|
int ret = 0;
|
|
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
|
piCoutObj << "isBit" << bname << " error: " << errorString();
|
|
return ret & bit;
|
|
#else
|
|
piCoutObj << "isBit" << bname << " doesn`t implemented on Windows, sorry :-(";
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
|
|
bool PISerial::closeDevice() {
|
|
if (!isInitialized()) return true;
|
|
if (isRunning()) {
|
|
stop();
|
|
PIThread::terminate();
|
|
}
|
|
if (fd != -1) {
|
|
#ifdef WINDOWS
|
|
SetCommState(hCom, &sdesc);
|
|
SetCommMask(hCom, mask);
|
|
CloseHandle(hCom);
|
|
hCom = 0;
|
|
#else
|
|
tcsetattr(fd, TCSANOW, &sdesc);
|
|
::close(fd);
|
|
#endif
|
|
fd = -1;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
int PISerial::convertSpeed(PISerial::Speed speed) {
|
|
switch (speed) {
|
|
case S50: return B50;
|
|
case S75: return B75;
|
|
case S110: return B110;
|
|
case S300: return B300;
|
|
case S600: return B600;
|
|
case S1200: return B1200;
|
|
case S2400: return B2400;
|
|
case S4800: return B4800;
|
|
case S9600: return B9600;
|
|
case S19200: return B19200;
|
|
case S38400: return B38400;
|
|
case S57600: return B57600;
|
|
case S115200: return B115200;
|
|
case S1500000: return B1500000;
|
|
case S2000000: return B2000000;
|
|
case S2500000: return B2500000;
|
|
case S3000000: return B3000000;
|
|
case S3500000: return B3500000;
|
|
case S4000000: return B4000000;
|
|
default: break;
|
|
}
|
|
return B115200;
|
|
}
|
|
|
|
|
|
/** \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 || size <= 0) return false;
|
|
int ret, all = 0;
|
|
if (timeout_ms > 0.) {
|
|
setReadIsBlocking(false);
|
|
all = read(data, 1);
|
|
timer.reset();
|
|
while (all < size && timer.elapsed_m() < timeout_ms) {
|
|
ret = read(&((uchar * )data)[all], size - all);
|
|
if (ret > 0) all += ret;
|
|
else msleep(1);
|
|
}
|
|
received(data, all);
|
|
return (all == size);
|
|
} else {
|
|
setReadIsBlocking(true);
|
|
all = read(data, 1);
|
|
while (all < size) {
|
|
ret = read(&((uchar * )data)[all], size - all);
|
|
if (ret > 0) all += ret;
|
|
}
|
|
received(data, all);
|
|
return (all == size);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/** \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];
|
|
if (timeout_ms > 0.) {
|
|
setReadIsBlocking(false);
|
|
timer.reset();
|
|
if (size <= 0) {
|
|
while (timer.elapsed_m() < timeout_ms) {
|
|
ret = read(td, 1024);
|
|
if (ret <= 0) msleep(1);
|
|
else str << PIString((char*)td, ret);
|
|
}
|
|
} else {
|
|
while (all < size && timer.elapsed_m() < timeout_ms) {
|
|
ret = read(td, size - all);
|
|
if (ret <= 0) msleep(1);
|
|
else {
|
|
str << PIString((char*)td, ret);
|
|
all += ret;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
setReadIsBlocking(true);
|
|
all = read(td, 1);
|
|
str << PIString((char*)td, all);
|
|
while (all < size) {
|
|
ret = read(td, size - all);
|
|
if (ret <= 0) msleep(1);
|
|
else {
|
|
str << PIString((char*)td, ret);
|
|
all += ret;
|
|
}
|
|
}
|
|
}
|
|
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(td, 1024);
|
|
if (ret <= 0) msleep(1);
|
|
else str.append(td, ret);
|
|
}
|
|
} else {
|
|
while (all < size && timer.elapsed_m() < timeout_ms) {
|
|
ret = read(td, size - all);
|
|
if (ret <= 0) msleep(1);
|
|
else {
|
|
str.append(td, ret);
|
|
all += ret;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
setReadIsBlocking(true);
|
|
all = read(td, 1);
|
|
str.append(td, all);
|
|
while (all < size) {
|
|
ret = read(td, size - all);
|
|
if (ret <= 0) msleep(1);
|
|
else {
|
|
str.append(td, ret);
|
|
all += ret;
|
|
}
|
|
}
|
|
}
|
|
received(str.data(), str.size_s());
|
|
return str;
|
|
}
|
|
|
|
|
|
bool PISerial::openDevice() {
|
|
//piCout << "ser open" << path();
|
|
if (path().isEmpty()) return false;
|
|
#ifdef WINDOWS
|
|
DWORD ds = 0, sm = 0;
|
|
if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;}
|
|
if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;}
|
|
PIString wp = "//./" + path();
|
|
hCom = CreateFileA(wp.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
|
if (hCom == INVALID_HANDLE_VALUE) {
|
|
piCoutObj << "Unable to open \"" << path() << "\"";
|
|
fd = -1;
|
|
return false;
|
|
}
|
|
fd = 0;
|
|
#else
|
|
int om = 0;
|
|
switch (mode()) {
|
|
case PIIODevice::ReadOnly: om = O_RDONLY; break;
|
|
case PIIODevice::WriteOnly: om = O_WRONLY; break;
|
|
case PIIODevice::ReadWrite: om = O_RDWR; break;
|
|
}
|
|
//cout << "init ser " << path_ << " mode " << om << " param " << params << endl;
|
|
fd = ::open(path().data(), O_NOCTTY | om);
|
|
if (fd == -1) {
|
|
piCoutObj << "Unable to open \"" << path() << "\"";
|
|
return false;
|
|
}
|
|
tcgetattr(fd, &desc);
|
|
sdesc = desc;
|
|
//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 ? 0 : 1;
|
|
times.ReadTotalTimeoutMultiplier = block_read ? 0 : MAXDWORD;
|
|
times.WriteTotalTimeoutConstant = 0;
|
|
times.WriteTotalTimeoutMultiplier = block_write ? 0 : 1;
|
|
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(outSpeed());
|
|
if (dataBitsCount() >= 5 && dataBitsCount() <= 8)
|
|
desc.ByteSize = dataBitsCount();
|
|
else
|
|
desc.ByteSize = 8;
|
|
PIFlags<Parameters> params = parameters();
|
|
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 (dataBitsCount()) {
|
|
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;
|
|
PIFlags<Parameters> params = parameters();
|
|
if (params[PISerial::TwoStopBits]) desc.c_cflag |= CSTOPB;
|
|
if (params[PISerial::ParityControl]) {
|
|
desc.c_iflag |= INPCK;
|
|
desc.c_cflag |= PARENB;
|
|
if (params[PISerial::ParityOdd]) desc.c_cflag |= PARODD;
|
|
}
|
|
desc.c_cc[VMIN] = 1;
|
|
desc.c_cc[VTIME] = vtime;
|
|
|
|
cfsetispeed(&desc, convertSpeed(inSpeed()));
|
|
cfsetospeed(&desc, convertSpeed(outSpeed()));
|
|
|
|
tcflush(fd, TCIOFLUSH);
|
|
fcntl(fd, F_SETFL, block_read ? 0 : O_NONBLOCK);
|
|
|
|
if(tcsetattr(fd, TCSANOW, &desc) < 0) {
|
|
piCoutObj << "Can`t set attributes for \"" << path() << "\"";
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
void PISerial::setReadIsBlocking(bool yes) {
|
|
block_read = yes;
|
|
#ifdef WINDOWS
|
|
COMMTIMEOUTS times;
|
|
times.ReadIntervalTimeout = block_read ? vtime : MAXDWORD;
|
|
times.ReadTotalTimeoutConstant = block_read ? 0 : 1;
|
|
times.ReadTotalTimeoutMultiplier = block_read ? 0 : MAXDWORD;
|
|
times.WriteTotalTimeoutConstant = 0;
|
|
times.WriteTotalTimeoutMultiplier = block_write ? 0 : 1;
|
|
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;
|
|
WaitCommEvent(hCom, 0, 0);
|
|
ReadFile(hCom, read_to, max_size, &readed, 0);
|
|
return readed;
|
|
#else
|
|
if (!canRead()) return -1;
|
|
return ::read(fd, read_to, max_size);
|
|
#endif
|
|
}
|
|
|
|
|
|
int PISerial::write(const void * data, int max_size, bool wait) {
|
|
//piCoutObj << "send " << max_size << ": " << PIString((char*)data, max_size);
|
|
if (fd == -1 || !canWrite()) {
|
|
//piCoutObj << "Can`t write to uninitialized COM";
|
|
return -1;
|
|
}
|
|
#ifdef WINDOWS
|
|
if (block_write != wait) {
|
|
block_write = wait;
|
|
setReadIsBlocking(block_read);
|
|
}
|
|
DWORD wrote;
|
|
WriteFile(hCom, data, max_size, &wrote, 0);
|
|
#else
|
|
int wrote;
|
|
wrote = ::write(fd, data, max_size);
|
|
if (wait) tcdrain(fd);
|
|
#endif
|
|
return (int)wrote;
|
|
//piCoutObj << "Error while sending";
|
|
//piCoutObj << "Wrote " << wrote << " bytes in " << path_;
|
|
}
|
|
|
|
|
|
bool PISerial::configureDevice(const void * e_main, const void * e_parent) {
|
|
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
|
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
|
setDevice(readDeviceSetting<PIString>("device", device(), em, ep));
|
|
setSpeed((PISerial::Speed)(readDeviceSetting<int>("speed", (int)outSpeed(), 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;
|
|
}
|
|
|
|
|
|
PIString PISerial::constructFullPath() const {
|
|
PIString ret(fullPathPrefix() + "://");
|
|
ret << path() << ":" << int(inSpeed()) << ":" << dataBitsCount();
|
|
if (parameters()[ParityControl]) {
|
|
if (parameters()[ParityOdd]) ret << ":O";
|
|
else ret << ":E";
|
|
} else ret << ":N";
|
|
if (parameters()[TwoStopBits]) ret << ":2";
|
|
else ret << ":1";
|
|
return ret;
|
|
}
|
|
|
|
|
|
void PISerial::configureFromFullPath(const PIString & full_path) {
|
|
PIStringList pl = full_path.split(":");
|
|
for (int i = 0; i < pl.size_s(); ++i) {
|
|
PIString p(pl[i]);
|
|
switch (i) {
|
|
case 0: setPath(p); break;
|
|
case 1: setSpeed((Speed)(p.toInt())); break;
|
|
case 2: setDataBitsCount(p.toInt()); break;
|
|
case 3:
|
|
p = p.toLowerCase();
|
|
if (p != "n") setParameter(ParityControl);
|
|
if (p == "o") setParameter(ParityOdd);
|
|
break;
|
|
case 4: if (p.toInt() == 2) setParameter(TwoStopBits); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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, (LPCTSTR)"HARDWARE\\DEVICEMAP\\SERIALCOMM", &key);
|
|
if (key != 0) {
|
|
char name[1024], data[1024];
|
|
DWORD name_len = 1024, data_len = 1024, type = 0, index = 0;
|
|
LONG ret;
|
|
while ((ret = RegEnumValue(key, index, (LPTSTR)name, &name_len, NULL, &type, (uchar * )data, &data_len)) != ERROR_NO_MORE_ITEMS) {
|
|
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;
|
|
}
|