|
|
|
|
@@ -23,10 +23,10 @@
|
|
|
|
|
#include "pipropertystorage.h"
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#if defined(WINDOWS) || defined(FREERTOS)
|
|
|
|
|
#if defined(FREERTOS)
|
|
|
|
|
# define PISERIAL_NO_PINS
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef PISERIAL_NO_PINS
|
|
|
|
|
#if defined(PISERIAL_NO_PINS) || defined(WINDOWS)
|
|
|
|
|
# define TIOCM_LE 1
|
|
|
|
|
# define TIOCM_DTR 4
|
|
|
|
|
# define TIOCM_RTS 7
|
|
|
|
|
@@ -38,7 +38,19 @@
|
|
|
|
|
# define TIOCM_DSR 6
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
# ifndef INITGUID
|
|
|
|
|
# define INITGUID
|
|
|
|
|
# include <guiddef.h>
|
|
|
|
|
# undef INITGUID
|
|
|
|
|
# else
|
|
|
|
|
# include <guiddef.h>
|
|
|
|
|
# endif
|
|
|
|
|
# include <ntddmodm.h>
|
|
|
|
|
# include <winreg.h>
|
|
|
|
|
# include <windows.h>
|
|
|
|
|
# include <winioctl.h>
|
|
|
|
|
# include <cfgmgr32.h>
|
|
|
|
|
# include <setupapi.h>
|
|
|
|
|
# define B50 50
|
|
|
|
|
# define B75 75
|
|
|
|
|
# define B110 110
|
|
|
|
|
@@ -130,7 +142,13 @@
|
|
|
|
|
* \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.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* \section PISerial_sec0 FullPath
|
|
|
|
|
* Since version 1.16.0 you can use as \a path DeviceInfo::id() USB identifier.
|
|
|
|
|
* \code
|
|
|
|
|
* PISerial * s = new PISerial("0403:6001");
|
|
|
|
|
* PIIODevice * d = PIIODevice::createFromFullPath("ser://0403:6001:115200");
|
|
|
|
|
* \endcode
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@@ -149,6 +167,21 @@ PRIVATE_DEFINITION_START(PISerial)
|
|
|
|
|
PRIVATE_DEFINITION_END(PISerial)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PISerial::DeviceInfo::DeviceInfo() {
|
|
|
|
|
vID = pID = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIString PISerial::DeviceInfo::id() const {
|
|
|
|
|
return PIString::fromNumber(vID, 16).toLowerCase().expandLeftTo(4, '0') + ":" +
|
|
|
|
|
PIString::fromNumber(pID, 16).toLowerCase().expandLeftTo(4, '0');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
|
|
|
|
construct();
|
|
|
|
|
}
|
|
|
|
|
@@ -255,37 +288,51 @@ bool PISerial::isDSR() const {return isBit(TIOCM_DSR, "DSR");}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
|
|
|
|
#ifndef PISERIAL_NO_PINS
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#ifndef PISERIAL_NO_PINS
|
|
|
|
|
# ifdef WINDOWS
|
|
|
|
|
static int bit_map_on [] = {0, 0, 0, 0, SETDTR, 0, 0, SETRTS, 0, 0, 0};
|
|
|
|
|
static int bit_map_off[] = {0, 0, 0, 0, CLRDTR, 0, 0, CLRRTS, 0, 0, 0};
|
|
|
|
|
int action = (on ? bit_map_on : bit_map_off)[bit];
|
|
|
|
|
if (action > 0) {
|
|
|
|
|
if (EscapeCommFunction(PRIVATE->hCom, action) == 0) {
|
|
|
|
|
piCoutObj << "setBit" << bname << " error: " << errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
# else
|
|
|
|
|
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
|
|
|
|
|
piCoutObj << "setBit" << bname << " error: " << errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
piCoutObj << "setBit" << bname << " doesn`t implemented, sorry :-(";
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PISerial::isBit(int bit, const PIString & bname) const {
|
|
|
|
|
#ifndef PISERIAL_NO_PINS
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
piCoutObj << "isBit" << bname << " error: \"" << path() << "\" is not opened!";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#ifndef PISERIAL_NO_PINS
|
|
|
|
|
# ifdef WINDOWS
|
|
|
|
|
# else
|
|
|
|
|
int ret = 0;
|
|
|
|
|
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
|
|
|
|
piCoutObj << "isBit" << bname << " error: " << errorString();
|
|
|
|
|
return ret & bit;
|
|
|
|
|
#else
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
piCoutObj << "isBit" << bname << " doesn`t implemented, sorry :-(";
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -296,28 +343,6 @@ void PISerial::flush() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PISerial::closeDevice() {
|
|
|
|
|
if (isRunning() && !isStopping()) {
|
|
|
|
|
stop();
|
|
|
|
|
PIThread::terminate();
|
|
|
|
|
}
|
|
|
|
|
if (fd != -1) {
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
|
|
|
|
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
|
|
|
|
|
// piCoutObj << "close" <<
|
|
|
|
|
CloseHandle(PRIVATE->hCom);
|
|
|
|
|
PRIVATE->hCom = 0;
|
|
|
|
|
#else
|
|
|
|
|
tcsetattr(fd, TCSANOW, &PRIVATE->sdesc);
|
|
|
|
|
::close(fd);
|
|
|
|
|
#endif
|
|
|
|
|
fd = -1;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int PISerial::convertSpeed(PISerial::Speed speed) {
|
|
|
|
|
switch (speed) {
|
|
|
|
|
case S50: return B50;
|
|
|
|
|
@@ -509,16 +534,31 @@ bool PISerial::send(const void * data, int size) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PISerial::openDevice() {
|
|
|
|
|
//piCout << "ser open" << path();
|
|
|
|
|
if (path().isEmpty()) return false;
|
|
|
|
|
PIString p = path();
|
|
|
|
|
//piCout << "ser open" << p;
|
|
|
|
|
PIString pl = p.toLowerCase().removeAll(' ');
|
|
|
|
|
if (!pl.startsWith("/") && !pl.startsWith("com")) {
|
|
|
|
|
p.clear();
|
|
|
|
|
PIVector<DeviceInfo> devs = availableDevicesInfo();
|
|
|
|
|
piForeachC (DeviceInfo & d, devs) {
|
|
|
|
|
if (d.id() == pl) {
|
|
|
|
|
p = d.path;
|
|
|
|
|
piBreak;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (p.isEmpty()) {
|
|
|
|
|
piCoutObj << "Unable to find device \"" << pl << "\"";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (p.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();
|
|
|
|
|
PRIVATE->hCom = CreateFileA(wp.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
|
|
|
|
PIString wp = "//./" + p;
|
|
|
|
|
PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
|
|
|
|
if (PRIVATE->hCom == INVALID_HANDLE_VALUE) {
|
|
|
|
|
piCoutObj << "Unable to open \"" << path() << "\"";
|
|
|
|
|
piCoutObj << "Unable to open \"" << p << "\"";
|
|
|
|
|
fd = -1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -530,21 +570,42 @@ bool PISerial::openDevice() {
|
|
|
|
|
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);
|
|
|
|
|
fd = ::open(p.data(), O_NOCTTY | om);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
piCoutObj << "Unable to open \"" << path() << "\"";
|
|
|
|
|
piCoutObj << "Unable to open \"" << p << "\"";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
tcgetattr(fd, &PRIVATE->desc);
|
|
|
|
|
PRIVATE->sdesc = PRIVATE->desc;
|
|
|
|
|
//piCoutObj << "Initialized " << path_;
|
|
|
|
|
//piCoutObj << "Initialized " << p;
|
|
|
|
|
#endif
|
|
|
|
|
applySettings();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PISerial::closeDevice() {
|
|
|
|
|
if (isRunning() && !isStopping()) {
|
|
|
|
|
stop();
|
|
|
|
|
PIThread::terminate();
|
|
|
|
|
}
|
|
|
|
|
if (fd != -1) {
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
|
|
|
|
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
|
|
|
|
|
// piCoutObj << "close" <<
|
|
|
|
|
CloseHandle(PRIVATE->hCom);
|
|
|
|
|
PRIVATE->hCom = 0;
|
|
|
|
|
#else
|
|
|
|
|
tcsetattr(fd, TCSANOW, &PRIVATE->sdesc);
|
|
|
|
|
::close(fd);
|
|
|
|
|
#endif
|
|
|
|
|
fd = -1;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PISerial::applySettings() {
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
if (fd == -1) return;
|
|
|
|
|
@@ -718,6 +779,13 @@ PIString PISerial::constructFullPathDevice() const {
|
|
|
|
|
|
|
|
|
|
void PISerial::configureFromFullPathDevice(const PIString & full_path) {
|
|
|
|
|
PIStringList pl = full_path.split(":");
|
|
|
|
|
if (pl.size_s() > 1) {
|
|
|
|
|
PIString _s = pl[0].toLowerCase().removeAll(' ').trim();
|
|
|
|
|
if (!_s.startsWith("/") && !_s.startsWith("com")) {
|
|
|
|
|
pl[0] += ":" + pl[1];
|
|
|
|
|
pl.remove(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < pl.size_s(); ++i) {
|
|
|
|
|
PIString p(pl[i]);
|
|
|
|
|
switch (i) {
|
|
|
|
|
@@ -792,24 +860,134 @@ PIVector<int> PISerial::availableSpeeds() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIStringList PISerial::availableDevices(bool test) {
|
|
|
|
|
PIStringList dl;
|
|
|
|
|
PIVector<DeviceInfo> devs = availableDevicesInfo(test);
|
|
|
|
|
PIStringList ret;
|
|
|
|
|
piForeachC (DeviceInfo & d, devs)
|
|
|
|
|
ret << d.path;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
HKEY key = 0;
|
|
|
|
|
PIString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) {
|
|
|
|
|
PIString ret;
|
|
|
|
|
const HKEY key = SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
|
|
|
|
if (key == INVALID_HANDLE_VALUE)
|
|
|
|
|
return ret;
|
|
|
|
|
static const wchar_t * const keyTokens[] = {
|
|
|
|
|
L"PortName\0",
|
|
|
|
|
L"PortNumber\0"
|
|
|
|
|
};
|
|
|
|
|
static const int keys_count = sizeof(keyTokens) / sizeof(keyTokens[0]);
|
|
|
|
|
for (int i = 0; i < keys_count; ++i) {
|
|
|
|
|
DWORD dataType = 0;
|
|
|
|
|
DWORD bytesRequired = MAX_PATH;
|
|
|
|
|
PIVector<wchar_t> outputBuffer(MAX_PATH + 1);
|
|
|
|
|
for (;;) {
|
|
|
|
|
LONG res = RegQueryValueExW(key, keyTokens[i], NULL, &dataType, (LPBYTE)outputBuffer.data(), &bytesRequired);
|
|
|
|
|
if (res == ERROR_MORE_DATA) {
|
|
|
|
|
outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2);
|
|
|
|
|
continue;
|
|
|
|
|
} else if (res == ERROR_SUCCESS) {
|
|
|
|
|
if (dataType == REG_SZ)
|
|
|
|
|
ret = PIString(outputBuffer.data());
|
|
|
|
|
else if (dataType == REG_DWORD)
|
|
|
|
|
ret = PIStringAscii("COM") + PIString::fromNumber(*(PDWORD(&outputBuffer[0])));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!ret.isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(key);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIString deviceRegistryProperty(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, DWORD property) {
|
|
|
|
|
DWORD dataType = 0;
|
|
|
|
|
DWORD bytesRequired = MAX_PATH;
|
|
|
|
|
PIVector<wchar_t> outputBuffer(MAX_PATH + 1);
|
|
|
|
|
for (;;) {
|
|
|
|
|
if (SetupDiGetDeviceRegistryPropertyW(deviceInfoSet, deviceInfoData, property, &dataType, (PBYTE)outputBuffer.data(), bytesRequired, &bytesRequired))
|
|
|
|
|
break;
|
|
|
|
|
if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dataType != REG_SZ && dataType != REG_EXPAND_SZ))
|
|
|
|
|
return PIString();
|
|
|
|
|
outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2, 0);
|
|
|
|
|
}
|
|
|
|
|
return PIString(outputBuffer.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIString deviceInstanceIdentifier(DEVINST deviceInstanceNumber) {
|
|
|
|
|
PIVector<wchar_t> outputBuffer(MAX_DEVICE_ID_LEN + 1);
|
|
|
|
|
if (CM_Get_Device_IDW(deviceInstanceNumber, (PWCHAR)outputBuffer.data(), MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) {
|
|
|
|
|
return PIString();
|
|
|
|
|
}
|
|
|
|
|
return PIString(outputBuffer.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool parseID(PIString str, PISerial::DeviceInfo & di) {
|
|
|
|
|
if (str.isEmpty()) return false;
|
|
|
|
|
int i = str.find("VID_");
|
|
|
|
|
if (i > 0) di.vID = str.mid(i + 4, 4).toInt(16);
|
|
|
|
|
i = str.find("PID_");
|
|
|
|
|
if (i > 0) di.pID = str.mid(i + 4, 4).toInt(16);
|
|
|
|
|
return (di.vID > 0) && (di.pID > 0);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
|
|
|
|
PIVector<DeviceInfo> ret;
|
|
|
|
|
DeviceInfo di;
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
/*HKEY key = 0;
|
|
|
|
|
RegOpenKey(HKEY_LOCAL_MACHINE, (LPCTSTR)"HARDWARE\\DEVICEMAP\\SERIALCOMM", &key);
|
|
|
|
|
if (key != 0) {
|
|
|
|
|
char name[1024], data[1024];
|
|
|
|
|
DWORD index = 0;
|
|
|
|
|
LONG ret = ERROR_SUCCESS;
|
|
|
|
|
while (ret != ERROR_NO_MORE_ITEMS) {
|
|
|
|
|
LONG res = ERROR_SUCCESS;
|
|
|
|
|
while (res != ERROR_NO_MORE_ITEMS) {
|
|
|
|
|
memset(name, 0, 1024);
|
|
|
|
|
memset(data, 0, 1024);
|
|
|
|
|
DWORD name_len = 1024, data_len = 1024, type = 0;
|
|
|
|
|
ret = RegEnumValue(key, index, (LPTSTR)name, &name_len, NULL, &type, (uchar * )data, &data_len);
|
|
|
|
|
if (ret == ERROR_NO_MORE_ITEMS) break;
|
|
|
|
|
dl << PIString(data, data_len).trim();
|
|
|
|
|
res = RegEnumValue(key, index, (LPTSTR)name, &name_len, NULL, &type, (uchar * )data, &data_len);
|
|
|
|
|
if (res == ERROR_NO_MORE_ITEMS) break;
|
|
|
|
|
di.path = PIString(data, data_len).trim();
|
|
|
|
|
ret << di;
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(key);
|
|
|
|
|
}*/
|
|
|
|
|
static const GUID guids[] = {GUID_DEVINTERFACE_MODEM, GUID_DEVINTERFACE_COMPORT};
|
|
|
|
|
static const int guids_cnt = sizeof(guids) / sizeof(GUID);
|
|
|
|
|
for (int i = 0; i < guids_cnt; ++i) {
|
|
|
|
|
const HDEVINFO dis = SetupDiGetClassDevs(&(guids[i]), NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
|
|
|
if (dis == INVALID_HANDLE_VALUE) continue;
|
|
|
|
|
SP_DEVINFO_DATA did;
|
|
|
|
|
memset(&did, 0, sizeof(did));
|
|
|
|
|
did.cbSize = sizeof(did);
|
|
|
|
|
DWORD index = 0;
|
|
|
|
|
while (SetupDiEnumDeviceInfo(dis, index++, &did)) {
|
|
|
|
|
di = DeviceInfo();
|
|
|
|
|
di.path = devicePortName(dis, &did);
|
|
|
|
|
if (!di.path.startsWith("COM")) continue;
|
|
|
|
|
di.description = deviceRegistryProperty(dis, &did, SPDRP_DEVICEDESC);
|
|
|
|
|
di.manufacturer = deviceRegistryProperty(dis, &did, SPDRP_MFG);
|
|
|
|
|
PIString id_str = deviceInstanceIdentifier(did.DevInst);
|
|
|
|
|
if (!parseID(id_str, di)) {
|
|
|
|
|
DEVINST pdev = 0;
|
|
|
|
|
if (CM_Get_Parent(&pdev, did.DevInst, 0) == CR_SUCCESS) {
|
|
|
|
|
id_str = deviceInstanceIdentifier(pdev);
|
|
|
|
|
parseID(id_str, di);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ret << di;
|
|
|
|
|
//piCout << "dev" << did.DevInst << di;
|
|
|
|
|
}
|
|
|
|
|
SetupDiDestroyDeviceInfoList(dis);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
# ifndef ANDROID
|
|
|
|
|
@@ -849,24 +1027,51 @@ PIStringList PISerial::availableDevices(bool test) {
|
|
|
|
|
# endif
|
|
|
|
|
PIDir dir("/dev");
|
|
|
|
|
PIVector<PIFile::FileInfo> de = dir.entries();
|
|
|
|
|
# ifdef LINUX
|
|
|
|
|
char linkbuf[1024];
|
|
|
|
|
# endif
|
|
|
|
|
piForeachC (PIFile::FileInfo & e, de) { // TODO changes in FileInfo
|
|
|
|
|
piForeachC (PIString & p, prefixes) {
|
|
|
|
|
if (e.name().startsWith(p))
|
|
|
|
|
dl << e.path;
|
|
|
|
|
if (e.name().startsWith(p)) {
|
|
|
|
|
di = DeviceInfo();
|
|
|
|
|
di.path = e.path;
|
|
|
|
|
# ifdef LINUX
|
|
|
|
|
ssize_t lsz = readlink(("/sys/class/tty/" + e.name()).dataAscii(), linkbuf, 1024);
|
|
|
|
|
if (lsz > 0) {
|
|
|
|
|
PIString fpath = "/sys/class/tty/" + PIString(linkbuf, lsz) + "/";
|
|
|
|
|
PIFile _f;
|
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
|
|
|
fpath += "../";
|
|
|
|
|
//piCout << "try" << fpath;
|
|
|
|
|
if (_f.open(fpath + "idVendor", PIIODevice::ReadOnly))
|
|
|
|
|
di.vID = PIString(_f.readAll()).trim().toInt(16);
|
|
|
|
|
if (_f.open(fpath + "idProduct", PIIODevice::ReadOnly))
|
|
|
|
|
di.pID = PIString(_f.readAll()).trim().toInt(16);
|
|
|
|
|
if (_f.open(fpath + "product", PIIODevice::ReadOnly))
|
|
|
|
|
di.description = PIString(_f.readAll()).trim();
|
|
|
|
|
if (_f.open(fpath + "manufacturer", PIIODevice::ReadOnly))
|
|
|
|
|
di.manufacturer = PIString(_f.readAll()).trim();
|
|
|
|
|
if (di.pID > 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# endif
|
|
|
|
|
ret << di;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
if (test) {
|
|
|
|
|
for (int i = 0; i < dl.size_s(); ++i) {
|
|
|
|
|
for (int i = 0; i < ret.size_s(); ++i) {
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
void * hComm = CreateFileA(dl[i].data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
|
|
|
|
void * hComm = CreateFileA(ret[i].path.dataAscii(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
|
|
|
|
if (hComm == INVALID_HANDLE_VALUE) {
|
|
|
|
|
#else
|
|
|
|
|
int fd = ::open(dl[i].data(), O_NOCTTY | O_RDONLY);
|
|
|
|
|
int fd = ::open(ret[i].path.dataAscii(), O_NOCTTY | O_RDONLY);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
#endif
|
|
|
|
|
dl.remove(i);
|
|
|
|
|
ret.remove(i);
|
|
|
|
|
--i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
@@ -889,7 +1094,7 @@ PIStringList PISerial::availableDevices(bool test) {
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
if (!rok) {
|
|
|
|
|
dl.remove(i);
|
|
|
|
|
ret.remove(i);
|
|
|
|
|
--i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
@@ -900,7 +1105,7 @@ PIStringList PISerial::availableDevices(bool test) {
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dl;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|