30.11.2013 - New PICollection namespace, Android support, my own PIVector implementation

This commit is contained in:
peri4
2013-11-30 19:34:53 +04:00
parent ec5530053a
commit f50891b376
64 changed files with 5466 additions and 3392 deletions

View File

@@ -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, &times) == -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, &times) == -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, &times);
#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, &times);
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;
}