code format
This commit is contained in:
@@ -1,23 +1,24 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for write binary data to logfile, and read or playback this data
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Class for write binary data to logfile, and read or playback this data
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pibinarylog.h"
|
||||
|
||||
#include "pidir.h"
|
||||
#include "pipropertystorage.h"
|
||||
|
||||
@@ -45,9 +46,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
static const uchar binlog_sig[] = {'B','I','N','L','O','G'};
|
||||
static const uchar binlog_sig[] = {'B', 'I', 'N', 'L', 'O', 'G'};
|
||||
|
||||
#define PIBINARYLOG_VERSION 0x32
|
||||
#define PIBINARYLOG_VERSION 0x32
|
||||
#define PIBINARYLOG_SIGNATURE_SIZE sizeof(binlog_sig)
|
||||
|
||||
REGISTER_DEVICE(PIBinaryLog)
|
||||
@@ -59,9 +60,9 @@ PIBinaryLog::PIBinaryLog() {
|
||||
setThreadedReadBufferSize(65536);
|
||||
#endif
|
||||
is_started = is_indexed = is_pause = false;
|
||||
current_index = -1;
|
||||
log_size = 0;
|
||||
f_new_path = nullptr;
|
||||
current_index = -1;
|
||||
log_size = 0;
|
||||
f_new_path = nullptr;
|
||||
setPlaySpeed(1.);
|
||||
setDefaultID(1);
|
||||
setPlaySpeed(1.0);
|
||||
@@ -75,7 +76,7 @@ PIBinaryLog::PIBinaryLog() {
|
||||
setFilePrefix(PIString());
|
||||
setRapidStart(false);
|
||||
file.setName("__S__PIBinaryLog::file");
|
||||
// piCoutObj << "created";
|
||||
// piCoutObj << "created";
|
||||
}
|
||||
|
||||
|
||||
@@ -87,12 +88,12 @@ PIBinaryLog::~PIBinaryLog() {
|
||||
|
||||
bool PIBinaryLog::openDevice() {
|
||||
lastrecord.timestamp = PISystemTime();
|
||||
lastrecord.id = 0;
|
||||
write_count = 0;
|
||||
is_started = false;
|
||||
is_thread_ok = true;
|
||||
is_indexed = false;
|
||||
is_pause = false;
|
||||
lastrecord.id = 0;
|
||||
write_count = 0;
|
||||
is_started = false;
|
||||
is_thread_ok = true;
|
||||
is_indexed = false;
|
||||
is_pause = false;
|
||||
index.clear();
|
||||
index_pos.clear();
|
||||
log_size = 0;
|
||||
@@ -101,14 +102,16 @@ bool PIBinaryLog::openDevice() {
|
||||
return false;
|
||||
}
|
||||
if (path().isEmpty() && mode_ == WriteOnly) {
|
||||
if (f_new_path) setPath(f_new_path());
|
||||
else setPath(getLogfilePath(logDir(), filePrefix()));
|
||||
if (f_new_path)
|
||||
setPath(f_new_path());
|
||||
else
|
||||
setPath(getLogfilePath(logDir(), filePrefix()));
|
||||
}
|
||||
if (path().isEmpty() && mode_ == ReadOnly) {
|
||||
PIDir ld(logDir());
|
||||
if (ld.isExists()) {
|
||||
PIVector<PIFile::FileInfo> es = ld.allEntries();
|
||||
piForeachC(PIFile::FileInfo &i, es) {
|
||||
piForeachC(PIFile::FileInfo & i, es) {
|
||||
if (i.extension() == "binlog" && i.isFile() && i.baseName().startsWith(filePrefix())) {
|
||||
setPath(i.path);
|
||||
break;
|
||||
@@ -147,7 +150,7 @@ bool PIBinaryLog::openDevice() {
|
||||
if (!rapid_start) is_started = true;
|
||||
}
|
||||
startlogtime = PISystemTime::current();
|
||||
pause_time = PISystemTime();
|
||||
pause_time = PISystemTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,7 +163,7 @@ bool PIBinaryLog::closeDevice() {
|
||||
is_indexed = false;
|
||||
index.clear();
|
||||
index_pos.clear();
|
||||
bool e = isEmpty();
|
||||
bool e = isEmpty();
|
||||
log_size = 0;
|
||||
if (canWrite() && e) {
|
||||
file.remove();
|
||||
@@ -170,8 +173,8 @@ bool PIBinaryLog::closeDevice() {
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::threadedRead(const uchar *readed, ssize_t size) {
|
||||
// piCout << "binlog threaded read";
|
||||
bool PIBinaryLog::threadedRead(const uchar * readed, ssize_t size) {
|
||||
// piCout << "binlog threaded read";
|
||||
if (!canRead() || isEnd()) return PIIODevice::threadedRead(readed, size);
|
||||
is_thread_ok = false;
|
||||
logmutex.lock();
|
||||
@@ -192,16 +195,15 @@ bool PIBinaryLog::threadedRead(const uchar *readed, ssize_t size) {
|
||||
pausemutex.unlock();
|
||||
pt = PISystemTime::current() - startlogtime;
|
||||
if (is_started) {
|
||||
if (lastrec_timestamp > pt)
|
||||
(lastrec_timestamp - pt).sleep();
|
||||
if (lastrec_timestamp > pt) (lastrec_timestamp - pt).sleep();
|
||||
} else {
|
||||
startlogtime = PISystemTime::current() - lastrec_timestamp;
|
||||
is_started = true;
|
||||
is_started = true;
|
||||
}
|
||||
break;
|
||||
case PlayVariableSpeed:
|
||||
delay = lastrec_timestamp.toMilliseconds() - play_time;
|
||||
//piCoutObj << "delay" << delay;
|
||||
// piCoutObj << "delay" << delay;
|
||||
double cdelay;
|
||||
int dtc;
|
||||
if (is_started) {
|
||||
@@ -210,36 +212,40 @@ bool PIBinaryLog::threadedRead(const uchar *readed, ssize_t size) {
|
||||
return false;
|
||||
}
|
||||
if (delay > 0) {
|
||||
cdelay = delay * play_speed;// TODO: rewrite with condvar
|
||||
dtc = int(cdelay) / 100;// TODO: rewrite with condvar
|
||||
cdelay = delay * play_speed; // TODO: rewrite with condvar
|
||||
dtc = int(cdelay) / 100; // TODO: rewrite with condvar
|
||||
if (play_speed <= 0.) dtc = 2;
|
||||
//piCout << play_speed << dtc;
|
||||
for (int j=0; j<dtc; j++) {
|
||||
cdelay = delay * play_speed;// TODO: rewrite with condvar
|
||||
dtc = int(cdelay) / 100;// TODO: rewrite with condvar
|
||||
piMSleep(100);// TODO: rewrite with condvar
|
||||
if (play_speed <= 0.) {dtc = 2; j = 0;}
|
||||
//piCout << " " << play_speed << dtc << j;
|
||||
// piCout << play_speed << dtc;
|
||||
for (int j = 0; j < dtc; j++) {
|
||||
cdelay = delay * play_speed; // TODO: rewrite with condvar
|
||||
dtc = int(cdelay) / 100; // TODO: rewrite with condvar
|
||||
piMSleep(100); // TODO: rewrite with condvar
|
||||
if (play_speed <= 0.) {
|
||||
dtc = 2;
|
||||
j = 0;
|
||||
}
|
||||
// piCout << " " << play_speed << dtc << j;
|
||||
}
|
||||
cdelay = cdelay - dtc*100;// TODO: rewrite with condvar
|
||||
cdelay = cdelay - dtc * 100; // TODO: rewrite with condvar
|
||||
PISystemTime::fromMilliseconds(cdelay).sleep();
|
||||
}
|
||||
} else is_started = true;
|
||||
} else
|
||||
is_started = true;
|
||||
play_time = lastrec_timestamp.toMilliseconds();
|
||||
break;
|
||||
case PlayStaticDelay:
|
||||
if (is_started) {
|
||||
if (is_pause) {
|
||||
piMSleep(100);// TODO: rewrite with condvar
|
||||
piMSleep(100); // TODO: rewrite with condvar
|
||||
return false;
|
||||
}
|
||||
play_delay.sleep();
|
||||
} else is_started = true;
|
||||
} else
|
||||
is_started = true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
bool res = PIIODevice::threadedRead(readed, size);
|
||||
bool res = PIIODevice::threadedRead(readed, size);
|
||||
is_thread_ok = true;
|
||||
return res;
|
||||
}
|
||||
@@ -249,12 +255,13 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString &
|
||||
PIDir dir(log_dir);
|
||||
dir.setDir(dir.absolutePath());
|
||||
if (!dir.isExists()) {
|
||||
piCout << "[PIBinaryLog]" << "Creating directory" << dir.path();
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Creating directory" << dir.path();
|
||||
dir.make(true);
|
||||
}
|
||||
PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
PIString cnpath = npath + ".binlog";
|
||||
int i = 1;
|
||||
int i = 1;
|
||||
while (PIFile::isExists(cnpath)) {
|
||||
cnpath = npath + '_' + PIString::fromNumber(i) + ".binlog";
|
||||
i++;
|
||||
@@ -265,8 +272,10 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString &
|
||||
PIString PIBinaryLog::createNewFile() {
|
||||
if (!file.close()) return PIString();
|
||||
PIString cnpath;
|
||||
if (f_new_path) cnpath = f_new_path();
|
||||
else cnpath = getLogfilePath(logDir(), filePrefix());
|
||||
if (f_new_path)
|
||||
cnpath = f_new_path();
|
||||
else
|
||||
cnpath = getLogfilePath(logDir(), filePrefix());
|
||||
if (open(cnpath, PIIODevice::WriteOnly)) {
|
||||
newFile(file.path());
|
||||
return file.path();
|
||||
@@ -276,27 +285,27 @@ PIString PIBinaryLog::createNewFile() {
|
||||
}
|
||||
|
||||
|
||||
void PIBinaryLog::createNewFile(const PIString &path) {
|
||||
void PIBinaryLog::createNewFile(const PIString & path) {
|
||||
if (open(path, PIIODevice::WriteOnly)) {
|
||||
newFile(file.path());
|
||||
}
|
||||
else piCoutObj << "Can't create new file, maybe path" << ("\"" + path + "\"") << "is invalid.";
|
||||
} else
|
||||
piCoutObj << "Can't create new file, maybe path" << ("\"" + path + "\"") << "is invalid.";
|
||||
}
|
||||
|
||||
|
||||
void PIBinaryLog::setPause(bool pause) {
|
||||
pausemutex.lock();
|
||||
is_pause = pause;
|
||||
if (pause) pause_time = PISystemTime::current();
|
||||
if (pause)
|
||||
pause_time = PISystemTime::current();
|
||||
else {
|
||||
if (pause_time > PISystemTime())
|
||||
pause_time = PISystemTime::current() - pause_time;
|
||||
if (pause_time > PISystemTime()) pause_time = PISystemTime::current() - pause_time;
|
||||
}
|
||||
pausemutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
int PIBinaryLog::writeBinLog(int id, const void *data, int size) {
|
||||
int PIBinaryLog::writeBinLog(int id, const void * data, int size) {
|
||||
if (size <= 0 || !canWrite()) return -1;
|
||||
if (id == 0) {
|
||||
piCoutObj << "Error: can`t write with id = 0! Id must be > 0";
|
||||
@@ -323,12 +332,14 @@ int PIBinaryLog::writeBinLog(int id, const void *data, int size) {
|
||||
default: break;
|
||||
}
|
||||
logmutex.unlock();
|
||||
if (res > 0) return size;
|
||||
else return res;
|
||||
if (res > 0)
|
||||
return size;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int PIBinaryLog::writeBinLog_raw(int id, const PISystemTime &time, const void *data, int size) {
|
||||
int PIBinaryLog::writeBinLog_raw(int id, const PISystemTime & time, const void * data, int size) {
|
||||
if (size <= 0 || !canWrite()) return -1;
|
||||
PIByteArray logdata;
|
||||
logdata << id << size << time << PIMemoryBlock(data, size);
|
||||
@@ -338,8 +349,10 @@ int PIBinaryLog::writeBinLog_raw(int id, const PISystemTime &time, const void *d
|
||||
write_count++;
|
||||
log_size = file.size();
|
||||
logmutex.unlock();
|
||||
if (res > 0) return size;
|
||||
else return res;
|
||||
if (res > 0)
|
||||
return size;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -359,7 +372,8 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
|
||||
return br.data;
|
||||
}
|
||||
logmutex.lock();
|
||||
while (br.id != id && !isEnd()) br = readRecord();
|
||||
while (br.id != id && !isEnd())
|
||||
br = readRecord();
|
||||
logmutex.unlock();
|
||||
if (br.id == -1) {
|
||||
piCoutObj << "End of BinLog file";
|
||||
@@ -376,7 +390,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
|
||||
}
|
||||
|
||||
|
||||
int PIBinaryLog::readBinLog(int id, void *read_to, int max_size, PISystemTime * time, int * readed_id) {
|
||||
int PIBinaryLog::readBinLog(int id, void * read_to, int max_size, PISystemTime * time, int * readed_id) {
|
||||
if (max_size <= 0 || read_to == 0) return -1;
|
||||
PIByteArray ba = readBinLog(id, time, readed_id);
|
||||
if (ba.isEmpty()) return -1;
|
||||
@@ -401,10 +415,10 @@ PIByteArray PIBinaryLog::getHeader() {
|
||||
}
|
||||
|
||||
|
||||
ssize_t PIBinaryLog::readDevice(void *read_to, ssize_t max_size) {
|
||||
ssize_t PIBinaryLog::readDevice(void * read_to, ssize_t max_size) {
|
||||
PIMutexLocker _ml(logmutex);
|
||||
if (lastrecord.id == -1 || isEnd()) return 0;
|
||||
if(!is_thread_ok && lastrecord.id > 0) return lastrecord.data.size();
|
||||
if (!is_thread_ok && lastrecord.id > 0) return lastrecord.data.size();
|
||||
if (!canRead()) return -1;
|
||||
if (max_size <= 0 || read_to == 0) return -1;
|
||||
BinLogRecord br;
|
||||
@@ -412,7 +426,8 @@ ssize_t PIBinaryLog::readDevice(void *read_to, ssize_t max_size) {
|
||||
if (filterID.isEmpty()) {
|
||||
br = readRecord();
|
||||
} else {
|
||||
while (!filterID.contains(br.id) && !isEnd()) br = readRecord();
|
||||
while (!filterID.contains(br.id) && !isEnd())
|
||||
br = readRecord();
|
||||
}
|
||||
if (br.id == -1) {
|
||||
fileEnd();
|
||||
@@ -441,10 +456,10 @@ void PIBinaryLog::restart() {
|
||||
if (!canRead()) return;
|
||||
logmutex.unlock();
|
||||
lastrecord.timestamp = PISystemTime();
|
||||
lastrecord.id = 0;
|
||||
is_thread_ok = true;
|
||||
is_started = !rapidStart();
|
||||
play_time = 0;
|
||||
lastrecord.id = 0;
|
||||
is_thread_ok = true;
|
||||
is_started = !rapidStart();
|
||||
play_time = 0;
|
||||
file.seekToBegin();
|
||||
checkFileHeader();
|
||||
moveIndex(0);
|
||||
@@ -468,10 +483,11 @@ bool PIBinaryLog::writeFileHeader() {
|
||||
bool PIBinaryLog::checkFileHeader() {
|
||||
binfo.user_header.clear();
|
||||
uchar read_sig[PIBINARYLOG_SIGNATURE_SIZE];
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++) read_sig[i] = 0;
|
||||
for (uint i = 0; i < PIBINARYLOG_SIGNATURE_SIZE; i++)
|
||||
read_sig[i] = 0;
|
||||
if (file.read(read_sig, PIBINARYLOG_SIGNATURE_SIZE) < 0) return false;
|
||||
bool correct = true;
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++)
|
||||
for (uint i = 0; i < PIBINARYLOG_SIGNATURE_SIZE; i++)
|
||||
if (read_sig[i] != binlog_sig[i]) correct = false;
|
||||
if (!correct) {
|
||||
piCoutObj << "BinLogFile signature is corrupted or invalid file";
|
||||
@@ -484,7 +500,7 @@ bool PIBinaryLog::checkFileHeader() {
|
||||
return true;
|
||||
}
|
||||
if (read_version == PIBINARYLOG_VERSION) {
|
||||
log_size = file.size();
|
||||
log_size = file.size();
|
||||
uint32_t sz = 0;
|
||||
file.read(&sz, 4);
|
||||
if (sz > 0) {
|
||||
@@ -492,18 +508,15 @@ bool PIBinaryLog::checkFileHeader() {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (read_version == 0)
|
||||
piCoutObj << "BinLogFile has invalid version";
|
||||
if (read_version < PIBINARYLOG_VERSION)
|
||||
piCoutObj << "BinLogFile has too old verion";
|
||||
if (read_version > PIBINARYLOG_VERSION)
|
||||
piCoutObj << "BinLogFile has too newest version";
|
||||
if (read_version == 0) piCoutObj << "BinLogFile has invalid version";
|
||||
if (read_version < PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too old verion";
|
||||
if (read_version > PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too newest version";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIBinaryLog::BinLogRecord PIBinaryLog::readRecord() {
|
||||
// piCoutObj << "readRecord";
|
||||
// piCoutObj << "readRecord";
|
||||
logmutex.lock();
|
||||
PIByteArray ba;
|
||||
BinLogRecord br;
|
||||
@@ -511,33 +524,35 @@ PIBinaryLog::BinLogRecord PIBinaryLog::readRecord() {
|
||||
lastrecord.data.clear();
|
||||
lastrecord.timestamp = PISystemTime();
|
||||
ba.resize(sizeof(BinLogRecord) - sizeof(PIByteArray));
|
||||
if(file.read(ba.data(), ba.size_s()) > 0) {
|
||||
if (file.read(ba.data(), ba.size_s()) > 0) {
|
||||
ba >> br.id >> br.size >> br.timestamp;
|
||||
} else {
|
||||
br.id = -1;
|
||||
logmutex.unlock();
|
||||
// piCoutObj << "readRecord done";
|
||||
// piCoutObj << "readRecord done";
|
||||
return br;
|
||||
}
|
||||
if (br.id > 0 && br.size > 0) {
|
||||
ba.resize(br.size);
|
||||
if(file.read(ba.data(), ba.size_s()) > 0) br.data = ba;
|
||||
else br.id = 0;
|
||||
} else br.id = 0;
|
||||
if (file.read(ba.data(), ba.size_s()) > 0)
|
||||
br.data = ba;
|
||||
else
|
||||
br.id = 0;
|
||||
} else
|
||||
br.id = 0;
|
||||
lastrecord = br;
|
||||
if (br.id == 0) fileError();
|
||||
moveIndex(index_pos.value(file.pos(), -1));
|
||||
logmutex.unlock();
|
||||
// piCoutObj << "readRecord done";
|
||||
// piCoutObj << "readRecord done";
|
||||
return br;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<PIBinaryLog::BinLogIndex> * index) {
|
||||
if (!info && !index) return;
|
||||
if (info) {
|
||||
info->log_size = -1;
|
||||
info->log_size = -1;
|
||||
info->records_count = 0;
|
||||
info->records.clear();
|
||||
}
|
||||
@@ -545,16 +560,17 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
if (f == 0) return;
|
||||
if (!f->canRead()) return;
|
||||
if (info) {
|
||||
info->path = f->path();
|
||||
info->path = f->path();
|
||||
info->log_size = f->size();
|
||||
}
|
||||
uchar read_sig[PIBINARYLOG_SIGNATURE_SIZE];
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++) read_sig[i] = 0;
|
||||
for (uint i = 0; i < PIBINARYLOG_SIGNATURE_SIZE; i++)
|
||||
read_sig[i] = 0;
|
||||
if (f->read(read_sig, PIBINARYLOG_SIGNATURE_SIZE) < 0) {
|
||||
if (info) info->records_count = -1;
|
||||
return;
|
||||
}
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++) {
|
||||
for (uint i = 0; i < PIBINARYLOG_SIGNATURE_SIZE; i++) {
|
||||
if (read_sig[i] != binlog_sig[i]) {
|
||||
if (info) info->records_count = -2;
|
||||
return;
|
||||
@@ -565,7 +581,7 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
if (info) info->records_count = -3;
|
||||
return;
|
||||
}
|
||||
if (read_version == 0) {
|
||||
if (read_version == 0) {
|
||||
if (info) info->records_count = -4;
|
||||
return;
|
||||
}
|
||||
@@ -586,9 +602,9 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
}
|
||||
PIByteArray ba;
|
||||
BinLogRecord br;
|
||||
br.id = 0;
|
||||
br.size = 0;
|
||||
bool first = true;
|
||||
br.id = 0;
|
||||
br.size = 0;
|
||||
bool first = true;
|
||||
size_t hdr_size = sizeof(BinLogRecord) - sizeof(PIByteArray);
|
||||
ba.resize(hdr_size);
|
||||
while (1) {
|
||||
@@ -596,20 +612,21 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
{
|
||||
if (f->read(ba.data(), ba.size()) > 0) {
|
||||
ba >> br.id >> br.size >> br.timestamp;
|
||||
} else break;
|
||||
} else
|
||||
break;
|
||||
if (info) {
|
||||
if (info->log_size - f->pos() >= br.size) {
|
||||
f->seek(f->pos() + br.size);
|
||||
}
|
||||
}
|
||||
else break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (br.id > 0) {
|
||||
if (index) {
|
||||
BinLogIndex bl_ind;
|
||||
bl_ind.id = br.id;
|
||||
bl_ind.id = br.id;
|
||||
bl_ind.data_size = br.size;
|
||||
bl_ind.pos = f->pos() - br.size - hdr_size;
|
||||
bl_ind.pos = f->pos() - br.size - hdr_size;
|
||||
bl_ind.timestamp = br.timestamp;
|
||||
index->append(bl_ind);
|
||||
}
|
||||
@@ -617,14 +634,14 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
info->records_count++;
|
||||
if (first) {
|
||||
info->start_time = br.timestamp;
|
||||
first = false;
|
||||
first = false;
|
||||
}
|
||||
BinLogRecordInfo &bri(info->records[br.id]);
|
||||
BinLogRecordInfo & bri(info->records[br.id]);
|
||||
bri.count++;
|
||||
if (bri.id == 0) {
|
||||
bri.id = br.id;
|
||||
bri.id = br.id;
|
||||
bri.minimum_size = bri.maximum_size = br.size;
|
||||
bri.start_time = br.timestamp;
|
||||
bri.start_time = br.timestamp;
|
||||
} else {
|
||||
bri.end_time = br.timestamp;
|
||||
if (bri.minimum_size > br.size) bri.minimum_size = br.size;
|
||||
@@ -647,7 +664,7 @@ void PIBinaryLog::moveIndex(int i) {
|
||||
|
||||
PIBinaryLog::BinLogInfo PIBinaryLog::getLogInfo(const PIString & path) {
|
||||
BinLogInfo bi;
|
||||
bi.path = path;
|
||||
bi.path = path;
|
||||
bi.records_count = 0;
|
||||
PIFile tfile;
|
||||
if (!tfile.open(path, PIIODevice::ReadOnly)) return bi;
|
||||
@@ -659,7 +676,8 @@ PIBinaryLog::BinLogInfo PIBinaryLog::getLogInfo(const PIString & path) {
|
||||
bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString & dst, int from, int to) {
|
||||
PIBinaryLog slog;
|
||||
if (!slog.open(src.path, PIIODevice::ReadOnly)) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't open" << src.path;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't open" << src.path;
|
||||
return false;
|
||||
}
|
||||
PIVector<int> ids = src.records.keys();
|
||||
@@ -667,7 +685,8 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
|
||||
PIBinaryLog dlog;
|
||||
dlog.createNewFile(dst);
|
||||
if (!dlog.isOpened()) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't create" << dst;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't create" << dst;
|
||||
return false;
|
||||
}
|
||||
bool first = true;
|
||||
@@ -677,34 +696,39 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
|
||||
while (!slog.isEnd() && ((slog.pos() <= to) || to < 0)) {
|
||||
br = slog.readRecord();
|
||||
if (first) {
|
||||
st = br.timestamp;
|
||||
st = br.timestamp;
|
||||
first = false;
|
||||
}
|
||||
if (ids.contains(br.id)) {
|
||||
if (dlog.writeBinLog_raw(br.id, br.timestamp - st, br.data) <= 0) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't write to file" << dst;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't write to file" << dst;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tm.elapsed_s() > 1) {
|
||||
tm.reset();
|
||||
piCout << "[PIBinaryLog]" << "process" << PITime::fromSystemTime(br.timestamp).toString();
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "process" << PITime::fromSystemTime(br.timestamp).toString();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src, const PIString & dst, std::function<bool (const PIString &, PISystemTime)> progress) {
|
||||
bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
|
||||
const PIString & dst,
|
||||
std::function<bool(const PIString &, PISystemTime)> progress) {
|
||||
PIBinaryLog slog;
|
||||
PIBinaryLog dlog;
|
||||
PISystemTime dtime;
|
||||
PISystemTime lt;
|
||||
PITimeMeasurer tm;
|
||||
bool first = true;
|
||||
for (const PIString & fn : src) {
|
||||
for (const PIString & fn: src) {
|
||||
if (!slog.open(fn, PIIODevice::ReadOnly)) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't open" << fn;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't open" << fn;
|
||||
return false;
|
||||
}
|
||||
if (first) {
|
||||
@@ -712,10 +736,12 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src, const PIString & d
|
||||
dlog.setHeader(slog.getHeader());
|
||||
dlog.createNewFile(dst);
|
||||
if (!dlog.isOpened()) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't create" << dst;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't create" << dst;
|
||||
return false;
|
||||
}
|
||||
piCout << "[PIBinaryLog]" << "Start join binlogs to" << dst;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Start join binlogs to" << dst;
|
||||
} else {
|
||||
dtime = lt;
|
||||
}
|
||||
@@ -728,7 +754,8 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src, const PIString & d
|
||||
st = br.timestamp;
|
||||
lt = dtime + br.timestamp;
|
||||
if (dlog.writeBinLog_raw(br.id, lt, br.data) <= 0) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't write to file" << dst;
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't write to file" << dst;
|
||||
return false;
|
||||
}
|
||||
if (tm.elapsed_s() > 0.1) {
|
||||
@@ -741,14 +768,16 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src, const PIString & d
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
piCout << "[PIBinaryLog]" << "process" << PITime::fromSystemTime(lt).toString();
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "process" << PITime::fromSystemTime(lt).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
slog.close();
|
||||
//piCout << "[PIBinaryLog]" << "complete" << fn;
|
||||
// piCout << "[PIBinaryLog]" << "complete" << fn;
|
||||
}
|
||||
piCout << "[PIBinaryLog]" << "Finish join binlogs, total time" << PITime::fromSystemTime(lt).toString();
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Finish join binlogs, total time" << PITime::fromSystemTime(lt).toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -762,7 +791,8 @@ bool PIBinaryLog::createIndex() {
|
||||
parseLog(&file, &binfo, &index);
|
||||
file.seek(cp);
|
||||
is_indexed = !index.isEmpty();
|
||||
for (uint i=0; i<index.size(); i++) index_pos[index[i].pos] = i;
|
||||
for (uint i = 0; i < index.size(); i++)
|
||||
index_pos[index[i].pos] = i;
|
||||
logmutex.unlock();
|
||||
return is_indexed;
|
||||
}
|
||||
@@ -781,20 +811,20 @@ int PIBinaryLog::posForTime(const PISystemTime & time) {
|
||||
|
||||
|
||||
void PIBinaryLog::seekTo(int rindex) {
|
||||
// piCoutObj << "seekTo";
|
||||
// piCoutObj << "seekTo";
|
||||
logmutex.lock();
|
||||
pausemutex.lock();
|
||||
if (rindex < index.size_s() && rindex >= 0) {
|
||||
file.seek(index[rindex].pos);
|
||||
moveIndex(index_pos.value(file.pos(), -1));
|
||||
//double prev_pt = play_time;
|
||||
play_time = index[rindex].timestamp.toMilliseconds();
|
||||
// double prev_pt = play_time;
|
||||
play_time = index[rindex].timestamp.toMilliseconds();
|
||||
lastrecord.timestamp = index[rindex].timestamp;
|
||||
if (play_mode == PlayRealTime) {
|
||||
startlogtime = PISystemTime::current() - lastrecord.timestamp;
|
||||
}
|
||||
}
|
||||
// piCoutObj << "seekTo done";
|
||||
// piCoutObj << "seekTo done";
|
||||
pausemutex.unlock();
|
||||
logmutex.unlock();
|
||||
}
|
||||
@@ -812,7 +842,7 @@ bool PIBinaryLog::seek(const PISystemTime & time) {
|
||||
|
||||
bool PIBinaryLog::seek(llong filepos) {
|
||||
int ci = -1;
|
||||
for (uint i=0; i<index.size(); i++) {
|
||||
for (uint i = 0; i < index.size(); i++) {
|
||||
if (filepos <= index[i].pos && (filterID.contains(index[i].id) || filterID.isEmpty())) {
|
||||
ci = i;
|
||||
break;
|
||||
@@ -830,18 +860,10 @@ PIString PIBinaryLog::constructFullPathDevice() const {
|
||||
PIString ret;
|
||||
ret += logDir() + ":" + filePrefix() + ":" + PIString::fromNumber(defaultID()) + ":";
|
||||
switch (play_mode) {
|
||||
case PlayRealTime:
|
||||
ret += "RT";
|
||||
break;
|
||||
case PlayVariableSpeed:
|
||||
ret += PIString::fromNumber(playSpeed()) + "X";
|
||||
break;
|
||||
case PlayStaticDelay:
|
||||
ret += PIString::fromNumber(playDelay().toMilliseconds()) + "M";
|
||||
break;
|
||||
default:
|
||||
ret += "RT";
|
||||
break;
|
||||
case PlayRealTime: ret += "RT"; break;
|
||||
case PlayVariableSpeed: ret += PIString::fromNumber(playSpeed()) + "X"; break;
|
||||
case PlayStaticDelay: ret += PIString::fromNumber(playDelay().toMilliseconds()) + "M"; break;
|
||||
default: ret += "RT"; break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -859,7 +881,7 @@ void PIBinaryLog::configureFromFullPathDevice(const PIString & full_path) {
|
||||
if (p.toUpperCase() == "RT") setPlayRealTime();
|
||||
if (p.toUpperCase().right(1) == "X") setPlaySpeed((p.left(p.size() - 1)).toDouble());
|
||||
if (p.toUpperCase().right(1) == "M") setPlayDelay(PISystemTime::fromMilliseconds((p.left(p.size() - 1)).toDouble()));
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// piCoutObj << "configured";
|
||||
@@ -872,7 +894,9 @@ PIPropertyStorage PIBinaryLog::constructVariantDevice() const {
|
||||
ret.addProperty("log dir", PIVariantTypes::Dir(logDir()));
|
||||
ret.addProperty("file prefix", filePrefix());
|
||||
ret.addProperty("default ID", defaultID());
|
||||
e << "real-time" << "variable speed" << "static delay";
|
||||
e << "real-time"
|
||||
<< "variable speed"
|
||||
<< "static delay";
|
||||
e.selectValue((int)playMode());
|
||||
ret.addProperty("play mode", e);
|
||||
ret.addProperty("play speed", playSpeed());
|
||||
@@ -892,16 +916,15 @@ void PIBinaryLog::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
|
||||
|
||||
void PIBinaryLog::propertyChanged(const char * s) {
|
||||
default_id = property("defaultID").toInt();
|
||||
default_id = property("defaultID").toInt();
|
||||
rapid_start = property("rapidStart").toBool();
|
||||
play_mode = (PlayMode)property("playMode").toInt();
|
||||
double ps = property("playSpeed").toDouble();
|
||||
play_speed = ps > 0. ? 1. / ps : 0.;
|
||||
play_delay = property("playDelay").toSystemTime();
|
||||
split_mode = (SplitMode)property("splitMode").toInt();
|
||||
split_time = property("splitTime").toSystemTime();
|
||||
split_size = property("splitFileSize").toLLong();
|
||||
play_mode = (PlayMode)property("playMode").toInt();
|
||||
double ps = property("playSpeed").toDouble();
|
||||
play_speed = ps > 0. ? 1. / ps : 0.;
|
||||
play_delay = property("playDelay").toSystemTime();
|
||||
split_mode = (SplitMode)property("splitMode").toInt();
|
||||
split_time = property("splitTime").toSystemTime();
|
||||
split_size = property("splitFileSize").toLLong();
|
||||
split_count = property("splitRecordCount").toInt();
|
||||
// piCoutObj << "propertyChanged" << s << play_mode;
|
||||
// piCoutObj << "propertyChanged" << s << play_mode;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Бинарный лог
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for write binary data to logfile, and read or playback this data
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Class for write binary data to logfile, and read or playback this data
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIBINARYLOG_H
|
||||
@@ -32,32 +32,32 @@
|
||||
//! \~\brief
|
||||
//! \~english Binary log
|
||||
//! \~russian Бинарный лог
|
||||
class PIP_EXPORT PIBinaryLog: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIBinaryLog: public PIIODevice {
|
||||
PIIODEVICE(PIBinaryLog, "binlog");
|
||||
|
||||
public:
|
||||
explicit PIBinaryLog();
|
||||
virtual ~PIBinaryLog();
|
||||
|
||||
//! \brief Play modes for \a PIBinaryLog
|
||||
enum PlayMode {
|
||||
PlayRealTime /*! Play in system realtime, default mode */ ,
|
||||
PlayVariableSpeed /*! Play in software realtime with speed, set by \a setSpeed */ ,
|
||||
PlayStaticDelay /*! Play with custom static delay, ignoring timestamp */
|
||||
PlayRealTime /*! Play in system realtime, default mode */,
|
||||
PlayVariableSpeed /*! Play in software realtime with speed, set by \a setSpeed */,
|
||||
PlayStaticDelay /*! Play with custom static delay, ignoring timestamp */
|
||||
};
|
||||
|
||||
|
||||
//! \brief Different split modes for writing \a PIBinaryLog, which can separate files by size, by time or by records count
|
||||
enum SplitMode {
|
||||
SplitNone /*! Without separate, default mode */ ,
|
||||
SplitTime /*! Separate files by record time */ ,
|
||||
SplitSize /*! Separate files by size */ ,
|
||||
SplitCount /*! Separate files by records count */
|
||||
SplitNone /*! Without separate, default mode */,
|
||||
SplitTime /*! Separate files by record time */,
|
||||
SplitSize /*! Separate files by size */,
|
||||
SplitCount /*! Separate files by records count */
|
||||
};
|
||||
|
||||
//! \brief Struct contains information about all records with same ID
|
||||
struct PIP_EXPORT BinLogRecordInfo {
|
||||
BinLogRecordInfo() {
|
||||
id = count = 0;
|
||||
id = count = 0;
|
||||
minimum_size = maximum_size = 0;
|
||||
}
|
||||
int id;
|
||||
@@ -89,81 +89,96 @@ public:
|
||||
|
||||
|
||||
//! Current \a PlayMode
|
||||
PlayMode playMode() const {return play_mode;}
|
||||
PlayMode playMode() const { return play_mode; }
|
||||
|
||||
//! Current \a SplitMode
|
||||
SplitMode splitMode() const {return split_mode;}
|
||||
SplitMode splitMode() const { return split_mode; }
|
||||
|
||||
//! Current directory where billogs wiil be saved
|
||||
PIString logDir() const {return property("logDir").toString();}
|
||||
|
||||
PIString logDir() const { return property("logDir").toString(); }
|
||||
|
||||
//! Returns current file prefix
|
||||
PIString filePrefix() const {return property("filePrefix").toString();}
|
||||
|
||||
PIString filePrefix() const { return property("filePrefix").toString(); }
|
||||
|
||||
//! Default ID, used in \a write function
|
||||
int defaultID() const {return default_id;}
|
||||
|
||||
int defaultID() const { return default_id; }
|
||||
|
||||
//! Returns current play speed
|
||||
double playSpeed() const {return play_speed > 0 ? 1. / play_speed : 0.;}
|
||||
double playSpeed() const { return play_speed > 0 ? 1. / play_speed : 0.; }
|
||||
|
||||
//! Returns current play delay
|
||||
PISystemTime playDelay() const {return play_delay;}
|
||||
PISystemTime playDelay() const { return play_delay; }
|
||||
|
||||
//! Returns current binlog file split time
|
||||
PISystemTime splitTime() const {return split_time;}
|
||||
PISystemTime splitTime() const { return split_time; }
|
||||
|
||||
//! Returns current binlog file split size
|
||||
llong splitFileSize() const {return split_size;}
|
||||
llong splitFileSize() const { return split_size; }
|
||||
|
||||
//! Returns current binlog file split records count
|
||||
int splitRecordCount() const {return split_count;}
|
||||
int splitRecordCount() const { return split_count; }
|
||||
|
||||
//! Returns if rapid start enabled
|
||||
bool rapidStart() const {return rapid_start;}
|
||||
|
||||
bool rapidStart() const { return rapid_start; }
|
||||
|
||||
//! Create binlog file with Filename = path
|
||||
void createNewFile(const PIString &path);
|
||||
|
||||
void createNewFile(const PIString & path);
|
||||
|
||||
//! Set \a PlayMode
|
||||
void setPlayMode(PlayMode mode) {setProperty("playMode", (int)mode);}
|
||||
void setPlayMode(PlayMode mode) { setProperty("playMode", (int)mode); }
|
||||
|
||||
//! Set \a SplitMode
|
||||
void setSplitMode(SplitMode mode) {setProperty("splitMode", (int)mode);}
|
||||
void setSplitMode(SplitMode mode) { setProperty("splitMode", (int)mode); }
|
||||
|
||||
//! Set path to directory where binlogs will be saved
|
||||
void setLogDir(const PIString & path) {setProperty("logDir", path);}
|
||||
|
||||
void setLogDir(const PIString & path) { setProperty("logDir", path); }
|
||||
|
||||
//! Set file prefix, used to
|
||||
void setFilePrefix(const PIString & prefix) {setProperty("filePrefix", prefix);}
|
||||
|
||||
void setFilePrefix(const PIString & prefix) { setProperty("filePrefix", prefix); }
|
||||
|
||||
//! Set defaultID, used in \a write function
|
||||
void setDefaultID(int id) {setProperty("defaultID", id);}
|
||||
|
||||
void setDefaultID(int id) { setProperty("defaultID", id); }
|
||||
|
||||
//! If enabled BinLog \a ThreadedRead starts without delay for first record, i.e. first record will be readed immediately
|
||||
void setRapidStart(bool enabled) {setProperty("rapidStart", enabled);}
|
||||
void setRapidStart(bool enabled) { setProperty("rapidStart", enabled); }
|
||||
|
||||
//! Set play speed to "speed", default value is 1.0x
|
||||
//! Also this function set \a playMode to \a PlayVariableSpeed
|
||||
void setPlaySpeed(double speed) {setPlayMode(PlayVariableSpeed); setProperty("playSpeed", speed);}
|
||||
void setPlaySpeed(double speed) {
|
||||
setPlayMode(PlayVariableSpeed);
|
||||
setProperty("playSpeed", speed);
|
||||
}
|
||||
|
||||
//! Setting static delay between records, default value is 1 sec
|
||||
//! Also this function set \a playMode to \a PlayStaticDelay
|
||||
void setPlayDelay(const PISystemTime & delay) {setPlayMode(PlayStaticDelay); setProperty("playDelay", delay);}
|
||||
void setPlayDelay(const PISystemTime & delay) {
|
||||
setPlayMode(PlayStaticDelay);
|
||||
setProperty("playDelay", delay);
|
||||
}
|
||||
|
||||
//! Set \a playMode to \a PlayRealTime
|
||||
void setPlayRealTime() {setPlayMode(PlayRealTime);}
|
||||
void setPlayRealTime() { setPlayMode(PlayRealTime); }
|
||||
|
||||
//! Set binlog file split time
|
||||
//! Also this function set \a splitMode to \a SplitTime
|
||||
void setSplitTime(const PISystemTime & time) {setSplitMode(SplitTime); setProperty("splitTime", time);}
|
||||
void setSplitTime(const PISystemTime & time) {
|
||||
setSplitMode(SplitTime);
|
||||
setProperty("splitTime", time);
|
||||
}
|
||||
|
||||
//! Set binlog file split size
|
||||
//! Also this function set \a splitMode to \a SplitSize
|
||||
void setSplitFileSize(llong size) {setSplitMode(SplitSize); setProperty("splitFileSize", size);}
|
||||
void setSplitFileSize(llong size) {
|
||||
setSplitMode(SplitSize);
|
||||
setProperty("splitFileSize", size);
|
||||
}
|
||||
|
||||
//! Set binlog file split records count
|
||||
//! Also this function set \a splitMode to \a SplitCount
|
||||
void setSplitRecordCount(int count) {setSplitMode(SplitCount); setProperty("splitRecordCount", count);}
|
||||
void setSplitRecordCount(int count) {
|
||||
setSplitMode(SplitCount);
|
||||
setProperty("splitRecordCount", count);
|
||||
}
|
||||
|
||||
//! Set pause while playing via \a threadedRead or writing via write
|
||||
void setPause(bool pause);
|
||||
@@ -171,82 +186,90 @@ public:
|
||||
//! Set function wich returns new binlog file path when using split mode.
|
||||
//! Overrides internal file path generator (logdir() + prefix() + current_time()).
|
||||
//! To restore internal file path generator set this function to "nullptr".
|
||||
void setFuncGetNewFilePath(std::function<PIString()> f) {f_new_path = f;}
|
||||
void setFuncGetNewFilePath(std::function<PIString()> f) { f_new_path = f; }
|
||||
|
||||
//! Write one record to BinLog file, with ID = id, id must be greather than 0
|
||||
int writeBinLog(int id, PIByteArray data) {return writeBinLog(id, data.data(), data.size_s());}
|
||||
|
||||
int writeBinLog(int id, PIByteArray data) { return writeBinLog(id, data.data(), data.size_s()); }
|
||||
|
||||
//! Write one record to BinLog file, with ID = id, id must be greather than 0
|
||||
int writeBinLog(int id, const void * data, int size);
|
||||
|
||||
//! Write one RAW record to BinLog file, with ID = id, Timestamp = time
|
||||
int writeBinLog_raw(int id, const PISystemTime &time, const PIByteArray &data) {return writeBinLog_raw(id, time, data.data(), data.size_s());}
|
||||
int writeBinLog_raw(int id, const PISystemTime &time, const void * data, int size);
|
||||
int writeBinLog_raw(int id, const PISystemTime & time, const PIByteArray & data) {
|
||||
return writeBinLog_raw(id, time, data.data(), data.size_s());
|
||||
}
|
||||
int writeBinLog_raw(int id, const PISystemTime & time, const void * data, int size);
|
||||
|
||||
//! Returns count of writed records
|
||||
int writeCount() const {return write_count;}
|
||||
|
||||
int writeCount() const { return write_count; }
|
||||
|
||||
//! Read one record from BinLog file, with ID = id, if id = 0 than any id will be readed
|
||||
PIByteArray readBinLog(int id = 0, PISystemTime * time = 0, int * readed_id = 0);
|
||||
|
||||
|
||||
//! Read one record from BinLog file, with ID = id, if id = 0 than any id will be readed
|
||||
int readBinLog(int id, void * read_to, int max_size, PISystemTime * time = 0, int * readed_id = 0);
|
||||
|
||||
|
||||
//! Returns binary log file size
|
||||
llong logSize() const {return log_size;}
|
||||
llong logSize() const { return log_size; }
|
||||
|
||||
//! Return position in current binlog file
|
||||
llong logPos() const {return file.pos();}
|
||||
llong logPos() const { return file.pos(); }
|
||||
|
||||
//! Return true, if position at the end of BinLog file
|
||||
bool isEnd() const {if (isClosed()) return true; return file.isEnd();}
|
||||
|
||||
bool isEnd() const {
|
||||
if (isClosed()) return true;
|
||||
return file.isEnd();
|
||||
}
|
||||
|
||||
//! Returns if BinLog file is empty
|
||||
bool isEmpty() const;
|
||||
|
||||
//! Returns BinLog pause status
|
||||
bool isPause() const {return is_pause;}
|
||||
|
||||
bool isPause() const { return is_pause; }
|
||||
|
||||
//! Returns id of last readed record
|
||||
int lastReadedID() const {return lastrecord.id;}
|
||||
int lastReadedID() const { return lastrecord.id; }
|
||||
|
||||
//! Returns timestamp of last readed record
|
||||
PISystemTime lastReadedTimestamp() const {return lastrecord.timestamp;}
|
||||
PISystemTime lastReadedTimestamp() const { return lastrecord.timestamp; }
|
||||
|
||||
//! Returns timestamp of log start
|
||||
PISystemTime logStartTimestamp() const {return startlogtime;}
|
||||
PISystemTime logStartTimestamp() const { return startlogtime; }
|
||||
|
||||
//!Set custom file header, you can get it back when read this binlog
|
||||
//! Set custom file header, you can get it back when read this binlog
|
||||
void setHeader(const PIByteArray & header);
|
||||
|
||||
//!Get custom file header
|
||||
//! Get custom file header
|
||||
PIByteArray getHeader();
|
||||
|
||||
#ifdef DOXYGEN
|
||||
//! Read one message from binlog file, with ID contains in "filterID" or any ID, if "filterID" is empty
|
||||
int read(void *read_to, int max_size);
|
||||
|
||||
int read(void * read_to, int max_size);
|
||||
|
||||
//! Write one record to BinLog file, with ID = "defaultID"
|
||||
int write(const void * data, int size);
|
||||
#endif
|
||||
|
||||
//! Array of ID, that BinLog can read from binlog file, when use \a read function, or in \a ThreadedRead
|
||||
PIVector<int> filterID;
|
||||
|
||||
|
||||
//! Go to begin of BinLog file
|
||||
void restart();
|
||||
|
||||
//! Get binlog info \a BinLogInfo
|
||||
BinLogInfo logInfo() const {if (is_indexed) return binfo; return getLogInfo(path());}
|
||||
BinLogInfo logInfo() const {
|
||||
if (is_indexed) return binfo;
|
||||
return getLogInfo(path());
|
||||
}
|
||||
|
||||
//! Get binlog index \a BinLogIndex, need \a createIndex before getting index
|
||||
const PIVector<BinLogIndex> & logIndex() const {return index;}
|
||||
|
||||
const PIVector<BinLogIndex> & logIndex() const { return index; }
|
||||
|
||||
//! Create index of current binlog file
|
||||
bool createIndex();
|
||||
|
||||
//! Return if current binlog file is indexed
|
||||
bool isIndexed() {return is_indexed;}
|
||||
bool isIndexed() { return is_indexed; }
|
||||
|
||||
//! Find nearest record of time \"time\". Returns -1 if not indexed or time less than first record
|
||||
int posForTime(const PISystemTime & time);
|
||||
@@ -261,22 +284,25 @@ public:
|
||||
bool seek(llong filepos);
|
||||
|
||||
//! Get current record index (position record in file)
|
||||
int pos() const {if (is_indexed) return current_index; return -1;}
|
||||
int pos() const {
|
||||
if (is_indexed) return current_index;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
|
||||
//! \fn PIString createNewFile()
|
||||
//! \brief Create new binlog file in \a logDir, if successful returns filename, else returns empty string.
|
||||
//! Filename is like \a filePrefix + "yyyy_MM_dd__hh_mm_ss.binlog"
|
||||
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
|
||||
//! \fn void fileEnd()
|
||||
//! \brief Raise on file end while reading
|
||||
|
||||
|
||||
//! \fn void fileError()
|
||||
//! \brief Raise on file creation error
|
||||
|
||||
@@ -284,7 +310,7 @@ public:
|
||||
//! \brief Raise on new file created
|
||||
|
||||
//! \}
|
||||
|
||||
|
||||
EVENT_HANDLER(PIString, createNewFile);
|
||||
EVENT(fileEnd);
|
||||
EVENT(fileError);
|
||||
@@ -298,20 +324,22 @@ public:
|
||||
static bool cutBinLog(const BinLogInfo & src, const PIString & dst, int from, int to);
|
||||
|
||||
//! Create new binlog from serial splitted binlogs "src"
|
||||
static bool joinBinLogsSerial(const PIStringList & src, const PIString & dst, std::function<bool (const PIString &, PISystemTime)> progress = nullptr);
|
||||
static bool joinBinLogsSerial(const PIStringList & src,
|
||||
const PIString & dst,
|
||||
std::function<bool(const PIString &, PISystemTime)> progress = nullptr);
|
||||
|
||||
protected:
|
||||
PIString constructFullPathDevice() const override;
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
ssize_t readDevice(void *read_to, ssize_t max_size) override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
void propertyChanged(const char * s) override;
|
||||
bool threadedRead(const uchar *readed, ssize_t size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
bool threadedRead(const uchar * readed, ssize_t size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
private:
|
||||
struct PIP_EXPORT BinLogRecord {
|
||||
@@ -324,7 +352,7 @@ private:
|
||||
bool writeFileHeader();
|
||||
bool checkFileHeader();
|
||||
BinLogRecord readRecord();
|
||||
static void parseLog(PIFile *f, BinLogInfo *info, PIVector<BinLogIndex> * index);
|
||||
static void parseLog(PIFile * f, BinLogInfo * info, PIVector<BinLogIndex> * index);
|
||||
void moveIndex(int i);
|
||||
static PIString getLogfilePath(const PIString & log_dir, const PIString & prefix);
|
||||
|
||||
@@ -347,7 +375,7 @@ private:
|
||||
};
|
||||
|
||||
//! \relatesalso PICout \brief Output operator PIBinaryLog::BinLogInfo to PICout
|
||||
inline PICout operator <<(PICout s, const PIBinaryLog::BinLogInfo & bi) {
|
||||
inline PICout operator<<(PICout s, const PIBinaryLog::BinLogInfo & bi) {
|
||||
s.space();
|
||||
s.saveAndSetControls(0);
|
||||
s << "[PIBinaryLog] " << bi.path << "\n";
|
||||
@@ -360,7 +388,8 @@ inline PICout operator <<(PICout s, const PIBinaryLog::BinLogInfo & bi) {
|
||||
s << "Invalid empty file";
|
||||
s.restoreControls();
|
||||
return s;
|
||||
} if (bi.records_count < 0 && bi.records_count > -4) {
|
||||
}
|
||||
if (bi.records_count < 0 && bi.records_count > -4) {
|
||||
s << "Invalid file or corrupted signature";
|
||||
s.restoreControls();
|
||||
return s;
|
||||
@@ -373,7 +402,7 @@ inline PICout operator <<(PICout s, const PIBinaryLog::BinLogInfo & bi) {
|
||||
s << "read records " << bi.records_count << " in " << bi.records.size() << " types, log size " << bi.log_size;
|
||||
s << "\nlog start " << bi.start_time << " , log end " << bi.end_time;
|
||||
PIVector<int> keys = bi.records.keys();
|
||||
for (int i : keys) {
|
||||
for (int i: keys) {
|
||||
PIBinaryLog::BinLogRecordInfo bri = bi.records.at(i);
|
||||
s << "\n record id " << bri.id << " , count " << bri.count;
|
||||
s << "\n record start " << bri.start_time << " , end " << bri.end_time;
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
CAN
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
CAN
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "pican.h"
|
||||
|
||||
#include "pipropertystorage.h"
|
||||
#include "piwaitevent_p.h"
|
||||
#if !defined(WINDOWS) && !defined(MAC_OS) && !defined(MICRO_PIP)
|
||||
# define PIP_CAN
|
||||
#endif
|
||||
#ifdef PIP_CAN
|
||||
# include <sys/ioctl.h>
|
||||
# include <net/if.h>
|
||||
# include <linux/can.h>
|
||||
# include <linux/can/raw.h>
|
||||
# include <net/if.h>
|
||||
# include <sys/ioctl.h>
|
||||
# ifndef AF_CAN
|
||||
# define AF_CAN 29
|
||||
# define AF_CAN 29
|
||||
# endif
|
||||
# ifndef PF_CAN
|
||||
# define PF_CAN AF_CAN
|
||||
# define PF_CAN AF_CAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -44,11 +45,11 @@ PRIVATE_DEFINITION_START(PICAN)
|
||||
PRIVATE_DEFINITION_END(PICAN)
|
||||
|
||||
|
||||
PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode) {
|
||||
PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode) {
|
||||
setThreadedReadBufferSize(256);
|
||||
setPath(path);
|
||||
can_id = 0;
|
||||
sock = 0;
|
||||
sock = 0;
|
||||
PRIVATE->event.create();
|
||||
}
|
||||
|
||||
@@ -64,27 +65,27 @@ bool PICAN::openDevice() {
|
||||
#ifdef PIP_CAN
|
||||
piCout << "PICAN open device" << path();
|
||||
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if(sock < 0){
|
||||
if (sock < 0) {
|
||||
piCoutObj << "Error! while opening socket";
|
||||
return false;
|
||||
}
|
||||
ifreq ifr;
|
||||
strcpy(ifr.ifr_name, path().dataAscii());
|
||||
piCout << "PICAN try to get interface index...";
|
||||
if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0){
|
||||
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
|
||||
piCoutObj << "Error! while determin the interface ioctl";
|
||||
return false;
|
||||
}
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv);
|
||||
// bind socket to all CAN interface
|
||||
sockaddr_can addr;
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
piCout << "PICAN try to bind socket to interface" << ifr.ifr_ifindex;
|
||||
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0){
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
piCoutObj << "Error! while binding socket";
|
||||
return false;
|
||||
}
|
||||
@@ -108,13 +109,14 @@ bool PICAN::closeDevice() {
|
||||
|
||||
ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
|
||||
#ifdef PIP_CAN
|
||||
//piCout << "PICAN read";
|
||||
// piCout << "PICAN read";
|
||||
can_frame frame;
|
||||
ssize_t ret = 0;
|
||||
if (PRIVATE->event.wait(sock))
|
||||
ret = ::read(sock, &frame, sizeof(can_frame));
|
||||
if (ret < 0) {/*piCoutObj << "Error while read CAN frame " << ret;*/ return -1;}
|
||||
//piCoutObj << "receive CAN frame Id =" << frame.can_id;
|
||||
if (PRIVATE->event.wait(sock)) ret = ::read(sock, &frame, sizeof(can_frame));
|
||||
if (ret < 0) { /*piCoutObj << "Error while read CAN frame " << ret;*/
|
||||
return -1;
|
||||
}
|
||||
// piCoutObj << "receive CAN frame Id =" << frame.can_id;
|
||||
memcpy(read_to, frame.data, piMini(frame.can_dlc, max_size));
|
||||
readed_id = frame.can_id;
|
||||
return piMini(frame.can_dlc, max_size);
|
||||
@@ -125,15 +127,21 @@ ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
|
||||
|
||||
ssize_t PICAN::writeDevice(const void * data, ssize_t max_size) {
|
||||
#ifdef PIP_CAN
|
||||
//piCout << "PICAN write" << can_id << max_size;
|
||||
if (max_size > 8) {piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!"; return -1;}
|
||||
// piCout << "PICAN write" << can_id << max_size;
|
||||
if (max_size > 8) {
|
||||
piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!";
|
||||
return -1;
|
||||
}
|
||||
can_frame frame;
|
||||
frame.can_id = can_id;
|
||||
frame.can_id = can_id;
|
||||
frame.can_dlc = max_size;
|
||||
memcpy(frame.data, data, max_size);
|
||||
ssize_t ret = 0;
|
||||
ret = ::write(sock, &frame, sizeof(can_frame));
|
||||
if (ret < 0) {piCoutObj << "Error while send CAN frame " << ret; return -1;}
|
||||
ret = ::write(sock, &frame, sizeof(can_frame));
|
||||
if (ret < 0) {
|
||||
piCoutObj << "Error while send CAN frame " << ret;
|
||||
return -1;
|
||||
}
|
||||
return max_size;
|
||||
#endif
|
||||
return 0;
|
||||
@@ -183,7 +191,7 @@ void PICAN::configureFromFullPathDevice(const PIString & full_path) {
|
||||
PIPropertyStorage PICAN::constructVariantDevice() const {
|
||||
PIPropertyStorage ret;
|
||||
ret.addProperty("path", path());
|
||||
ret.addProperty("CAN ID", PIString::fromNumber(CANID(),16));
|
||||
ret.addProperty("CAN ID", PIString::fromNumber(CANID(), 16));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Устройство CAN
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
CAN
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
CAN
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICAN_H
|
||||
@@ -29,9 +29,9 @@
|
||||
#include "piiodevice.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PICAN: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PICAN: public PIIODevice {
|
||||
PIIODEVICE(PICAN, "can");
|
||||
|
||||
public:
|
||||
explicit PICAN(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
virtual ~PICAN();
|
||||
@@ -50,7 +50,7 @@ protected:
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
private:
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Config parser
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Config parser
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "piconfig.h"
|
||||
|
||||
#include "pifile.h"
|
||||
#include "piiostring.h"
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
# include "pistring_std.h"
|
||||
|
||||
# include <iostream>
|
||||
#endif
|
||||
/*! \class PIConfig
|
||||
@@ -88,14 +90,14 @@
|
||||
* internal instance of %PIConfig::Entry with "default" value will be returned.
|
||||
* \snippet piconfig.cpp PIConfig::Entry
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
/*! \class PIConfig::Branch
|
||||
* \brief %Branch is a list of entries of configuration file
|
||||
* \details %Branch provides some features to get entries lists.
|
||||
* \snippet piconfig.cpp PIConfig::Branch
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
PIConfig::Entry PIConfig::Branch::_empty;
|
||||
@@ -105,9 +107,11 @@ PIConfig::Entry PIConfig::Entry::_empty;
|
||||
PIConfig::Branch PIConfig::Branch::allLeaves() {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this) {
|
||||
if (i->isLeaf()) b << i;
|
||||
else allLeaves(b, i);
|
||||
piForeach(Entry * i, *this) {
|
||||
if (i->isLeaf())
|
||||
b << i;
|
||||
else
|
||||
allLeaves(b, i);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
@@ -121,27 +125,27 @@ PIConfig::Entry & PIConfig::Branch::getValue(const PIString & vname, const PIStr
|
||||
return _empty;
|
||||
}
|
||||
PIStringList tree = vname.split(delim);
|
||||
PIString name = tree.front();
|
||||
PIString name = tree.front();
|
||||
tree.pop_front();
|
||||
Entry * ce = 0;
|
||||
piForeach (Entry * i, *this)
|
||||
piForeach(Entry * i, *this)
|
||||
if (i->_name == name) {
|
||||
ce = i;
|
||||
break;
|
||||
}
|
||||
if (ce == 0) {
|
||||
_empty._name = vname;
|
||||
_empty._name = vname;
|
||||
_empty._value = def;
|
||||
_empty.delim = delim;
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
piForeach (PIString & i, tree) {
|
||||
piForeach(PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0) {
|
||||
_empty._name = vname;
|
||||
_empty._name = vname;
|
||||
_empty._value = def;
|
||||
_empty.delim = delim;
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
@@ -154,14 +158,12 @@ PIConfig::Entry & PIConfig::Branch::getValue(const PIString & vname, const PIStr
|
||||
PIConfig::Branch PIConfig::Branch::getValues(const PIString & name) {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this) {
|
||||
piForeach(Entry * i, *this) {
|
||||
if (i->isLeaf()) {
|
||||
if (i->_name.find(name) >= 0)
|
||||
b << i;
|
||||
if (i->_name.find(name) >= 0) b << i;
|
||||
} else {
|
||||
piForeach (Entry * j, i->_children)
|
||||
if (j->_name.find(name) >= 0)
|
||||
b << j;
|
||||
piForeach(Entry * j, i->_children)
|
||||
if (j->_name.find(name) >= 0) b << j;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
@@ -171,9 +173,8 @@ PIConfig::Branch PIConfig::Branch::getValues(const PIString & name) {
|
||||
PIConfig::Branch PIConfig::Branch::getLeaves() {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this)
|
||||
if (i->isLeaf())
|
||||
b << i;
|
||||
piForeach(Entry * i, *this)
|
||||
if (i->isLeaf()) b << i;
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -181,9 +182,8 @@ PIConfig::Branch PIConfig::Branch::getLeaves() {
|
||||
PIConfig::Branch PIConfig::Branch::getBranches() {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this)
|
||||
if (!i->isLeaf())
|
||||
b << i;
|
||||
piForeach(Entry * i, *this)
|
||||
if (!i->isLeaf()) b << i;
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ bool PIConfig::Branch::entryExists(const Entry * e, const PIString & name) const
|
||||
if (e->_children.isEmpty()) {
|
||||
return (e->_name == name);
|
||||
}
|
||||
piForeachC (Entry * i, e->_children)
|
||||
piForeachC(Entry * i, e->_children)
|
||||
if (entryExists(i, name)) return true;
|
||||
return false;
|
||||
}
|
||||
@@ -211,13 +211,13 @@ bool PIConfig::Branch::entryExists(const Entry * e, const PIString & name) const
|
||||
|
||||
PIConfig::Entry & PIConfig::Entry::getValue(const PIString & vname, const PIString & def, bool * exist) {
|
||||
PIStringList tree = vname.split(delim);
|
||||
Entry * ce = this;
|
||||
piForeach (PIString & i, tree) {
|
||||
Entry * ce = this;
|
||||
piForeach(PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0) {
|
||||
_empty._name = vname;
|
||||
_empty._name = vname;
|
||||
_empty._value = def;
|
||||
_empty.delim = delim;
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
@@ -230,9 +230,8 @@ PIConfig::Entry & PIConfig::Entry::getValue(const PIString & vname, const PIStri
|
||||
PIConfig::Branch PIConfig::Entry::getValues(const PIString & vname) {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, _children)
|
||||
if (i->_name.find(vname) >= 0)
|
||||
b << i;
|
||||
piForeach(Entry * i, _children)
|
||||
if (i->_name.find(vname) >= 0) b << i;
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -241,7 +240,7 @@ bool PIConfig::Entry::entryExists(const Entry * e, const PIString & name) const
|
||||
if (e->_children.isEmpty()) {
|
||||
return (e->_name == name);
|
||||
}
|
||||
piForeachC (Entry * i, e->_children)
|
||||
piForeachC(Entry * i, e->_children)
|
||||
if (entryExists(i, name)) return true;
|
||||
return false;
|
||||
}
|
||||
@@ -249,19 +248,25 @@ bool PIConfig::Entry::entryExists(const Entry * e, const PIString & name) const
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
void PIConfig::Entry::coutt(std::ostream & s, const PIString & p) const {
|
||||
PIString nl = p + " ";
|
||||
if (!_value.isEmpty()) s << p << _name << " = " << _value << std::endl;
|
||||
else std::cout << p << _name << std::endl;
|
||||
piForeachC (Entry * i, _children) i->coutt(s, nl);
|
||||
PIString nl = p + " ";
|
||||
if (!_value.isEmpty())
|
||||
s << p << _name << " = " << _value << std::endl;
|
||||
else
|
||||
std::cout << p << _name << std::endl;
|
||||
piForeachC(Entry * i, _children)
|
||||
i->coutt(s, nl);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void PIConfig::Entry::piCoutt(PICout s, const PIString & p) const {
|
||||
PIString nl = p + " ";
|
||||
if (!_value.isEmpty()) s << p << _name << " = " << _value << " (" << _type << " " << _comment << ")" << PICoutManipulators::NewLine;
|
||||
else s << p << _name << PICoutManipulators::NewLine;
|
||||
piForeachC (Entry * i, _children) i->piCoutt(s, nl);
|
||||
PIString nl = p + " ";
|
||||
if (!_value.isEmpty())
|
||||
s << p << _name << " = " << _value << " (" << _type << " " << _comment << ")" << PICoutManipulators::NewLine;
|
||||
else
|
||||
s << p << _name << PICoutManipulators::NewLine;
|
||||
piForeachC(Entry * i, _children)
|
||||
i->piCoutt(s, nl);
|
||||
}
|
||||
|
||||
|
||||
@@ -286,9 +291,9 @@ PIConfig::PIConfig(PIIODevice * device, PIIODevice::DeviceMode mode) {
|
||||
PIConfig::PIConfig(const PIString & path, PIStringList dirs) {
|
||||
_init();
|
||||
internal = true;
|
||||
own_dev = true;
|
||||
dev = new PIFile(path, PIIODevice::ReadOnly);
|
||||
incdirs = dirs;
|
||||
own_dev = true;
|
||||
dev = new PIFile(path, PIIODevice::ReadOnly);
|
||||
incdirs = dirs;
|
||||
incdirs << PIFile::fileInfo(path).dir();
|
||||
while (!dev->isOpened()) {
|
||||
if (dirs.isEmpty()) break;
|
||||
@@ -318,9 +323,8 @@ bool PIConfig::open(const PIString & path, PIIODevice::DeviceMode mode) {
|
||||
_destroy();
|
||||
incdirs << PIFile::fileInfo(path).dir();
|
||||
own_dev = true;
|
||||
dev = new PIFile(path, mode);
|
||||
if (!dev->isOpened())
|
||||
dev->open(path, mode);
|
||||
dev = new PIFile(path, mode);
|
||||
if (!dev->isOpened()) dev->open(path, mode);
|
||||
_setupDev();
|
||||
parse();
|
||||
return dev->isOpened();
|
||||
@@ -330,7 +334,7 @@ bool PIConfig::open(const PIString & path, PIIODevice::DeviceMode mode) {
|
||||
bool PIConfig::open(PIString * string, PIIODevice::DeviceMode mode) {
|
||||
_destroy();
|
||||
own_dev = true;
|
||||
dev = new PIIOString(string, mode);
|
||||
dev = new PIIOString(string, mode);
|
||||
_setupDev();
|
||||
parse();
|
||||
return true;
|
||||
@@ -340,11 +344,10 @@ bool PIConfig::open(PIString * string, PIIODevice::DeviceMode mode) {
|
||||
bool PIConfig::open(PIIODevice * device, PIIODevice::DeviceMode mode) {
|
||||
_destroy();
|
||||
own_dev = false;
|
||||
dev = device;
|
||||
dev = device;
|
||||
if (dev) {
|
||||
dev->open(mode);
|
||||
if (dev->isTypeOf<PIFile>())
|
||||
incdirs << PIFile::fileInfo(((PIFile*)dev)->path()).dir();
|
||||
if (dev->isTypeOf<PIFile>()) incdirs << PIFile::fileInfo(((PIFile *)dev)->path()).dir();
|
||||
}
|
||||
_setupDev();
|
||||
parse();
|
||||
@@ -354,9 +357,9 @@ bool PIConfig::open(PIIODevice * device, PIIODevice::DeviceMode mode) {
|
||||
|
||||
|
||||
void PIConfig::_init() {
|
||||
delim = PIStringAscii(".");
|
||||
root.delim = delim;
|
||||
empty.delim = delim;
|
||||
delim = PIStringAscii(".");
|
||||
root.delim = delim;
|
||||
empty.delim = delim;
|
||||
empty._parent = 0;
|
||||
}
|
||||
|
||||
@@ -368,7 +371,7 @@ void PIConfig::_destroy() {
|
||||
}
|
||||
if (own_dev && dev) delete dev;
|
||||
dev = nullptr;
|
||||
piForeach (PIConfig * c, inc_devs)
|
||||
piForeach(PIConfig * c, inc_devs)
|
||||
delete c;
|
||||
inc_devs.clear();
|
||||
}
|
||||
@@ -383,14 +386,22 @@ void PIConfig::_setupDev() {
|
||||
|
||||
void PIConfig::_clearDev() {
|
||||
if (!dev) return;
|
||||
if (PIString(dev->className()) == "PIFile") {((PIFile*)dev)->clear(); return;}
|
||||
if (PIString(dev->className()) == "PIIOString") {((PIIOString*)dev)->clear(); return;}
|
||||
if (PIString(dev->className()) == "PIFile") {
|
||||
((PIFile *)dev)->clear();
|
||||
return;
|
||||
}
|
||||
if (PIString(dev->className()) == "PIIOString") {
|
||||
((PIIOString *)dev)->clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::_flushDev() {
|
||||
if (!dev) return;
|
||||
if (PIString(dev->className()) == "PIFile") {((PIFile*)dev)->flush();}
|
||||
if (PIString(dev->className()) == "PIFile") {
|
||||
((PIFile *)dev)->flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -402,8 +413,14 @@ bool PIConfig::_isEndDev() {
|
||||
|
||||
void PIConfig::_seekToBeginDev() {
|
||||
if (!dev) return;
|
||||
if (PIString(dev->className()) == "PIFile") {((PIFile*)dev)->seekToBegin(); return;}
|
||||
if (PIString(dev->className()) == "PIIOString") {((PIIOString*)dev)->seekToBegin(); return;}
|
||||
if (PIString(dev->className()) == "PIFile") {
|
||||
((PIFile *)dev)->seekToBegin();
|
||||
return;
|
||||
}
|
||||
if (PIString(dev->className()) == "PIIOString") {
|
||||
((PIIOString *)dev)->seekToBegin();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -414,7 +431,7 @@ PIString PIConfig::_readLineDev() {
|
||||
|
||||
|
||||
void PIConfig::_writeDev(const PIString & l) {
|
||||
//piCout << "write \"" << l << "\"";
|
||||
// piCout << "write \"" << l << "\"";
|
||||
if (!stream) return;
|
||||
stream->append(l);
|
||||
}
|
||||
@@ -428,14 +445,14 @@ bool PIConfig::isOpened() const {
|
||||
|
||||
PIConfig::Entry & PIConfig::getValue(const PIString & vname, const PIString & def, bool * exist) {
|
||||
PIStringList tree = vname.split(delim);
|
||||
Entry * ce = &root;
|
||||
piForeach (PIString & i, tree) {
|
||||
Entry * ce = &root;
|
||||
piForeach(PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0) {
|
||||
if (exist != 0) *exist = false;
|
||||
empty._name = vname;
|
||||
empty._name = vname;
|
||||
empty._value = def;
|
||||
empty.delim = delim;
|
||||
empty.delim = delim;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
@@ -447,50 +464,52 @@ PIConfig::Entry & PIConfig::getValue(const PIString & vname, const PIString & de
|
||||
PIConfig::Branch PIConfig::getValues(const PIString & vname) {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, root._children)
|
||||
if (i->_name.find(vname) >= 0)
|
||||
b << i;
|
||||
piForeach(Entry * i, root._children)
|
||||
if (i->_name.find(vname) >= 0) b << i;
|
||||
return b;
|
||||
};
|
||||
|
||||
|
||||
void PIConfig::addEntry(const PIString & name, const PIString & value, const PIString & type, bool write) {
|
||||
if (getValue(name)._parent != 0)
|
||||
return;
|
||||
bool toRoot = false;
|
||||
if (getValue(name)._parent != 0) return;
|
||||
bool toRoot = false;
|
||||
PIStringList tree = name.split(delim);
|
||||
PIString ename = tree.back();
|
||||
PIString ename = tree.back();
|
||||
tree.pop_back();
|
||||
Entry * te, * ce, * entry = &root;
|
||||
Entry *te, *ce, *entry = &root;
|
||||
if (tree.isEmpty()) toRoot = true;
|
||||
piForeach (PIString & i, tree) {
|
||||
piForeach(PIString & i, tree) {
|
||||
te = entry->findChild(i);
|
||||
if (te == 0) {
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_tab = entry->_tab;
|
||||
ce->_line = entry->_line;
|
||||
ce->_name = i;
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_tab = entry->_tab;
|
||||
ce->_line = entry->_line;
|
||||
ce->_name = i;
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
entry = ce;
|
||||
} else entry = te;
|
||||
} else
|
||||
entry = te;
|
||||
}
|
||||
PIConfig::Branch ch = entry->_children;
|
||||
ch.sort(PIConfig::Entry::compare);
|
||||
te = (entry->isLeaf() ? 0 : ch.back());
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_name = ename;
|
||||
te = (entry->isLeaf() ? 0 : ch.back());
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_name = ename;
|
||||
ce->_value = value;
|
||||
ce->_type = type;
|
||||
ce->_type = type;
|
||||
if (te == 0) {
|
||||
ce->_tab = entry->_tab;
|
||||
if (toRoot) ce->_line = other.size_s() - 1;
|
||||
else ce->_line = entry->_line;
|
||||
if (toRoot)
|
||||
ce->_line = other.size_s() - 1;
|
||||
else
|
||||
ce->_line = entry->_line;
|
||||
} else {
|
||||
ce->_tab = te->_tab;
|
||||
if (toRoot) ce->_line = other.size_s() - 1;
|
||||
if (toRoot)
|
||||
ce->_line = other.size_s() - 1;
|
||||
else {
|
||||
ch = entry->_parent->_children;
|
||||
ch.sort(PIConfig::Entry::compare);
|
||||
@@ -500,7 +519,7 @@ void PIConfig::addEntry(const PIString & name, const PIString & value, const PIS
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
other.insert(ce->_line, "");
|
||||
Branch b = allLeaves();
|
||||
Branch b = allLeaves();
|
||||
bool found = false;
|
||||
for (int i = 0; i < b.size_s(); ++i) {
|
||||
if (found) {
|
||||
@@ -510,8 +529,7 @@ void PIConfig::addEntry(const PIString & name, const PIString & value, const PIS
|
||||
if (b[i] == ce) {
|
||||
found = true;
|
||||
if (i > 0)
|
||||
if (b[i - 1]->_line == b[i]->_line)
|
||||
b[i - 1]->_line++;
|
||||
if (b[i - 1]->_line == b[i]->_line) b[i - 1]->_line++;
|
||||
}
|
||||
}
|
||||
if (write) writeAll();
|
||||
@@ -525,18 +543,17 @@ void PIConfig::setValue(const PIString & name, const PIString & value, const PIS
|
||||
return;
|
||||
}
|
||||
e._value = value;
|
||||
e._type = type;
|
||||
e._type = type;
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
int PIConfig::entryIndex(const PIString & name) {
|
||||
PIStringList tree = name.split(delim);
|
||||
Entry * ce = &root;
|
||||
piForeach (PIString & i, tree) {
|
||||
Entry * ce = &root;
|
||||
piForeach(PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0)
|
||||
return -1;
|
||||
if (ce == 0) return -1;
|
||||
}
|
||||
return allLeaves().indexOf(ce);
|
||||
}
|
||||
@@ -600,8 +617,7 @@ void PIConfig::removeEntry(Branch & b, PIConfig::Entry * e) {
|
||||
leaf = false;
|
||||
} else {
|
||||
int cc = e->_children.size_s();
|
||||
piForTimes (cc)
|
||||
removeEntry(b, e->_children.back());
|
||||
piForTimes(cc) removeEntry(b, e->_children.back());
|
||||
}
|
||||
bool found = false;
|
||||
for (int i = 0; i < b.size_s(); ++i) {
|
||||
@@ -620,10 +636,16 @@ void PIConfig::removeEntry(Branch & b, PIConfig::Entry * e) {
|
||||
|
||||
PIString PIConfig::getPrefixFromLine(PIString line, bool * exists) {
|
||||
line.trim();
|
||||
if (line.left(1) == "#") {if (exists) *exists = false; return PIString();}
|
||||
if (line.left(1) == "#") {
|
||||
if (exists) *exists = false;
|
||||
return PIString();
|
||||
}
|
||||
int ci = line.find("#");
|
||||
if (ci >= 0) line.cutRight(line.size() - ci);
|
||||
if (line.find("=") >= 0) {if (exists) *exists = false; return PIString();}
|
||||
if (line.find("=") >= 0) {
|
||||
if (exists) *exists = false;
|
||||
return PIString();
|
||||
}
|
||||
if (line.find("[") >= 0 && line.find("]") >= 0) {
|
||||
if (exists) *exists = true;
|
||||
return line.takeRange('[', ']').trim();
|
||||
@@ -634,51 +656,47 @@ PIString PIConfig::getPrefixFromLine(PIString line, bool * exists) {
|
||||
|
||||
|
||||
void PIConfig::writeAll() {
|
||||
//cout << this << " write < " << size() << endl;
|
||||
// cout << this << " write < " << size() << endl;
|
||||
_clearDev();
|
||||
buildFullNames(&root);
|
||||
Branch b = allLeaves();
|
||||
PIString prefix, tprefix;
|
||||
bool isPrefix;
|
||||
//for (int i = 0; i < b.size_s(); ++i)
|
||||
// for (int i = 0; i < b.size_s(); ++i)
|
||||
// cout << b[i]->_name << " = " << b[i]->_value << endl;
|
||||
int j = 0;
|
||||
for (int i = 0; i < other.size_s(); ++i) {
|
||||
//cout << j << endl;
|
||||
// cout << j << endl;
|
||||
if (j >= 0 && j < b.size_s()) {
|
||||
if (b[j]->_line == i) {
|
||||
b[j]->buildLine();
|
||||
_writeDev((b[j]->_all).cutLeft(prefix.size()) + "\n");
|
||||
//cout << this << " " << b[j]->_all << endl;
|
||||
// cout << this << " " << b[j]->_all << endl;
|
||||
++j;
|
||||
} else {
|
||||
_writeDev(other[i]);
|
||||
tprefix = getPrefixFromLine(other[i], &isPrefix);
|
||||
if (isPrefix) {
|
||||
prefix = tprefix;
|
||||
if (!prefix.isEmpty())
|
||||
prefix += delim;
|
||||
if (!prefix.isEmpty()) prefix += delim;
|
||||
}
|
||||
if (i < other.size_s() - 1)
|
||||
_writeDev('\n');
|
||||
//cout << this << " " << other[i] << endl;
|
||||
if (i < other.size_s() - 1) _writeDev('\n');
|
||||
// cout << this << " " << other[i] << endl;
|
||||
}
|
||||
} else {
|
||||
_writeDev(other[i]);
|
||||
tprefix = getPrefixFromLine(other[i], &isPrefix);
|
||||
if (isPrefix) {
|
||||
prefix = tprefix;
|
||||
if (!prefix.isEmpty())
|
||||
prefix += delim;
|
||||
if (!prefix.isEmpty()) prefix += delim;
|
||||
}
|
||||
if (i < other.size_s() - 1)
|
||||
_writeDev('\n');
|
||||
//cout << this << " " << other[i] << endl;
|
||||
if (i < other.size_s() - 1) _writeDev('\n');
|
||||
// cout << this << " " << other[i] << endl;
|
||||
}
|
||||
}
|
||||
_flushDev();
|
||||
readAll();
|
||||
//cout << this << " write > " << size() << endl;
|
||||
// cout << this << " write > " << size() << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -699,7 +717,7 @@ bool PIConfig::entryExists(const Entry * e, const PIString & name) const {
|
||||
if (e->_children.isEmpty()) {
|
||||
return (e->_name == name);
|
||||
}
|
||||
piForeachC (Entry * i, e->_children)
|
||||
piForeachC(Entry * i, e->_children)
|
||||
if (entryExists(i, name)) return true;
|
||||
return false;
|
||||
}
|
||||
@@ -708,7 +726,7 @@ bool PIConfig::entryExists(const Entry * e, const PIString & name) const {
|
||||
void PIConfig::updateIncludes() {
|
||||
if (internal) return;
|
||||
all_includes.clear();
|
||||
piForeach (PIConfig * c, includes)
|
||||
piForeach(PIConfig * c, includes)
|
||||
all_includes << c->allLeaves();
|
||||
}
|
||||
|
||||
@@ -719,15 +737,15 @@ PIString PIConfig::parseLine(PIString v) {
|
||||
i = v.find("${");
|
||||
if (i < 0) break;
|
||||
PIString w = v.mid(i + 1).takeRange('{', '}'), r;
|
||||
l = w.length() + 3;
|
||||
w = parseLine(w);
|
||||
l = w.length() + 3;
|
||||
w = parseLine(w);
|
||||
w.trim();
|
||||
bool ex = false;
|
||||
bool ex = false;
|
||||
PIConfig::Entry & me = getValue(w, "", &ex);
|
||||
if (ex) {
|
||||
r = me._value;
|
||||
} else {
|
||||
piForeachC (PIConfig::Entry * e, all_includes)
|
||||
piForeachC(PIConfig::Entry * e, all_includes)
|
||||
if (e->_full_name == w) {
|
||||
r = e->_value;
|
||||
break;
|
||||
@@ -740,13 +758,13 @@ PIString PIConfig::parseLine(PIString v) {
|
||||
|
||||
|
||||
void PIConfig::parse() {
|
||||
//piCout << "[PIConfig] charset" << PIFile::defaultCharset();
|
||||
// piCout << "[PIConfig] charset" << PIFile::defaultCharset();
|
||||
PIString src, str, tab, comm, all, name, type, prefix, tprefix;
|
||||
PIStringList tree;
|
||||
Entry * entry = 0, * te = 0, * ce = 0;
|
||||
Entry *entry = 0, *te = 0, *ce = 0;
|
||||
int ind, sind;
|
||||
bool isNew = false, isPrefix = false, wasMultiline = false, isMultiline = false;
|
||||
piForeach (PIConfig * c, inc_devs)
|
||||
piForeach(PIConfig * c, inc_devs)
|
||||
delete c;
|
||||
inc_devs.clear();
|
||||
includes.clear();
|
||||
@@ -757,16 +775,15 @@ void PIConfig::parse() {
|
||||
while (!_isEndDev()) {
|
||||
other.push_back(PIString());
|
||||
src = str = parseLine(_readLineDev());
|
||||
tprefix = getPrefixFromLine(src, &isPrefix);
|
||||
tprefix = getPrefixFromLine(src, &isPrefix);
|
||||
if (isPrefix) {
|
||||
prefix = tprefix;
|
||||
if (!prefix.isEmpty())
|
||||
prefix += delim;
|
||||
if (!prefix.isEmpty()) prefix += delim;
|
||||
}
|
||||
//piCout << "line \"" << str << "\"";
|
||||
// piCout << "line \"" << str << "\"";
|
||||
tab = str.left(str.find(str.trimmed().left(1)));
|
||||
str.trim();
|
||||
all = str;
|
||||
all = str;
|
||||
|
||||
sind = str.find('#');
|
||||
if (sind > 0) {
|
||||
@@ -774,7 +791,8 @@ void PIConfig::parse() {
|
||||
if (!comm.isEmpty()) {
|
||||
type = comm[0];
|
||||
comm.cutLeft(1).trim();
|
||||
} else type = "s";
|
||||
} else
|
||||
type = "s";
|
||||
str = str.left(sind).trim();
|
||||
} else {
|
||||
type = "s";
|
||||
@@ -798,14 +816,14 @@ void PIConfig::parse() {
|
||||
ce = 0;
|
||||
wasMultiline = isMultiline;
|
||||
|
||||
//piCout << "[PIConfig] str" << str.size() << str << str.toUTF8();
|
||||
ind = str.find('=');
|
||||
// piCout << "[PIConfig] str" << str.size() << str << str.toUTF8();
|
||||
ind = str.find('=');
|
||||
if ((ind > 0) && (str[0] != '#')) {
|
||||
tree = (prefix + str.left(ind).trimmed()).split(delim);
|
||||
if (tree.front() == "include") {
|
||||
name = str.mid(ind + 1).trimmed();
|
||||
name = str.mid(ind + 1).trimmed();
|
||||
PIConfig * iconf = new PIConfig(name, incdirs);
|
||||
//piCout << "include" << name << iconf->dev;
|
||||
// piCout << "include" << name << iconf->dev;
|
||||
if (!iconf->dev) {
|
||||
delete iconf;
|
||||
} else {
|
||||
@@ -818,41 +836,43 @@ void PIConfig::parse() {
|
||||
name = tree.back();
|
||||
tree.pop_back();
|
||||
entry = &root;
|
||||
piForeachC (PIString & i, tree) {
|
||||
piForeachC(PIString & i, tree) {
|
||||
te = entry->findChild(i);
|
||||
if (te == 0) {
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_tab = tab;
|
||||
ce->_line = lines;
|
||||
ce->_name = i;
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_tab = tab;
|
||||
ce->_line = lines;
|
||||
ce->_name = i;
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
entry = ce;
|
||||
} else entry = te;
|
||||
} else
|
||||
entry = te;
|
||||
}
|
||||
isNew = false;
|
||||
ce = entry->findChild(name);
|
||||
ce = entry->findChild(name);
|
||||
if (ce == 0) {
|
||||
ce = new Entry();
|
||||
ce = new Entry();
|
||||
isNew = true;
|
||||
}
|
||||
ce->delim = delim;
|
||||
ce->_tab = tab;
|
||||
ce->_name = name;
|
||||
ce->_value = str.mid(ind + 1).trimmed();
|
||||
ce->_type = type;
|
||||
ce->delim = delim;
|
||||
ce->_tab = tab;
|
||||
ce->_name = name;
|
||||
ce->_value = str.mid(ind + 1).trimmed();
|
||||
ce->_type = type;
|
||||
ce->_comment = comm;
|
||||
//piCout << "[PIConfig] comm" << comm.size() << comm << comm.toUTF8();
|
||||
//piCout << "[PIConfig] type" << type.size() << type << type.toUTF8();
|
||||
ce->_line = lines;
|
||||
ce->_all = all;
|
||||
// piCout << "[PIConfig] comm" << comm.size() << comm << comm.toUTF8();
|
||||
// piCout << "[PIConfig] type" << type.size() << type << type.toUTF8();
|
||||
ce->_line = lines;
|
||||
ce->_all = all;
|
||||
if (isNew) {
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
}
|
||||
}
|
||||
} else other.back() = src;
|
||||
} else
|
||||
other.back() = src;
|
||||
lines++;
|
||||
}
|
||||
setEntryDelim(&root, delim);
|
||||
@@ -861,13 +881,13 @@ void PIConfig::parse() {
|
||||
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
std::ostream &operator <<(std::ostream & s, const PIConfig::Entry & v) {
|
||||
std::ostream & operator<<(std::ostream & s, const PIConfig::Entry & v) {
|
||||
s << v.value();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &operator <<(std::ostream & s, const PIConfig::Branch & v) {
|
||||
std::ostream & operator<<(std::ostream & s, const PIConfig::Branch & v) {
|
||||
v.coutt(s, "");
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Разбор и запись конфигурационных файлов
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Configuration parser and writer
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Configuration parser and writer
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICONFIG_H
|
||||
|
||||
@@ -1,46 +1,47 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Directory
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Directory
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "piincludes_p.h"
|
||||
#include "pidir.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
|
||||
|
||||
const PIChar PIDir::separator = '/';
|
||||
#ifdef QNX
|
||||
# define _stat_struct_ struct stat
|
||||
# define _stat_call_ stat
|
||||
# define _stat_link_ lstat
|
||||
# define _stat_struct_ struct stat
|
||||
# define _stat_call_ stat
|
||||
# define _stat_link_ lstat
|
||||
#else
|
||||
# define _stat_struct_ struct stat64
|
||||
# define _stat_call_ stat64
|
||||
# define _stat_link_ lstat64
|
||||
# define _stat_struct_ struct stat64
|
||||
# define _stat_call_ stat64
|
||||
# define _stat_link_ lstat64
|
||||
#endif
|
||||
#ifndef WINDOWS
|
||||
# ifdef ANDROID
|
||||
# include <dirent.h>
|
||||
# include <dirent.h>
|
||||
# else
|
||||
# ifdef FREERTOS
|
||||
# ifdef FREERTOS
|
||||
extern "C" {
|
||||
# include <sys/dirent.h>
|
||||
# include <sys/dirent.h>
|
||||
}
|
||||
# else
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# else
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# endif
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
@@ -70,7 +71,7 @@ PIDir::PIDir(const PIFile & file) {
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::operator ==(const PIDir & d) const {
|
||||
bool PIDir::operator==(const PIDir & d) const {
|
||||
return d.absolutePath() == absolutePath();
|
||||
}
|
||||
|
||||
@@ -94,7 +95,7 @@ PIString PIDir::path() const {
|
||||
return path_.mid(1);
|
||||
} else
|
||||
#endif
|
||||
return path_;
|
||||
return path_;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +109,7 @@ PIString PIDir::absolutePath() const {
|
||||
return path_.mid(1);
|
||||
} else
|
||||
#endif
|
||||
return path_;
|
||||
return path_;
|
||||
}
|
||||
return PIDir(PIDir::current().path() + separator + path_).path();
|
||||
}
|
||||
@@ -131,7 +132,7 @@ PIDir & PIDir::cleanPath() {
|
||||
}
|
||||
PIString sep = PIString(separator);
|
||||
path_.replaceAll(sep + sep, sep);
|
||||
bool is_abs = isAbsolute();
|
||||
bool is_abs = isAbsolute();
|
||||
PIStringList l = PIString(p).split(separator);
|
||||
l.removeAll(".");
|
||||
l.removeAll("");
|
||||
@@ -150,8 +151,7 @@ PIDir & PIDir::cleanPath() {
|
||||
break;
|
||||
}
|
||||
path_ = l.join(separator);
|
||||
if (is_abs)
|
||||
path_.prepend(separator);
|
||||
if (is_abs) path_.prepend(separator);
|
||||
if (path_.isEmpty()) path_ = ".";
|
||||
return *this;
|
||||
}
|
||||
@@ -160,7 +160,7 @@ PIDir & PIDir::cleanPath() {
|
||||
PIString PIDir::relative(const PIString & path) const {
|
||||
PIDir td(path);
|
||||
PIStringList dl(absolutePath().split(separator)), pl(td.absolutePath().split(separator)), rl;
|
||||
//piCout << pl << "rel to" << dl;
|
||||
// piCout << pl << "rel to" << dl;
|
||||
while (!dl.isEmpty() && !pl.isEmpty()) {
|
||||
if (dl.front() != pl.front()) break;
|
||||
dl.pop_front();
|
||||
@@ -179,8 +179,7 @@ PIDir & PIDir::setDir(const PIString & path) {
|
||||
#ifdef WINDOWS
|
||||
path_.replaceAll("\\", separator);
|
||||
if (path_.length() > 2)
|
||||
if (path_.mid(1, 2).contains(":"))
|
||||
path_.prepend(separator);
|
||||
if (path_.mid(1, 2).contains(":")) path_.prepend(separator);
|
||||
#endif
|
||||
cleanPath();
|
||||
return *this;
|
||||
@@ -197,56 +196,54 @@ PIDir & PIDir::cd(const PIString & path) {
|
||||
|
||||
bool PIDir::make(bool withParents) {
|
||||
PIDir d = cleanedPath();
|
||||
//PIString tp;
|
||||
// PIString tp;
|
||||
#ifndef WINDOWS
|
||||
bool is_abs = isAbsolute();
|
||||
#endif
|
||||
if (withParents) {
|
||||
PIStringList l = d.path().split(separator);
|
||||
//piCout << l;
|
||||
// piCout << l;
|
||||
l.removeAll("");
|
||||
//piCout << l;
|
||||
// piCout << l;
|
||||
PIString cdp;
|
||||
piForeachC (PIString & i, l) {
|
||||
piForeachC(PIString & i, l) {
|
||||
if (!cdp.isEmpty()
|
||||
#ifndef WINDOWS
|
||||
|| is_abs
|
||||
|| is_abs
|
||||
#endif
|
||||
)
|
||||
)
|
||||
cdp += separator;
|
||||
cdp += i;
|
||||
//piCout << "dir" << cdp;
|
||||
// piCout << "dir" << cdp;
|
||||
if (!isExists(cdp))
|
||||
if (!makeDir(cdp))
|
||||
return false;
|
||||
if (!makeDir(cdp)) return false;
|
||||
}
|
||||
/*for (int i = l.size_s() - 1; i >= 0; --i) {
|
||||
if (i > 1) tp = PIStringList(l).remove(i, l.size_s() - i).join(separator);
|
||||
else {
|
||||
tp = separator;
|
||||
if (!is_abs) tp.push_front('.');
|
||||
}
|
||||
piCout << "check" << tp;
|
||||
if (isExists(tp)) {
|
||||
for (int j = i + 1; j <= l.size_s(); ++j) {
|
||||
tp = PIStringList(l).remove(j, l.size_s() - j).join(separator);
|
||||
piCout << "make" << tp;
|
||||
if (makeDir(tp)) continue;
|
||||
else return false;
|
||||
}
|
||||
break;
|
||||
};
|
||||
if (i > 1) tp = PIStringList(l).remove(i, l.size_s() - i).join(separator);
|
||||
else {
|
||||
tp = separator;
|
||||
if (!is_abs) tp.push_front('.');
|
||||
}
|
||||
piCout << "check" << tp;
|
||||
if (isExists(tp)) {
|
||||
for (int j = i + 1; j <= l.size_s(); ++j) {
|
||||
tp = PIStringList(l).remove(j, l.size_s() - j).join(separator);
|
||||
piCout << "make" << tp;
|
||||
if (makeDir(tp)) continue;
|
||||
else return false;
|
||||
}
|
||||
break;
|
||||
};
|
||||
}*/
|
||||
return true;
|
||||
} else
|
||||
if (makeDir(d.path())) return true;
|
||||
} else if (makeDir(d.path()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::rename(const PIString & new_name) {
|
||||
if (!PIDir::rename(path(), new_name))
|
||||
return false;
|
||||
if (!PIDir::rename(path(), new_name)) return false;
|
||||
setDir(new_name);
|
||||
return true;
|
||||
}
|
||||
@@ -278,8 +275,10 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
if (!isExists()) return l;
|
||||
PIString dp = absolutePath();
|
||||
PIString p(dp);
|
||||
if (dp == ".") dp.clear();
|
||||
else if (!dp.endsWith(separator)) dp += separator;
|
||||
if (dp == ".")
|
||||
dp.clear();
|
||||
else if (!dp.endsWith(separator))
|
||||
dp += separator;
|
||||
// piCout << "start entries from" << p;
|
||||
#ifdef WINDOWS
|
||||
if (dp == separator) {
|
||||
@@ -290,7 +289,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
for (DWORD i = 0; i < ll; ++i) {
|
||||
if (letters[i] == '\0') {
|
||||
clet.resize(2);
|
||||
fi.path = clet;
|
||||
fi.path = clet;
|
||||
fi.flags = PIFile::FileInfo::Dir;
|
||||
l << fi;
|
||||
clet.clear();
|
||||
@@ -298,7 +297,8 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
clet += PIChar(letters[i]);
|
||||
}
|
||||
} else {
|
||||
WIN32_FIND_DATAA fd; memset(&fd, 0, sizeof(fd));
|
||||
WIN32_FIND_DATAA fd;
|
||||
memset(&fd, 0, sizeof(fd));
|
||||
p += "\\*";
|
||||
void * hf = FindFirstFileA((LPCSTR)(p.data()), &fd);
|
||||
if (!hf) return l;
|
||||
@@ -313,7 +313,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
l.sort(sort_compare);
|
||||
if (!hdd) {
|
||||
PIFile::FileInfo fi;
|
||||
fi.path = "..";
|
||||
fi.path = "..";
|
||||
fi.flags = PIFile::FileInfo::Dir | PIFile::FileInfo::DotDot;
|
||||
l.push_front(fi);
|
||||
}
|
||||
@@ -322,8 +322,8 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
#else
|
||||
# if defined(QNX) || defined(FREERTOS)
|
||||
struct dirent * de = 0;
|
||||
DIR * dir = 0;
|
||||
dir = opendir(p.data());
|
||||
DIR * dir = 0;
|
||||
dir = opendir(p.data());
|
||||
if (dir) {
|
||||
for (;;) {
|
||||
de = readdir(dir);
|
||||
@@ -334,12 +334,14 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
}
|
||||
# else
|
||||
dirent ** list;
|
||||
int cnt = scandir(p.data(), &list, 0,
|
||||
# if defined(MAC_OS) || defined(ANDROID) || defined(BLACKBERRY)
|
||||
alphasort);
|
||||
# else
|
||||
versionsort);
|
||||
# endif
|
||||
int cnt = scandir(p.data(),
|
||||
&list,
|
||||
0,
|
||||
# if defined(MAC_OS) || defined(ANDROID) || defined(BLACKBERRY)
|
||||
alphasort);
|
||||
# else
|
||||
versionsort);
|
||||
# endif
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
l << PIFile::fileInfo(dp + PIString(list[i]->d_name));
|
||||
free(list[i]);
|
||||
@@ -347,7 +349,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
||||
free(list);
|
||||
# endif
|
||||
#endif
|
||||
// piCout << "end entries from" << p;
|
||||
// piCout << "end entries from" << p;
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -370,16 +372,17 @@ PIVector<PIFile::FileInfo> PIDir::allEntries() {
|
||||
PIStringList cdirs, ndirs;
|
||||
cdirs << path();
|
||||
while (!cdirs.isEmpty()) {
|
||||
piForeachC (PIString & d, cdirs) {
|
||||
scan_ = d;
|
||||
piForeachC(PIString & d, cdirs) {
|
||||
scan_ = d;
|
||||
PIVector<PIFile::FileInfo> el = PIDir(d).entries();
|
||||
piForeachC (PIFile::FileInfo & de, el) {
|
||||
piForeachC(PIFile::FileInfo & de, el) {
|
||||
if (de.name() == "." || de.name() == "..") continue;
|
||||
if (de.isSymbolicLink()) continue; /// TODO: resolve symlinks
|
||||
if (de.isDir()) {
|
||||
dirs << de;
|
||||
ndirs << de.path;
|
||||
} else ret << de;
|
||||
} else
|
||||
ret << de;
|
||||
}
|
||||
}
|
||||
cdirs = ndirs;
|
||||
@@ -391,7 +394,6 @@ PIVector<PIFile::FileInfo> PIDir::allEntries() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PIDir::isExists(const PIString & path) {
|
||||
#ifdef WINDOWS
|
||||
DWORD ret = GetFileAttributes((LPCTSTR)(path.data()));
|
||||
@@ -434,20 +436,20 @@ PIDir PIDir::home() {
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
memset(rc, 0, 1024);
|
||||
if (ExpandEnvironmentStrings((LPCTSTR)"%HOMEPATH%", (LPTSTR)rc, 1024) == 0) {
|
||||
if (ExpandEnvironmentStrings((LPCTSTR) "%HOMEPATH%", (LPTSTR)rc, 1024) == 0) {
|
||||
delete[] rc;
|
||||
return PIDir();
|
||||
}
|
||||
PIString hp(rc);
|
||||
memset(rc, 0, 1024);
|
||||
if (ExpandEnvironmentStrings((LPCTSTR)"%HOMEDRIVE%", (LPTSTR)rc, 1024) == 0) {
|
||||
if (ExpandEnvironmentStrings((LPCTSTR) "%HOMEDRIVE%", (LPTSTR)rc, 1024) == 0) {
|
||||
delete[] rc;
|
||||
return PIDir();
|
||||
}
|
||||
PIString hd(rc);
|
||||
hp.replaceAll("\\", PIDir::separator);
|
||||
delete[] rc;
|
||||
//s.prepend(separator);
|
||||
// s.prepend(separator);
|
||||
return PIDir(hd + hp);
|
||||
#else
|
||||
# ifndef ESP_PLATFORM
|
||||
@@ -485,7 +487,7 @@ PIDir PIDir::temporary() {
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIFile::FileInfo> PIDir::allEntries(const PIString &path) {
|
||||
PIVector<PIFile::FileInfo> PIDir::allEntries(const PIString & path) {
|
||||
return PIDir(path).allEntries();
|
||||
}
|
||||
|
||||
@@ -535,5 +537,3 @@ bool PIDir::renameDir(const PIString & path, const PIString & new_name) {
|
||||
printf("[PIDir] renameDir(\"%s\", \"%s\") error: %s\n", path.data(), new_name.data(), errorString().data());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Локальная директория
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Directory
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Directory
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIDIR_H
|
||||
@@ -33,80 +33,82 @@
|
||||
//! \~\brief
|
||||
//! \~english Local directory.
|
||||
//! \~russian Локальная директория.
|
||||
class PIP_EXPORT PIDir
|
||||
{
|
||||
class PIP_EXPORT PIDir {
|
||||
public:
|
||||
|
||||
//! \~english Constructs directory with path "dir"
|
||||
//! \~russian Создает директорию с путём "dir"
|
||||
PIDir(const PIString & dir = PIString());
|
||||
|
||||
|
||||
//! \~english Constructs directory with "file" directory path
|
||||
//! \~russian Создает директорию с путём директории файла "file"
|
||||
PIDir(const PIFile & file);
|
||||
|
||||
|
||||
|
||||
|
||||
//! \~english Returns if this directory exists
|
||||
//! \~russian Возвращает существует ли эта директория
|
||||
bool isExists() const {return PIDir::isExists(path());}
|
||||
|
||||
bool isExists() const { return PIDir::isExists(path()); }
|
||||
|
||||
//! \~english Returns if path of this directory is absolute
|
||||
//! \~russian Возвращает абсолютный ли путь у директории
|
||||
bool isAbsolute() const;
|
||||
|
||||
|
||||
//! \~english Returns if path of this directory is relative
|
||||
//! \~russian Возвращает относительный ли путь у директории
|
||||
bool isRelative() const {return !isAbsolute();}
|
||||
bool isRelative() const { return !isAbsolute(); }
|
||||
|
||||
//! \~english Returns path of current reading directory. This path valid only while \a allEntries() functions
|
||||
//! \~russian Возвращает путь текущей директории чтения. Этот путь действителен только во время выполнения метода \a allEntries()
|
||||
const PIString & scanDir() const {return scan_;}
|
||||
|
||||
|
||||
const PIString & scanDir() const { return scan_; }
|
||||
|
||||
|
||||
//! \~english Returns path of this directory
|
||||
//! \~russian Возвращает путь директории
|
||||
PIString path() const;
|
||||
|
||||
|
||||
//! \~english Returns absolute path of this directory
|
||||
//! \~russian Возвращает абсолютный путь директории
|
||||
PIString absolutePath() const;
|
||||
|
||||
|
||||
//! \~english Simplify path of this directory
|
||||
//! \~russian Упрощает путь директории
|
||||
PIDir & cleanPath();
|
||||
|
||||
|
||||
//! \~english Returns %PIDir with simplified path of this directory
|
||||
//! \~russian Возвращает %PIDir с упрощённым путём директории
|
||||
PIDir cleanedPath() const {PIDir d(path()); d.cleanPath(); return d;}
|
||||
|
||||
PIDir cleanedPath() const {
|
||||
PIDir d(path());
|
||||
d.cleanPath();
|
||||
return d;
|
||||
}
|
||||
|
||||
//! \~english Returns relative to this directory path "path"
|
||||
//! \~russian Возвращает путь "path" относительно этой директории
|
||||
PIString relative(const PIString & path) const;
|
||||
|
||||
|
||||
//! \~english Set this directory path to simplified "path"
|
||||
//! \~russian Устанавливает путь директории упрощённым "path"
|
||||
PIDir & setDir(const PIString & path);
|
||||
|
||||
|
||||
//! \~english Set this directory path as current for application
|
||||
//! \~russian Устанавливает путь директории текущим путём приложения
|
||||
bool setCurrent() {return PIDir::setCurrent(path());}
|
||||
|
||||
|
||||
bool setCurrent() { return PIDir::setCurrent(path()); }
|
||||
|
||||
|
||||
//! \~english Returns this directory content
|
||||
//! \~russian Возвращает содержимое этой директории
|
||||
PIVector<PIFile::FileInfo> entries();
|
||||
|
||||
|
||||
//! \~english Returns this directory content recursively
|
||||
//! \~russian Возвращает содержимое этой директории рекурсивно
|
||||
PIVector<PIFile::FileInfo> allEntries();
|
||||
|
||||
|
||||
//! \~english Make this directory, recursively if "withParents"
|
||||
//! \~russian Создаёт эту директорию, рекурсивно если "withParents"
|
||||
bool make(bool withParents = true);
|
||||
|
||||
//! \~english Remove this directory
|
||||
//! \~russian Удаляет эту директорию
|
||||
bool remove() {return PIDir::remove(path());}
|
||||
bool remove() { return PIDir::remove(path()); }
|
||||
|
||||
//! \~english Rename this directory
|
||||
//! \~russian Переименовывает эту директорию
|
||||
@@ -118,18 +120,18 @@ public:
|
||||
|
||||
//! \~english Change this directory to parent
|
||||
//! \~russian Изменяет директорию на родительскую
|
||||
PIDir & up() {return cd("..");}
|
||||
|
||||
//! \~english Compare operator
|
||||
//! \~russian Оператор сравнения
|
||||
bool operator ==(const PIDir & d) const;
|
||||
PIDir & up() { return cd(".."); }
|
||||
|
||||
//! \~english Compare operator
|
||||
//! \~russian Оператор сравнения
|
||||
bool operator !=(const PIDir & d) const {return !((*this) == d);}
|
||||
|
||||
bool operator==(const PIDir & d) const;
|
||||
|
||||
//! \~english Compare operator
|
||||
//! \~russian Оператор сравнения
|
||||
bool operator!=(const PIDir & d) const { return !((*this) == d); }
|
||||
|
||||
static const PIChar separator;
|
||||
|
||||
|
||||
|
||||
//! \~english Returns current directory for application
|
||||
//! \~russian Возвращает текущую директорию приложения
|
||||
@@ -157,11 +159,11 @@ public:
|
||||
|
||||
//! \~english Remove directory "path"
|
||||
//! \~russian Удаляет директорию "path"
|
||||
static bool remove(const PIString & path) {return removeDir(path);}
|
||||
static bool remove(const PIString & path) { return removeDir(path); }
|
||||
|
||||
//! \~english Rename directory "path"
|
||||
//! \~russian Переименовывает директорию "path"
|
||||
static bool rename(const PIString & path, const PIString & new_name) {return PIDir::renameDir(path, new_name);}
|
||||
static bool rename(const PIString & path, const PIString & new_name) { return PIDir::renameDir(path, new_name); }
|
||||
|
||||
//! \~english Set path "path" as current for application
|
||||
//! \~russian Устанавливает путь "path" текущим путём приложения
|
||||
@@ -169,27 +171,39 @@ public:
|
||||
|
||||
//! \~english Set directory "dir" path as current for application
|
||||
//! \~russian Устанавливает путь директории "dir" текущим путём приложения
|
||||
static bool setCurrent(const PIDir & dir) {return setCurrent(dir.path());}
|
||||
|
||||
static bool setCurrent(const PIDir & dir) { return setCurrent(dir.path()); }
|
||||
|
||||
private:
|
||||
static bool makeDir(const PIString & path);
|
||||
static bool removeDir(const PIString & path);
|
||||
static bool renameDir(const PIString & path, const PIString & new_name);
|
||||
|
||||
|
||||
PIString path_, scan_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline bool operator <(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {return (v0.path < v1.path);}
|
||||
inline bool operator >(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {return (v0.path > v1.path);}
|
||||
inline bool operator ==(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {return (v0.path == v1.path);}
|
||||
inline bool operator !=(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {return (v0.path != v1.path);}
|
||||
inline bool operator<(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
|
||||
return (v0.path < v1.path);
|
||||
}
|
||||
inline bool operator>(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
|
||||
return (v0.path > v1.path);
|
||||
}
|
||||
inline bool operator==(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
|
||||
return (v0.path == v1.path);
|
||||
}
|
||||
inline bool operator!=(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
|
||||
return (v0.path != v1.path);
|
||||
}
|
||||
|
||||
//! \relatesalso PICout
|
||||
//! \~english Output operator to \a PICout
|
||||
//! \~russian Оператор вывода в \a PICout
|
||||
inline PICout operator <<(PICout s, const PIDir & v) {s.saveAndSetControls(0); s << "PIDir(\"" << v.path() << "\")"; s.restoreControls(); return s;}
|
||||
inline PICout operator<<(PICout s, const PIDir & v) {
|
||||
s.saveAndSetControls(0);
|
||||
s << "PIDir(\"" << v.path() << "\")";
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIDIR_H
|
||||
|
||||
@@ -1,46 +1,48 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP/TCP Broadcast/Multicast
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP/TCP Broadcast/Multicast
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "piincludes_p.h"
|
||||
#include "piethernet.h"
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "piconstchars.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pisysteminfo.h"
|
||||
// clang-format off
|
||||
#ifdef QNX
|
||||
# include <arpa/inet.h>
|
||||
# include <fcntl.h>
|
||||
# include <hw/nicinfo.h>
|
||||
# include <ifaddrs.h>
|
||||
# include <net/if.h>
|
||||
# include <net/if_dl.h>
|
||||
# include <hw/nicinfo.h>
|
||||
# include <netdb.h>
|
||||
# include <netinet/in.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <ifaddrs.h>
|
||||
# include <fcntl.h>
|
||||
# ifdef BLACKBERRY
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/in.h>
|
||||
# else
|
||||
# include <sys/dcmd_io-net.h>
|
||||
# include <sys/dcmd_io-net.h>
|
||||
# endif
|
||||
# define ip_mreqn ip_mreq
|
||||
# define ip_mreqn ip_mreq
|
||||
# define imr_address imr_interface
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
@@ -67,7 +69,9 @@
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
#include "piwaitevent_p.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
@@ -81,21 +85,21 @@
|
||||
* UDP and TCP. This class allow you send and receive packets to/from
|
||||
* another computer through network. Also it supports broadcast and
|
||||
* multicast extensions.
|
||||
*
|
||||
*
|
||||
* \section PIEthernet_sec1 IPv4
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* \section PIEthernet_sec2 UDP
|
||||
* User Datagram Protocol
|
||||
*
|
||||
*
|
||||
* \section PIEthernet_sec3 TCP
|
||||
* Transmission Control Protocol
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
#ifndef WINDOWS
|
||||
PIString getSockAddr(sockaddr * s) {
|
||||
return s == 0 ? PIString() : PIStringAscii(inet_ntoa(((sockaddr_in*)s)->sin_addr));
|
||||
return s == 0 ? PIString() : PIStringAscii(inet_ntoa(((sockaddr_in *)s)->sin_addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -145,7 +149,8 @@ void PIEthernet::Address::setPort(ushort _port) {
|
||||
|
||||
|
||||
void PIEthernet::Address::set(const PIString & ip_port) {
|
||||
PIString _ip; int p(0);
|
||||
PIString _ip;
|
||||
int p(0);
|
||||
splitIPPort(ip_port, &_ip, &p);
|
||||
port_ = p;
|
||||
initIP(_ip);
|
||||
@@ -159,13 +164,13 @@ void PIEthernet::Address::set(const PIString & _ip, ushort _port) {
|
||||
|
||||
|
||||
void PIEthernet::Address::set(uint _ip, ushort _port) {
|
||||
ip_ = _ip;
|
||||
ip_ = _ip;
|
||||
port_ = _port;
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::Address::clear() {
|
||||
ip_ = 0;
|
||||
ip_ = 0;
|
||||
port_ = 0;
|
||||
}
|
||||
|
||||
@@ -176,7 +181,8 @@ bool PIEthernet::Address::isNull() const {
|
||||
|
||||
|
||||
PIEthernet::Address PIEthernet::Address::resolve(const PIString & host_port) {
|
||||
PIString host; int port(0);
|
||||
PIString host;
|
||||
int port(0);
|
||||
splitIPPort(host_port, &host, &port);
|
||||
return resolve(host, port);
|
||||
}
|
||||
@@ -185,16 +191,14 @@ PIEthernet::Address PIEthernet::Address::resolve(const PIString & host_port) {
|
||||
PIEthernet::Address PIEthernet::Address::resolve(const PIString & host, ushort port) {
|
||||
Address ret(0, port);
|
||||
hostent * he = gethostbyname(host.dataAscii());
|
||||
if (!he)
|
||||
return ret;
|
||||
if (he->h_addr_list[0])
|
||||
ret.setIP(*((uint*)(he->h_addr_list[0])));
|
||||
if (!he) return ret;
|
||||
if (he->h_addr_list[0]) ret.setIP(*((uint *)(he->h_addr_list[0])));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::Address::splitIPPort(const PIString & ipp, PIString * _ip, int * _port) {
|
||||
//piCout << "parse" << ipp;
|
||||
// piCout << "parse" << ipp;
|
||||
int sp = ipp.findLast(":");
|
||||
if (_ip != 0) *_ip = (sp >= 0 ? ipp.left(sp) : ipp);
|
||||
if (_port != 0 && sp >= 0) *_port = ipp.right(ipp.length() - ipp.find(":") - 1).toInt();
|
||||
@@ -224,7 +228,8 @@ PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) {
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const PIFlags<PIEthernet::Parameters> params_): PIIODevice(ip_port, ReadWrite) {
|
||||
PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const PIFlags<PIEthernet::Parameters> params_)
|
||||
: PIIODevice(ip_port, ReadWrite) {
|
||||
construct();
|
||||
addr_r.set(ip_port);
|
||||
setType(type_);
|
||||
@@ -236,7 +241,7 @@ PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const P
|
||||
PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
||||
construct();
|
||||
addr_s.set(ip_port);
|
||||
sock = sock_;
|
||||
sock = sock_;
|
||||
opened_ = connected_ = true;
|
||||
init();
|
||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop);
|
||||
@@ -244,21 +249,21 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
||||
setPath(ip_port);
|
||||
ethNonblocking(sock);
|
||||
PRIVATE->event.create();
|
||||
//piCoutObj << "new tcp client" << sock_;
|
||||
// piCoutObj << "new tcp client" << sock_;
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::~PIEthernet() {
|
||||
//piCout << "~PIEthernet";
|
||||
// piCout << "~PIEthernet";
|
||||
stopAndWait();
|
||||
close();
|
||||
PRIVATE->event.destroy();
|
||||
//piCout << "~PIEthernet done";
|
||||
// piCout << "~PIEthernet done";
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::construct() {
|
||||
//piCout << " PIEthernet" << uint(this);
|
||||
// piCout << " PIEthernet" << uint(this);
|
||||
setOption(BlockingWrite);
|
||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||
sock = sock_s = -1;
|
||||
@@ -273,17 +278,16 @@ void PIEthernet::construct() {
|
||||
#else
|
||||
setThreadedReadBufferSize(65536);
|
||||
#endif
|
||||
//setPriority(piHigh);
|
||||
// setPriority(piHigh);
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::init() {
|
||||
if (isOpened()) return true;
|
||||
if (sock != -1) return true;
|
||||
//piCout << "init " << type();
|
||||
// piCout << "init " << type();
|
||||
PRIVATE->event.destroy();
|
||||
if (sock_s == sock)
|
||||
sock_s = -1;
|
||||
if (sock_s == sock) sock_s = -1;
|
||||
closeSocket(sock);
|
||||
closeSocket(sock_s);
|
||||
int st = 0, pr = 0;
|
||||
@@ -309,7 +313,7 @@ bool PIEthernet::init() {
|
||||
if (params[PIEthernet::Broadcast]) ethSetsockoptBool(sock, SOL_SOCKET, SO_BROADCAST);
|
||||
applyTimeouts();
|
||||
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
|
||||
//piCoutObj << "inited" << path();
|
||||
// piCoutObj << "inited" << path();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -324,10 +328,10 @@ PIString PIEthernet::macFromBytes(const PIByteArray & mac) {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIEthernet::macToBytes(const PIString & mac) {
|
||||
PIByteArray PIEthernet::macToBytes(const PIString & mac) {
|
||||
PIByteArray r;
|
||||
PIStringList sl = mac.split(PIStringAscii(":"));
|
||||
piForeachC (PIString & i, sl)
|
||||
piForeachC(PIString & i, sl)
|
||||
r << uchar(i.toInt(16));
|
||||
return r;
|
||||
}
|
||||
@@ -363,25 +367,26 @@ PIEthernet::Address PIEthernet::getBroadcast(const PIEthernet::Address & ip, con
|
||||
|
||||
bool PIEthernet::openDevice() {
|
||||
if (connected_) return true;
|
||||
//piCoutObj << "open";
|
||||
// piCoutObj << "open";
|
||||
init();
|
||||
if (sock == -1 || path().isEmpty()) return false;
|
||||
addr_r.set(path());
|
||||
//if (type() == TCP_Client)
|
||||
// if (type() == TCP_Client)
|
||||
// connecting_ = true;
|
||||
if (type() != UDP || mode() == PIIODevice::WriteOnly)
|
||||
return true;
|
||||
if (type() != UDP || mode() == PIIODevice::WriteOnly) return true;
|
||||
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
if (params[PIEthernet::Broadcast]) PRIVATE->addr_.sin_addr.s_addr = INADDR_ANY;
|
||||
else PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
if (params[PIEthernet::Broadcast])
|
||||
PRIVATE->addr_.sin_addr.s_addr = INADDR_ANY;
|
||||
else
|
||||
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
|
||||
#ifdef QNX
|
||||
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
||||
#endif
|
||||
//piCout << "bind to" << (params[PIEthernet::Broadcast] ? "255.255.255.255" : ip_) << ":" << port_ << " ...";
|
||||
// piCout << "bind to" << (params[PIEthernet::Broadcast] ? "255.255.255.255" : ip_) << ":" << port_ << " ...";
|
||||
int tries = 0;
|
||||
while ((bind(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == -1) && (tries < 2)) {
|
||||
while ((bind(sock, (sockaddr *)&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == -1) && (tries < 2)) {
|
||||
init();
|
||||
tries++;
|
||||
}
|
||||
@@ -400,24 +405,22 @@ bool PIEthernet::openDevice() {
|
||||
|
||||
|
||||
bool PIEthernet::closeDevice() {
|
||||
//piCoutObj << "close";
|
||||
bool ned = connected_;
|
||||
// piCoutObj << "close";
|
||||
bool ned = connected_;
|
||||
connected_ = connecting_ = false;
|
||||
server_thread_.stop();
|
||||
PRIVATE->event.interrupt();
|
||||
if (server_thread_.isRunning()) {
|
||||
if (!server_thread_.waitForFinish(1000))
|
||||
server_thread_.terminate();
|
||||
if (!server_thread_.waitForFinish(1000)) server_thread_.terminate();
|
||||
}
|
||||
PRIVATE->event.destroy();
|
||||
if (sock_s == sock)
|
||||
sock_s = -1;
|
||||
if (sock_s == sock) sock_s = -1;
|
||||
closeSocket(sock);
|
||||
closeSocket(sock_s);
|
||||
while (!clients_.isEmpty())
|
||||
delete clients_.back();
|
||||
if (ned) {
|
||||
//piCoutObj << "Disconnect on close";
|
||||
// piCoutObj << "Disconnect on close";
|
||||
disconnected(false);
|
||||
}
|
||||
return true;
|
||||
@@ -425,8 +428,7 @@ bool PIEthernet::closeDevice() {
|
||||
|
||||
|
||||
void PIEthernet::closeSocket(int & sd) {
|
||||
if (sd != -1)
|
||||
ethClosesocket(sd, type() != PIEthernet::UDP);
|
||||
if (sd != -1) ethClosesocket(sd, type() != PIEthernet::UDP);
|
||||
sd = -1;
|
||||
}
|
||||
|
||||
@@ -445,13 +447,14 @@ void PIEthernet::applyTimeouts() {
|
||||
|
||||
void PIEthernet::applyTimeout(int fd, int opt, double ms) {
|
||||
if (fd == 0) return;
|
||||
//piCoutObj << "setReadIsBlocking" << yes;
|
||||
// piCoutObj << "setReadIsBlocking" << yes;
|
||||
#ifdef WINDOWS
|
||||
DWORD _tm = ms;
|
||||
#else
|
||||
double s = ms / 1000.;
|
||||
timeval _tm;
|
||||
_tm.tv_sec = piFloord(s); s -= _tm.tv_sec;
|
||||
_tm.tv_sec = piFloord(s);
|
||||
s -= _tm.tv_sec;
|
||||
_tm.tv_usec = s * 1000000.;
|
||||
#endif
|
||||
ethSetsockopt(fd, SOL_SOCKET, opt, &_tm, sizeof(_tm));
|
||||
@@ -461,8 +464,7 @@ void PIEthernet::applyTimeout(int fd, int opt, double ms) {
|
||||
void PIEthernet::applyOptInt(int level, int opt, int val) {
|
||||
if (sock < 0) return;
|
||||
ethSetsockoptInt(sock, level, opt, val);
|
||||
if (sock_s != sock && sock_s != -1)
|
||||
ethSetsockoptInt(sock_s, level, opt, val);
|
||||
if (sock_s != sock && sock_s != -1) ethSetsockoptInt(sock_s, level, opt, val);
|
||||
}
|
||||
|
||||
|
||||
@@ -474,8 +476,7 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
||||
return false;
|
||||
}
|
||||
if (isClosed()) {
|
||||
if (mcast_queue.contains(group))
|
||||
return false;
|
||||
if (mcast_queue.contains(group)) return false;
|
||||
mcast_queue.enqueue(group);
|
||||
if (!mcast_groups.contains(group)) mcast_groups << group;
|
||||
return true;
|
||||
@@ -488,7 +489,7 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
||||
#endif
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
#ifdef LINUX
|
||||
//mreq.imr_address.s_addr = INADDR_ANY;
|
||||
// mreq.imr_address.s_addr = INADDR_ANY;
|
||||
/*PIEthernet::InterfaceList il = interfaces();
|
||||
const PIEthernet::Interface * ci = il.getByAddress(addr_r.ipString());
|
||||
if (ci != 0) mreq.imr_ifindex = ci->index;*/
|
||||
@@ -499,14 +500,14 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
||||
#else
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
#endif
|
||||
else
|
||||
else
|
||||
#ifndef LWIP
|
||||
mreq.imr_address.s_addr = addr_r.ip();
|
||||
#else
|
||||
mreq.imr_interface.s_addr = addr_r.ip();
|
||||
#endif
|
||||
|
||||
//piCout << "join group" << group << "ip" << ip_ << "with index" << mreq.imr_ifindex << "socket" << sock;
|
||||
// piCout << "join group" << group << "ip" << ip_ << "with index" << mreq.imr_ifindex << "socket" << sock;
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(group.dataAscii());
|
||||
if (ethSetsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) {
|
||||
piCoutObj << "Can`t join multicast group" << group << "," << ethErrorString();
|
||||
@@ -539,7 +540,7 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
|
||||
#else
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
#endif
|
||||
else
|
||||
else
|
||||
#ifndef LWIP
|
||||
mreq.imr_address.s_addr = addr_r.ip();
|
||||
#else
|
||||
@@ -565,14 +566,14 @@ bool PIEthernet::connect(bool threaded) {
|
||||
if (sock == -1) return false;
|
||||
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
|
||||
addr_r.set(path());
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
||||
#endif
|
||||
connecting_ = true;
|
||||
connected_ = connectTCP();
|
||||
connected_ = connectTCP();
|
||||
connecting_ = false;
|
||||
if (!connected_) {
|
||||
piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
||||
@@ -592,26 +593,25 @@ bool PIEthernet::listen(bool threaded) {
|
||||
if (server_thread_.isRunning()) {
|
||||
if (!server_bounded) return true;
|
||||
server_thread_.stop();
|
||||
if (!server_thread_.waitForFinish(100))
|
||||
server_thread_.terminate();
|
||||
if (!server_thread_.waitForFinish(100)) server_thread_.terminate();
|
||||
}
|
||||
listen_threaded = true;
|
||||
server_bounded = false;
|
||||
server_bounded = false;
|
||||
server_thread_.start(server_func);
|
||||
return true;
|
||||
}
|
||||
listen_threaded = server_bounded = false;
|
||||
addr_r.set(path());
|
||||
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
||||
#endif
|
||||
opened_ = false;
|
||||
opened_ = false;
|
||||
int tries = 0;
|
||||
while ((bind(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == -1) && (tries < 2)) {
|
||||
while ((bind(sock, (sockaddr *)&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == -1) && (tries < 2)) {
|
||||
init();
|
||||
tries++;
|
||||
}
|
||||
@@ -620,7 +620,7 @@ bool PIEthernet::listen(bool threaded) {
|
||||
return false;
|
||||
}
|
||||
if (::listen(sock, 64) == -1) {
|
||||
piCoutObj << "Can`t listen on"<< addr_r << "," << ethErrorString();
|
||||
piCoutObj << "Can`t listen on" << addr_r << "," << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
opened_ = server_bounded = true;
|
||||
@@ -652,9 +652,9 @@ bool PIEthernet::send(const PIEthernet::Address & addr, const void * data, int s
|
||||
return true;
|
||||
}
|
||||
Address pa = addr_s;
|
||||
addr_s = addr;
|
||||
int wr = write(data, size);
|
||||
addr_s = pa;
|
||||
addr_s = addr;
|
||||
int wr = write(data, size);
|
||||
addr_s = pa;
|
||||
return (wr == size);
|
||||
}
|
||||
|
||||
@@ -674,66 +674,65 @@ bool PIEthernet::send(const PIEthernet::Address & addr, const PIByteArray & data
|
||||
return true;
|
||||
}
|
||||
Address pa = addr_s;
|
||||
addr_s = addr;
|
||||
int wr = write(data);
|
||||
addr_s = pa;
|
||||
addr_s = addr;
|
||||
int wr = write(data);
|
||||
addr_s = pa;
|
||||
return (wr == data.size_s());
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::interrupt() {
|
||||
//piCout << "interrupt";
|
||||
// piCout << "interrupt";
|
||||
PRIVATE->event.interrupt();
|
||||
}
|
||||
|
||||
|
||||
ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
||||
//piCout << "read" << sock;
|
||||
// piCout << "read" << sock;
|
||||
if (sock == -1) init();
|
||||
if (sock == -1 || read_to == 0) return -1;
|
||||
int rs = 0, lerr = 0;
|
||||
//piCoutObj << "read from " << path() << connecting_;
|
||||
// piCoutObj << "read from " << path() << connecting_;
|
||||
switch (type()) {
|
||||
case TCP_Client:
|
||||
if (connecting_) {
|
||||
addr_r.set(path());
|
||||
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
||||
#endif
|
||||
//piCoutObj << "connect to " << path() << "...";
|
||||
// piCoutObj << "connect to " << path() << "...";
|
||||
connected_ = connectTCP();
|
||||
//piCoutObj << "connect to " << path() << connected_;
|
||||
if (!connected_)
|
||||
piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
||||
// piCoutObj << "connect to " << path() << connected_;
|
||||
if (!connected_) piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
||||
opened_.exchange(connected_);
|
||||
if (connected_) {
|
||||
connecting_ = false;
|
||||
connected();
|
||||
} else
|
||||
piMSleep(10);
|
||||
//piCout << "connected to" << path();
|
||||
// piCout << "connected to" << path();
|
||||
}
|
||||
if (!connected_) return -1;
|
||||
errorClear();
|
||||
#ifdef WINDOWS
|
||||
{
|
||||
long wr = waitForEvent(PRIVATE->event, FD_READ | FD_CLOSE);
|
||||
switch (wr) {
|
||||
case 0: return -1;
|
||||
case FD_READ:
|
||||
//piCout << "fd_read ...";
|
||||
rs = ethRecv(sock, read_to, max_size);
|
||||
break;
|
||||
case FD_CLOSE:
|
||||
//piCout << "fd_close ...";
|
||||
rs = -1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
long wr = waitForEvent(PRIVATE->event, FD_READ | FD_CLOSE);
|
||||
switch (wr) {
|
||||
case 0: return -1;
|
||||
case FD_READ:
|
||||
// piCout << "fd_read ...";
|
||||
rs = ethRecv(sock, read_to, max_size);
|
||||
break;
|
||||
case FD_CLOSE:
|
||||
// piCout << "fd_close ...";
|
||||
rs = -1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (PRIVATE->event.wait(sock)) {
|
||||
@@ -741,10 +740,10 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
||||
rs = ethRecv(sock, read_to, max_size);
|
||||
}
|
||||
#endif
|
||||
//piCoutObj << "readed" << rs;
|
||||
// piCoutObj << "readed" << rs;
|
||||
if (rs <= 0) {
|
||||
lerr = ethErrorCore();
|
||||
//piCoutObj << "readed" << rs << "error" << lerr;
|
||||
// piCoutObj << "readed" << rs << "error" << lerr;
|
||||
|
||||
// async normal returns
|
||||
#ifdef WINDOWS
|
||||
@@ -752,7 +751,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
||||
#else
|
||||
if (lerr == EWOULDBLOCK || lerr == EAGAIN || lerr == EINTR) {
|
||||
#endif
|
||||
//piCoutObj << "Ignore would_block" << lerr;
|
||||
// piCoutObj << "Ignore would_block" << lerr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -763,15 +762,15 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
||||
#else
|
||||
if (lerr == ETIMEDOUT) {
|
||||
#endif
|
||||
//piCoutObj << "Ignore read timeout";
|
||||
// piCoutObj << "Ignore read timeout";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// disconnect here
|
||||
//piCoutObj << "Disconnnected, check for event, connected =" << connected_;
|
||||
// piCoutObj << "Disconnnected, check for event, connected =" << connected_;
|
||||
if (connected_.exchange(false)) {
|
||||
opened_ = false;
|
||||
//piCoutObj << "Disconnect on read," << ethErrorString();
|
||||
// piCoutObj << "Disconnect on read," << ethErrorString();
|
||||
closeSocket(sock);
|
||||
init();
|
||||
disconnected(rs < 0);
|
||||
@@ -779,38 +778,38 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
||||
if (params[KeepConnection]) {
|
||||
connect();
|
||||
}
|
||||
//piCoutObj << "eth" << ip_ << "disconnected";
|
||||
// piCoutObj << "eth" << ip_ << "disconnected";
|
||||
}
|
||||
if (rs > 0) received(read_to, rs);
|
||||
return rs;
|
||||
case UDP: {
|
||||
memset(&PRIVATE->raddr_, 0, sizeof(PRIVATE->raddr_));
|
||||
//piCoutObj << "read from" << path() << "...";
|
||||
// piCoutObj << "read from" << path() << "...";
|
||||
#ifdef WINDOWS
|
||||
long wr = waitForEvent(PRIVATE->event, FD_READ | FD_CLOSE);
|
||||
switch (wr) {
|
||||
case FD_READ:
|
||||
//piCout << "fd_read ...";
|
||||
rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_);
|
||||
// piCout << "fd_read ...";
|
||||
rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr *)&PRIVATE->raddr_);
|
||||
break;
|
||||
case FD_CLOSE:
|
||||
//piCout << "fd_close ...";
|
||||
// piCout << "fd_close ...";
|
||||
rs = -1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
#else
|
||||
rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_);
|
||||
rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr *)&PRIVATE->raddr_);
|
||||
#endif
|
||||
//piCoutObj << "read from" << path() << rs << "bytes";
|
||||
// piCoutObj << "read from" << path() << rs << "bytes";
|
||||
if (rs > 0) {
|
||||
addr_lr.set(uint(PRIVATE->raddr_.sin_addr.s_addr), ntohs(PRIVATE->raddr_.sin_port));
|
||||
//piCoutObj << "read from" << ip_r << ":" << port_r << rs << "bytes";
|
||||
// piCoutObj << "read from" << ip_r << ":" << port_r << rs << "bytes";
|
||||
received(read_to, rs);
|
||||
}
|
||||
//else piCoutObj << "read returt" << rs << ", error" << ethErrorString();
|
||||
// else piCoutObj << "read returt" << rs << ", error" << ethErrorString();
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
return -1;
|
||||
@@ -820,39 +819,42 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
|
||||
ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1 || !isWriteable()) {
|
||||
//piCoutObj << "Can`t send to uninitialized socket";
|
||||
// piCoutObj << "Can`t send to uninitialized socket";
|
||||
return -1;
|
||||
}
|
||||
//piCoutObj << "sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
|
||||
// piCoutObj << "sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
|
||||
int ret = 0;
|
||||
switch (type()) {
|
||||
case UDP:
|
||||
PRIVATE->saddr_.sin_port = htons(addr_s.port());
|
||||
PRIVATE->saddr_.sin_port = htons(addr_s.port());
|
||||
PRIVATE->saddr_.sin_addr.s_addr = addr_s.ip();
|
||||
PRIVATE->saddr_.sin_family = AF_INET;
|
||||
//piCoutObj << "write to" << ip_s << ":" << port_s << "socket" << sock_s << max_size << "bytes ...";
|
||||
return ethSendto(sock_s, data, max_size,
|
||||
PRIVATE->saddr_.sin_family = AF_INET;
|
||||
// piCoutObj << "write to" << ip_s << ":" << port_s << "socket" << sock_s << max_size << "bytes ...";
|
||||
return ethSendto(sock_s,
|
||||
data,
|
||||
max_size,
|
||||
#ifndef WINDOWS
|
||||
isOptionSet(BlockingWrite) ? 0 : MSG_DONTWAIT
|
||||
isOptionSet(BlockingWrite) ? 0 : MSG_DONTWAIT
|
||||
#else
|
||||
0
|
||||
0
|
||||
#endif
|
||||
, (sockaddr * )&PRIVATE->saddr_, sizeof(PRIVATE->saddr_));
|
||||
//piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok";
|
||||
,
|
||||
(sockaddr *)&PRIVATE->saddr_,
|
||||
sizeof(PRIVATE->saddr_));
|
||||
// piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok";
|
||||
case TCP_Client: {
|
||||
if (connecting_) {
|
||||
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
|
||||
addr_r.set(path());
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_port = htons(addr_r.port());
|
||||
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
PRIVATE->addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_);
|
||||
#endif
|
||||
//piCoutObj << "connect to " << ip << ":" << port_;
|
||||
// piCoutObj << "connect to " << ip << ":" << port_;
|
||||
connected_ = connectTCP();
|
||||
if (!connected_)
|
||||
piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
||||
if (!connected_) piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString();
|
||||
opened_.exchange(connected_);
|
||||
if (connected_) {
|
||||
connecting_ = false;
|
||||
@@ -860,10 +862,10 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
}
|
||||
}
|
||||
if (!connected_) return -1;
|
||||
auto disconnectFunc = [this](){
|
||||
auto disconnectFunc = [this]() {
|
||||
if (connected_.exchange(false)) {
|
||||
opened_ = false;
|
||||
//piCoutObj << "Disconnect on write," << ethErrorString();
|
||||
// piCoutObj << "Disconnect on write," << ethErrorString();
|
||||
closeSocket(sock);
|
||||
init();
|
||||
disconnected(true);
|
||||
@@ -876,7 +878,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ssize_t remain_size = max_size;
|
||||
ssize_t remain_size = max_size;
|
||||
const char * remain_data = (const char *)data;
|
||||
while (remain_size > 0) {
|
||||
int sr = ::send(sock, remain_data, remain_size, 0);
|
||||
@@ -888,7 +890,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
if (err == EAGAIN || err == EWOULDBLOCK) {
|
||||
#endif
|
||||
piMinSleep();
|
||||
//piCoutObj << "wait for write";
|
||||
// piCoutObj << "wait for write";
|
||||
continue;
|
||||
} else {
|
||||
disconnectFunc();
|
||||
@@ -899,7 +901,8 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
|
||||
remain_size -= sr;
|
||||
}
|
||||
}
|
||||
return ret;}
|
||||
return ret;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
return -1;
|
||||
@@ -919,13 +922,13 @@ PIIODevice::DeviceInfoFlags PIEthernet::deviceInfoFlags() const {
|
||||
|
||||
void PIEthernet::clientDeleted(PIObject * o) {
|
||||
clients_mutex.lock();
|
||||
clients_.removeOne((PIEthernet*)o);
|
||||
clients_.removeOne((PIEthernet *)o);
|
||||
clients_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::server_func(void * eth) {
|
||||
PIEthernet * ce = (PIEthernet * )eth;
|
||||
PIEthernet * ce = (PIEthernet *)eth;
|
||||
if (ce->listen_threaded) {
|
||||
if (!ce->server_bounded) {
|
||||
if (!ce->listen(false)) {
|
||||
@@ -949,9 +952,9 @@ void PIEthernet::server_func(void * eth) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
//piCout << "server" << "accept ...";
|
||||
int s = accept(ce->sock, (sockaddr * )&client_addr, &slen);
|
||||
//piCout << "server" << "accept done" << ethErrorString();
|
||||
// piCout << "server" << "accept ...";
|
||||
int s = accept(ce->sock, (sockaddr *)&client_addr, &slen);
|
||||
// piCout << "server" << "accept done" << ethErrorString();
|
||||
if (s == -1) {
|
||||
int lerr = ethErrorCore();
|
||||
#ifdef WINDOWS
|
||||
@@ -976,7 +979,7 @@ void PIEthernet::server_func(void * eth) {
|
||||
ce->clients_ << e;
|
||||
ce->clients_mutex.unlock();
|
||||
ce->newConnection(e);
|
||||
//cout << "connected " << ip << endl;
|
||||
// cout << "connected " << ip << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -992,19 +995,20 @@ void PIEthernet::setType(Type t, bool reopen) {
|
||||
|
||||
|
||||
bool PIEthernet::connectTCP() {
|
||||
::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_));
|
||||
//piCout << errorString();
|
||||
::connect(sock, (sockaddr *)&(PRIVATE->addr_), sizeof(PRIVATE->addr_));
|
||||
// piCout << errorString();
|
||||
#ifdef WINDOWS
|
||||
long wr = waitForEvent(PRIVATE->event, FD_CONNECT | FD_CLOSE);
|
||||
switch (wr) {
|
||||
case FD_CONNECT:
|
||||
//piCout << "fd_connect ...";
|
||||
// piCout << "fd_connect ...";
|
||||
return ethIsWriteable(sock);
|
||||
default: break;
|
||||
}
|
||||
#else
|
||||
if (PRIVATE->event.wait(sock, PIWaitEvent::CheckWrite)) {
|
||||
if (ethIsWriteable(sock)) return true;
|
||||
if (ethIsWriteable(sock))
|
||||
return true;
|
||||
else {
|
||||
closeSocket(sock);
|
||||
init();
|
||||
@@ -1019,16 +1023,15 @@ bool PIEthernet::connectTCP() {
|
||||
long PIEthernet::waitForEvent(PIWaitEvent & event, long mask) {
|
||||
if (!event.isCreate() || sock < 0) return 0;
|
||||
if (WSAEventSelect(sock, event.getEvent(), mask) == SOCKET_ERROR) {
|
||||
if (ethErrorCore() == WSAEINPROGRESS)
|
||||
return 0;
|
||||
if (ethErrorCore() == WSAEINPROGRESS) return 0;
|
||||
}
|
||||
if (event.wait()) {
|
||||
//DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE);
|
||||
//if (wr == WSA_WAIT_EVENT_0) {
|
||||
// DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE);
|
||||
// if (wr == WSA_WAIT_EVENT_0) {
|
||||
WSANETWORKEVENTS events;
|
||||
memset(&events, 0, sizeof(events));
|
||||
WSAEnumNetworkEvents(sock, event.getEvent(), &events);
|
||||
//piCoutObj << "wait result" << events.lNetworkEvents;
|
||||
// piCoutObj << "wait result" << events.lNetworkEvents;
|
||||
return events.lNetworkEvents;
|
||||
}
|
||||
return 0;
|
||||
@@ -1037,8 +1040,8 @@ long PIEthernet::waitForEvent(PIWaitEvent & event, long mask) {
|
||||
|
||||
|
||||
bool PIEthernet::configureDevice(const void * e_main, const void * e_parent) {
|
||||
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
||||
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
||||
PIConfig::Entry * em = (PIConfig::Entry *)e_main;
|
||||
PIConfig::Entry * ep = (PIConfig::Entry *)e_parent;
|
||||
setReadIP(readDeviceSetting<PIString>("ip", readIP(), em, ep));
|
||||
setReadPort(readDeviceSetting<int>("port", readPort(), em, ep));
|
||||
setParameter(PIEthernet::Broadcast, readDeviceSetting<bool>("broadcast", isParameterSet(PIEthernet::Broadcast), em, ep));
|
||||
@@ -1061,7 +1064,7 @@ PIString PIEthernet::constructFullPathDevice() const {
|
||||
ret += ":" + readIP() + ":" + PIString::fromNumber(readPort());
|
||||
if (type() == PIEthernet::UDP) {
|
||||
ret += ":" + sendIP() + ":" + PIString::fromNumber(sendPort());
|
||||
piForeachC (PIString & m, multicastGroups())
|
||||
piForeachC(PIString & m, multicastGroups())
|
||||
ret += ":mcast:" + m;
|
||||
}
|
||||
return ret;
|
||||
@@ -1070,7 +1073,7 @@ PIString PIEthernet::constructFullPathDevice() const {
|
||||
|
||||
void PIEthernet::configureFromFullPathDevice(const PIString & full_path) {
|
||||
PIStringList pl = full_path.split(":");
|
||||
bool mcast = false;
|
||||
bool mcast = false;
|
||||
for (int i = 0; i < pl.size_s(); ++i) {
|
||||
PIString p(pl[i]);
|
||||
switch (i) {
|
||||
@@ -1079,14 +1082,26 @@ void PIEthernet::configureFromFullPathDevice(const PIString & full_path) {
|
||||
if (p == "udp") setType(UDP);
|
||||
if (p == "tcp") setType(TCP_Client);
|
||||
break;
|
||||
case 1: setReadIP(p); setSendIP(p); break;
|
||||
case 2: setReadPort(p.toInt()); setSendPort(p.toInt()); break;
|
||||
case 1:
|
||||
setReadIP(p);
|
||||
setSendIP(p);
|
||||
break;
|
||||
case 2:
|
||||
setReadPort(p.toInt());
|
||||
setSendPort(p.toInt());
|
||||
break;
|
||||
case 3: setSendIP(p); break;
|
||||
case 4: setSendPort(p.toInt()); break;
|
||||
}
|
||||
if (i <= 4) continue;
|
||||
if (i % 2 == 1) {if (p.toLowerCase() == "mcast") mcast = true;}
|
||||
else {if (mcast) {joinMulticastGroup(p); mcast = false;}}
|
||||
if (i % 2 == 1) {
|
||||
if (p.toLowerCase() == "mcast") mcast = true;
|
||||
} else {
|
||||
if (mcast) {
|
||||
joinMulticastGroup(p);
|
||||
mcast = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1095,7 +1110,8 @@ PIPropertyStorage PIEthernet::constructVariantDevice() const {
|
||||
PIPropertyStorage ret;
|
||||
PIVariantTypes::Enum e;
|
||||
|
||||
e << "UDP" << "TCP";
|
||||
e << "UDP"
|
||||
<< "TCP";
|
||||
if (type() == PIEthernet::UDP)
|
||||
e.selectValue(0);
|
||||
else
|
||||
@@ -1118,21 +1134,21 @@ void PIEthernet::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
setSendIP(d.propertyValueByName("send IP").toString());
|
||||
setSendPort(d.propertyValueByName("send port").toInt());
|
||||
PIStringList mcgl = d.propertyValueByName("multicast").toStringList();
|
||||
piForeachC (PIString & g, mcgl) {
|
||||
piForeachC(PIString & g, mcgl) {
|
||||
joinMulticastGroup(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
//piCout << "PIEthernet::interfaces()";
|
||||
// piCout << "PIEthernet::interfaces()";
|
||||
PIEthernet::InterfaceList il;
|
||||
Interface ci;
|
||||
ci.index = -1;
|
||||
ci.mtu = 1500;
|
||||
ci.mtu = 1500;
|
||||
#ifdef WINDOWS
|
||||
int ret = 0;
|
||||
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
int ret = 0;
|
||||
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO));
|
||||
if (!pAdapterInfo) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersInfo";
|
||||
@@ -1149,9 +1165,9 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
||||
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
|
||||
while (pAdapter) {
|
||||
ci.name = PIString(pAdapter->AdapterName);
|
||||
ci.name = PIString(pAdapter->AdapterName);
|
||||
ci.index = pAdapter->Index;
|
||||
ci.mac = macFromBytes(PIByteArray(pAdapter->Address, pAdapter->AddressLength));
|
||||
ci.mac = macFromBytes(PIByteArray(pAdapter->Address, pAdapter->AddressLength));
|
||||
ci.flags = PIEthernet::ifActive | PIEthernet::ifRunning;
|
||||
if (pAdapter->Type == MIB_IF_TYPE_PPP) ci.flags |= PIEthernet::ifPTP;
|
||||
if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
|
||||
@@ -1159,7 +1175,7 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
ci.ptp.clear();
|
||||
IP_ADDR_STRING * as = &(pAdapter->IpAddressList);
|
||||
while (as) {
|
||||
// piCout << "[pAdapter]" << ci.name << PIString(as->IpAddress.String);
|
||||
// piCout << "[pAdapter]" << ci.name << PIString(as->IpAddress.String);
|
||||
ci.address = PIStringAscii(as->IpAddress.String);
|
||||
ci.netmask = PIStringAscii(as->IpMask.String);
|
||||
if (ci.address == "0.0.0.0") {
|
||||
@@ -1174,21 +1190,17 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
} else {
|
||||
switch (ret) {
|
||||
case ERROR_NO_DATA: break;
|
||||
case ERROR_NOT_SUPPORTED:
|
||||
piCout << "[PIEthernet] GetAdaptersInfo not supported";
|
||||
break;
|
||||
default:
|
||||
piCout << "[PIEthernet] GetAdaptersInfo failed with error:" << ret;
|
||||
case ERROR_NOT_SUPPORTED: piCout << "[PIEthernet] GetAdaptersInfo not supported"; break;
|
||||
default: piCout << "[PIEthernet] GetAdaptersInfo failed with error:" << ret;
|
||||
}
|
||||
}
|
||||
if (pAdapterInfo)
|
||||
HeapFree(GetProcessHeap(), 0, pAdapterInfo);
|
||||
if (pAdapterInfo) HeapFree(GetProcessHeap(), 0, pAdapterInfo);
|
||||
#else
|
||||
#ifdef MICRO_PIP
|
||||
#else
|
||||
# ifdef ANDROID
|
||||
# ifdef MICRO_PIP
|
||||
# else
|
||||
# ifdef ANDROID
|
||||
struct ifconf ifc;
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
ifc.ifc_len = 256;
|
||||
ifc.ifc_buf = new char[ifc.ifc_len];
|
||||
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
|
||||
@@ -1200,24 +1212,21 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
PIStringList inl;
|
||||
struct ifreq ir;
|
||||
for (int i = 0; i < icnt; ++i) {
|
||||
ci.flags = 0;
|
||||
ci.flags = 0;
|
||||
PIString in = PIStringAscii(ifc.ifc_req[i].ifr_name);
|
||||
if (in.isEmpty()) continue;
|
||||
ci.name = in;
|
||||
strcpy(ir.ifr_name, in.dataAscii());
|
||||
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0)
|
||||
ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
|
||||
if (ioctl(s, SIOCGIFADDR, &ir) >= 0)
|
||||
ci.address = getSockAddr(&ir.ifr_addr);
|
||||
if (ioctl(s, SIOCGIFNETMASK, &ir) >= 0)
|
||||
ci.netmask = getSockAddr(&ir.ifr_addr);
|
||||
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0) ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
|
||||
if (ioctl(s, SIOCGIFADDR, &ir) >= 0) ci.address = getSockAddr(&ir.ifr_addr);
|
||||
if (ioctl(s, SIOCGIFNETMASK, &ir) >= 0) ci.netmask = getSockAddr(&ir.ifr_addr);
|
||||
ioctl(s, SIOCGIFMTU, &ci.mtu);
|
||||
if (ci.address == "127.0.0.1") ci.flags |= PIEthernet::ifLoopback;
|
||||
il << ci;
|
||||
}
|
||||
delete ifc.ifc_buf;
|
||||
# else
|
||||
struct ifaddrs * ret, * cif = 0;
|
||||
# else
|
||||
struct ifaddrs *ret, *cif = 0;
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (getifaddrs(&ret) == 0) {
|
||||
cif = ret;
|
||||
@@ -1230,12 +1239,12 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
cif = cif->ifa_next;
|
||||
continue;
|
||||
}
|
||||
ci.name = PIString(cif->ifa_name);
|
||||
ci.name = PIString(cif->ifa_name);
|
||||
ci.address = getSockAddr(cif->ifa_addr);
|
||||
ci.netmask = getSockAddr(cif->ifa_netmask);
|
||||
ci.mac.clear();
|
||||
# ifdef QNX
|
||||
# ifndef BLACKBERRY
|
||||
# ifdef QNX
|
||||
# ifndef BLACKBERRY
|
||||
int fd = ::open((PIString("/dev/io-net/") + ci.name).dataAscii(), O_RDONLY);
|
||||
if (fd != 0) {
|
||||
nic_config_t nic;
|
||||
@@ -1243,20 +1252,20 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
::close(fd);
|
||||
ci.mac = macFromBytes(PIByteArray(nic.permanent_address, 6));
|
||||
}
|
||||
# endif
|
||||
# else
|
||||
# ifdef MAC_OS
|
||||
# endif
|
||||
# else
|
||||
# ifdef MAC_OS
|
||||
PIString req = PISystemInfo::instance()->ifconfigPath + " " + ci.name + " | grep ether";
|
||||
FILE * fp = popen(req.dataAscii(), "r");
|
||||
FILE * fp = popen(req.dataAscii(), "r");
|
||||
if (fp != 0) {
|
||||
char in[256];
|
||||
if (fgets(in, 256, fp) != 0) {
|
||||
req = PIString(in).trim();
|
||||
req = PIString(in).trim();
|
||||
ci.mac = req.cutLeft(req.find(" ") + 1).trim().toUpperCase();
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
# else
|
||||
# else
|
||||
if (s != -1) {
|
||||
struct ifreq ir;
|
||||
strcpy(ir.ifr_name, cif->ifa_name);
|
||||
@@ -1265,8 +1274,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
ci.mtu = ir.ifr_mtu;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
ci.flags = 0;
|
||||
if (cif->ifa_flags & IFF_UP) ci.flags |= PIEthernet::ifActive;
|
||||
if (cif->ifa_flags & IFF_RUNNING) ci.flags |= PIEthernet::ifRunning;
|
||||
@@ -1276,10 +1285,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
if (cif->ifa_flags & IFF_POINTOPOINT) ci.flags |= PIEthernet::ifPTP;
|
||||
ci.broadcast.clear();
|
||||
ci.ptp.clear();
|
||||
if (ci.flags[PIEthernet::ifBroadcast])
|
||||
ci.broadcast = getSockAddr(cif->ifa_broadaddr);
|
||||
if (ci.flags[PIEthernet::ifPTP])
|
||||
ci.ptp = getSockAddr(cif->ifa_dstaddr);
|
||||
if (ci.flags[PIEthernet::ifBroadcast]) ci.broadcast = getSockAddr(cif->ifa_broadaddr);
|
||||
if (ci.flags[PIEthernet::ifPTP]) ci.ptp = getSockAddr(cif->ifa_dstaddr);
|
||||
ci.index = if_nametoindex(cif->ifa_name);
|
||||
il << ci;
|
||||
cif = cif->ifa_next;
|
||||
@@ -1288,7 +1295,7 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
} else
|
||||
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
|
||||
if (s != -1) ::close(s);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
return il;
|
||||
@@ -1306,10 +1313,9 @@ PIEthernet::Address PIEthernet::interfaceAddress(const PIString & interface_) {
|
||||
int s = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ioctl(s, SIOCGIFADDR, &ifr);
|
||||
::close(s);
|
||||
struct sockaddr_in * sa = (struct sockaddr_in * )&ifr.ifr_addr;
|
||||
struct sockaddr_in * sa = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
return Address(uint(sa->sin_addr.s_addr));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1317,13 +1323,13 @@ PIVector<PIEthernet::Address> PIEthernet::allAddresses() {
|
||||
PIEthernet::InterfaceList il = interfaces();
|
||||
PIVector<Address> ret;
|
||||
bool has_127 = false;
|
||||
piForeachC (PIEthernet::Interface & i, il) {
|
||||
piForeachC(PIEthernet::Interface & i, il) {
|
||||
if (i.address == "127.0.0.1") has_127 = true;
|
||||
Address a(i.address);
|
||||
if (a.ip() == 0) continue;
|
||||
ret << a;
|
||||
}
|
||||
// piCout << "[PIEthernet::allAddresses]" << al;
|
||||
// piCout << "[PIEthernet::allAddresses]" << al;
|
||||
if (!has_127) ret << Address("127.0.0.1");
|
||||
return ret;
|
||||
}
|
||||
@@ -1343,8 +1349,14 @@ int PIEthernet::ethErrorCore() {
|
||||
PIString PIEthernet::ethErrorString() {
|
||||
#ifdef WINDOWS
|
||||
char * msg = nullptr;
|
||||
int err = WSAGetLastError();
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
|
||||
int err = WSAGetLastError();
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&msg,
|
||||
0,
|
||||
NULL);
|
||||
PIString ret = PIStringAscii("code ") + PIString::fromNumber(err) + PIStringAscii(" - ");
|
||||
if (msg) {
|
||||
ret += PIString::fromSystem(msg).trim();
|
||||
@@ -1362,9 +1374,11 @@ int PIEthernet::ethRecv(int sock, void * buf, int size, int flags) {
|
||||
if (sock < 0) return -1;
|
||||
return recv(sock,
|
||||
#ifdef WINDOWS
|
||||
(char*)
|
||||
(char *)
|
||||
#endif
|
||||
buf, size, flags);
|
||||
buf,
|
||||
size,
|
||||
flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -1376,9 +1390,13 @@ int PIEthernet::ethRecvfrom(int sock, void * buf, int size, int flags, sockaddr
|
||||
socklen_t len = sizeof(sockaddr);
|
||||
return recvfrom(sock,
|
||||
# ifdef WINDOWS
|
||||
(char*)
|
||||
(char *)
|
||||
# endif
|
||||
buf, size, flags, addr, &len);
|
||||
buf,
|
||||
size,
|
||||
flags,
|
||||
addr,
|
||||
&len);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1387,33 +1405,41 @@ int PIEthernet::ethSendto(int sock, const void * buf, int size, int flags, socka
|
||||
if (sock < 0) return -1;
|
||||
return sendto(sock,
|
||||
#ifdef WINDOWS
|
||||
(const char*)
|
||||
(const char *)
|
||||
#endif
|
||||
buf, size, flags, addr, addr_len);
|
||||
buf,
|
||||
size,
|
||||
flags,
|
||||
addr,
|
||||
addr_len);
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::ethClosesocket(int sock, bool shutdown) {
|
||||
//piCout << "close socket" << sock << shutdown;
|
||||
// piCout << "close socket" << sock << shutdown;
|
||||
if (sock < 0) return;
|
||||
if (shutdown) ::shutdown(sock,
|
||||
if (shutdown)
|
||||
::shutdown(sock,
|
||||
#ifdef WINDOWS
|
||||
SD_BOTH);
|
||||
closesocket(sock);
|
||||
SD_BOTH);
|
||||
closesocket(sock);
|
||||
#else
|
||||
SHUT_RDWR);
|
||||
::close(sock);
|
||||
SHUT_RDWR);
|
||||
::close(sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int PIEthernet::ethSetsockopt(int sock, int level, int optname, const void * optval, int optlen) {
|
||||
if (sock < 0) return -1;
|
||||
return setsockopt(sock, level, optname,
|
||||
return setsockopt(sock,
|
||||
level,
|
||||
optname,
|
||||
#ifdef WINDOWS
|
||||
(char*)
|
||||
(char *)
|
||||
#endif
|
||||
optval, optlen);
|
||||
optval,
|
||||
optlen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1424,7 +1450,7 @@ int PIEthernet::ethSetsockoptInt(int sock, int level, int optname, int value) {
|
||||
#else
|
||||
int
|
||||
#endif
|
||||
so = value;
|
||||
so = value;
|
||||
return ethSetsockopt(sock, level, optname, &so, sizeof(so));
|
||||
}
|
||||
|
||||
@@ -1436,7 +1462,7 @@ int PIEthernet::ethSetsockoptBool(int sock, int level, int optname, bool value)
|
||||
#else
|
||||
int
|
||||
#endif
|
||||
so = (value ? 1 : 0);
|
||||
so = (value ? 1 : 0);
|
||||
return ethSetsockopt(sock, level, optname, &so, sizeof(so));
|
||||
}
|
||||
|
||||
@@ -1473,9 +1499,9 @@ bool PIEthernet::ethIsWriteable(int sock) {
|
||||
::select(0, nullptr, &fd_test, nullptr, &timeout);
|
||||
return FD_ISSET(sock, &fd_test);
|
||||
#else
|
||||
int ret = 0;
|
||||
int ret = 0;
|
||||
socklen_t len = sizeof(ret);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&ret, &len);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&ret, &len);
|
||||
return ret == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,61 +5,61 @@
|
||||
* \~russian Устройство Ethernet
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP/TCP Broadcast/Multicast
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP/TCP Broadcast/Multicast
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIETHERNET_H
|
||||
#define PIETHERNET_H
|
||||
|
||||
#include "pitimer.h"
|
||||
#include "piiodevice.h"
|
||||
#include "pitimer.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
struct
|
||||
struct
|
||||
#else
|
||||
class
|
||||
class
|
||||
#endif
|
||||
sockaddr;
|
||||
|
||||
class PIP_EXPORT PIEthernet: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIEthernet: public PIIODevice {
|
||||
PIIODEVICE(PIEthernet, "eth");
|
||||
friend class PIPeer;
|
||||
|
||||
public:
|
||||
|
||||
//! Contructs UDP %PIEthernet with empty read address
|
||||
explicit PIEthernet();
|
||||
|
||||
//! \brief Type of %PIEthernet
|
||||
enum Type {
|
||||
UDP /** UDP - User Datagram Protocol */ ,
|
||||
TCP_Client /** TCP client - allow connection to TCP server */ ,
|
||||
UDP /** UDP - User Datagram Protocol */,
|
||||
TCP_Client /** TCP client - allow connection to TCP server */,
|
||||
TCP_Server /** TCP server - receive connections from TCP clients */
|
||||
};
|
||||
|
||||
|
||||
//! \brief Parameters of %PIEthernet
|
||||
enum Parameters {
|
||||
ReuseAddress /** Rebind address if there is already binded. Enabled by default */ = 0x1,
|
||||
Broadcast /** Broadcast send. Disabled by default */ = 0x2,
|
||||
Broadcast /** Broadcast send. Disabled by default */ = 0x2,
|
||||
SeparateSockets /** If this parameter is set, %PIEthernet will initialize two different sockets,
|
||||
for receive and send, instead of single one. Disabled by default */ = 0x4,
|
||||
MulticastLoop /** Enable receiving multicast packets from same host. Enabled by default */ = 0x8,
|
||||
KeepConnection /** Automatic reconnect TCP connection on disconnect. Enabled by default */ = 0x10,
|
||||
for receive and send, instead of single one. Disabled by default */
|
||||
= 0x4,
|
||||
MulticastLoop /** Enable receiving multicast packets from same host. Enabled by default */ = 0x8,
|
||||
KeepConnection /** Automatic reconnect TCP connection on disconnect. Enabled by default */ = 0x10,
|
||||
DisonnectOnTimeout /** Disconnect TCP connection on read timeout expired. Disabled by default */ = 0x20
|
||||
};
|
||||
|
||||
@@ -67,8 +67,8 @@ public:
|
||||
//! \brief IPv4 network address, IP and port
|
||||
class PIP_EXPORT Address {
|
||||
friend class PIEthernet;
|
||||
public:
|
||||
|
||||
public:
|
||||
//! Contructs %Address with binary representation of IP and port
|
||||
Address(uint ip = 0, ushort port = 0);
|
||||
|
||||
@@ -79,10 +79,10 @@ public:
|
||||
Address(const PIString & ip, ushort port);
|
||||
|
||||
//! Returns binary IP
|
||||
uint ip() const {return ip_;}
|
||||
uint ip() const { return ip_; }
|
||||
|
||||
//! Returns port
|
||||
ushort port() const {return port_;}
|
||||
ushort port() const { return port_; }
|
||||
|
||||
//! Returns string IP
|
||||
PIString ipString() const;
|
||||
@@ -121,6 +121,7 @@ public:
|
||||
static Address resolve(const PIString & host, ushort port);
|
||||
|
||||
static void splitIPPort(const PIString & ipp, PIString * ip, int * port);
|
||||
|
||||
private:
|
||||
void initIP(const PIString & _ip);
|
||||
union {
|
||||
@@ -132,301 +133,351 @@ public:
|
||||
|
||||
|
||||
//! Contructs %PIEthernet with type "type", read address "ip_port" and parameters "params"
|
||||
explicit PIEthernet(Type type, const PIString & ip_port = PIString(), const PIFlags<Parameters> params = PIEthernet::ReuseAddress | PIEthernet::MulticastLoop | PIEthernet::KeepConnection);
|
||||
|
||||
explicit PIEthernet(Type type,
|
||||
const PIString & ip_port = PIString(),
|
||||
const PIFlags<Parameters> params = PIEthernet::ReuseAddress | PIEthernet::MulticastLoop |
|
||||
PIEthernet::KeepConnection);
|
||||
|
||||
virtual ~PIEthernet();
|
||||
|
||||
|
||||
|
||||
//! Set read address
|
||||
void setReadAddress(const PIString & ip, int port) {addr_r.set(ip, port); setPath(addr_r.toString());}
|
||||
|
||||
void setReadAddress(const PIString & ip, int port) {
|
||||
addr_r.set(ip, port);
|
||||
setPath(addr_r.toString());
|
||||
}
|
||||
|
||||
//! Set read address in format "i.i.i.i:p"
|
||||
void setReadAddress(const PIString & ip_port) {addr_r.set(ip_port); setPath(addr_r.toString());}
|
||||
void setReadAddress(const PIString & ip_port) {
|
||||
addr_r.set(ip_port);
|
||||
setPath(addr_r.toString());
|
||||
}
|
||||
|
||||
//! Set read address
|
||||
void setReadAddress(const Address & addr) {addr_r = addr; setPath(addr_r.toString());}
|
||||
|
||||
void setReadAddress(const Address & addr) {
|
||||
addr_r = addr;
|
||||
setPath(addr_r.toString());
|
||||
}
|
||||
|
||||
//! Set read IP
|
||||
void setReadIP(const PIString & ip) {addr_r.setIP(ip); setPath(addr_r.toString());}
|
||||
|
||||
void setReadIP(const PIString & ip) {
|
||||
addr_r.setIP(ip);
|
||||
setPath(addr_r.toString());
|
||||
}
|
||||
|
||||
//! Set read port
|
||||
void setReadPort(int port) {addr_r.setPort(port); setPath(addr_r.toString());}
|
||||
|
||||
|
||||
void setReadPort(int port) {
|
||||
addr_r.setPort(port);
|
||||
setPath(addr_r.toString());
|
||||
}
|
||||
|
||||
|
||||
//! Set send address
|
||||
void setSendAddress(const PIString & ip, int port) {addr_s.set(ip, port);}
|
||||
|
||||
void setSendAddress(const PIString & ip, int port) { addr_s.set(ip, port); }
|
||||
|
||||
//! Set send address in format "i.i.i.i:p"
|
||||
void setSendAddress(const PIString & ip_port) {addr_s.set(ip_port);}
|
||||
void setSendAddress(const PIString & ip_port) { addr_s.set(ip_port); }
|
||||
|
||||
//! Set send address
|
||||
void setSendAddress(const Address & addr) {addr_s = addr;}
|
||||
|
||||
//! Set send IP
|
||||
void setSendIP(const PIString & ip) {addr_s.setIP(ip);}
|
||||
|
||||
//! Set send port
|
||||
void setSendPort(int port) {addr_s.setPort(port);}
|
||||
|
||||
|
||||
//! Returns read address in format "i.i.i.i:p"
|
||||
Address readAddress() const {return addr_r;}
|
||||
|
||||
//! Returns read IP
|
||||
PIString readIP() const {return addr_r.ipString();}
|
||||
|
||||
//! Returns read port
|
||||
int readPort() const {return addr_r.port();}
|
||||
|
||||
|
||||
//! Returns send address in format "i.i.i.i:p"
|
||||
Address sendAddress() const {return addr_s;}
|
||||
|
||||
//! Returns send IP
|
||||
PIString sendIP() const {return addr_s.ipString();}
|
||||
|
||||
//! Returns send port
|
||||
int sendPort() const {return addr_s.port();}
|
||||
|
||||
|
||||
//! Returns address of last received UDP packet in format "i.i.i.i:p"
|
||||
Address lastReadAddress() const {return addr_lr;}
|
||||
|
||||
//! Returns IP of last received UDP packet
|
||||
PIString lastReadIP() const {return addr_lr.ipString();}
|
||||
|
||||
//! Returns port of last received UDP packet
|
||||
int lastReadPort() const {return addr_lr.port();}
|
||||
void setSendAddress(const Address & addr) { addr_s = addr; }
|
||||
|
||||
//! Set send IP
|
||||
void setSendIP(const PIString & ip) { addr_s.setIP(ip); }
|
||||
|
||||
//! Set send port
|
||||
void setSendPort(int port) { addr_s.setPort(port); }
|
||||
|
||||
|
||||
//! Returns read address in format "i.i.i.i:p"
|
||||
Address readAddress() const { return addr_r; }
|
||||
|
||||
//! Returns read IP
|
||||
PIString readIP() const { return addr_r.ipString(); }
|
||||
|
||||
//! Returns read port
|
||||
int readPort() const { return addr_r.port(); }
|
||||
|
||||
|
||||
//! Returns send address in format "i.i.i.i:p"
|
||||
Address sendAddress() const { return addr_s; }
|
||||
|
||||
//! Returns send IP
|
||||
PIString sendIP() const { return addr_s.ipString(); }
|
||||
|
||||
//! Returns send port
|
||||
int sendPort() const { return addr_s.port(); }
|
||||
|
||||
|
||||
//! Returns address of last received UDP packet in format "i.i.i.i:p"
|
||||
Address lastReadAddress() const { return addr_lr; }
|
||||
|
||||
//! Returns IP of last received UDP packet
|
||||
PIString lastReadIP() const { return addr_lr.ipString(); }
|
||||
|
||||
//! Returns port of last received UDP packet
|
||||
int lastReadPort() const { return addr_lr.port(); }
|
||||
|
||||
|
||||
|
||||
//! Set parameters to "parameters_". You should to reopen %PIEthernet to apply them
|
||||
void setParameters(PIFlags<PIEthernet::Parameters> parameters_) {params = parameters_;}
|
||||
|
||||
void setParameters(PIFlags<PIEthernet::Parameters> parameters_) { params = parameters_; }
|
||||
|
||||
//! Set parameter "parameter" to state "on". You should to reopen %PIEthernet to apply this
|
||||
void setParameter(PIEthernet::Parameters parameter, bool on = true) {params.setFlag(parameter, on);}
|
||||
|
||||
void setParameter(PIEthernet::Parameters parameter, bool on = true) { params.setFlag(parameter, on); }
|
||||
|
||||
//! Returns if parameter "parameter" is set
|
||||
bool isParameterSet(PIEthernet::Parameters parameter) const {return params[parameter];}
|
||||
|
||||
bool isParameterSet(PIEthernet::Parameters parameter) const { return params[parameter]; }
|
||||
|
||||
//! Returns parameters
|
||||
PIFlags<PIEthernet::Parameters> parameters() const {return params;}
|
||||
PIFlags<PIEthernet::Parameters> parameters() const { return params; }
|
||||
|
||||
//! Returns %PIEthernet type
|
||||
Type type() const {return eth_type;}
|
||||
|
||||
//! Returns read timeout
|
||||
double readTimeout() const {return property("readTimeout").toDouble();}
|
||||
|
||||
//! Returns write timeout
|
||||
double writeTimeout() const {return property("writeTimeout").toDouble();}
|
||||
|
||||
//! Set timeout for read
|
||||
void setReadTimeout(double ms) {setProperty("readTimeout", ms);}
|
||||
|
||||
//! Set timeout for write
|
||||
void setWriteTimeout(double ms) {setProperty("writeTimeout", ms);}
|
||||
|
||||
|
||||
//! Returns TTL (Time To Live)
|
||||
int TTL() const {return property("TTL").toInt();}
|
||||
|
||||
//! Returns multicast TTL (Time To Live)
|
||||
int multicastTTL() const {return property("MulticastTTL").toInt();}
|
||||
|
||||
//! Set TTL (Time To Live), default is 64
|
||||
void setTTL(int ttl) {setProperty("TTL", ttl);}
|
||||
|
||||
//! Set multicast TTL (Time To Live), default is 1
|
||||
void setMulticastTTL(int ttl) {setProperty("MulticastTTL", ttl);}
|
||||
Type type() const { return eth_type; }
|
||||
|
||||
//! Returns read timeout
|
||||
double readTimeout() const { return property("readTimeout").toDouble(); }
|
||||
|
||||
//! Returns write timeout
|
||||
double writeTimeout() const { return property("writeTimeout").toDouble(); }
|
||||
|
||||
//! Set timeout for read
|
||||
void setReadTimeout(double ms) { setProperty("readTimeout", ms); }
|
||||
|
||||
//! Set timeout for write
|
||||
void setWriteTimeout(double ms) { setProperty("writeTimeout", ms); }
|
||||
|
||||
|
||||
//! Returns TTL (Time To Live)
|
||||
int TTL() const { return property("TTL").toInt(); }
|
||||
|
||||
//! Returns multicast TTL (Time To Live)
|
||||
int multicastTTL() const { return property("MulticastTTL").toInt(); }
|
||||
|
||||
//! Set TTL (Time To Live), default is 64
|
||||
void setTTL(int ttl) { setProperty("TTL", ttl); }
|
||||
|
||||
//! Set multicast TTL (Time To Live), default is 1
|
||||
void setMulticastTTL(int ttl) { setProperty("MulticastTTL", ttl); }
|
||||
|
||||
|
||||
|
||||
//! Join to multicast group with address "group". Use only for UDP
|
||||
bool joinMulticastGroup(const PIString & group);
|
||||
|
||||
|
||||
//! Leave multicast group with address "group". Use only for UDP
|
||||
bool leaveMulticastGroup(const PIString & group);
|
||||
|
||||
|
||||
//! Returns joined multicast groups. Use only for UDP
|
||||
const PIStringList & multicastGroups() const {return mcast_groups;}
|
||||
|
||||
|
||||
const PIStringList & multicastGroups() const { return mcast_groups; }
|
||||
|
||||
|
||||
//! If \"threaded\" queue connect to TCP server with address \a readAddress() in
|
||||
//! any \a read() or \a write() call. Otherwise connect immediate.
|
||||
//! Use only for TCP_Client
|
||||
bool connect(bool threaded = true);
|
||||
|
||||
|
||||
//! Connect to TCP server with address "ip":"port". Use only for TCP_Client
|
||||
bool connect(const PIString & ip, int port, bool threaded = true) {setPath(ip + PIStringAscii(":") + PIString::fromNumber(port)); return connect(threaded);}
|
||||
|
||||
bool connect(const PIString & ip, int port, bool threaded = true) {
|
||||
setPath(ip + PIStringAscii(":") + PIString::fromNumber(port));
|
||||
return connect(threaded);
|
||||
}
|
||||
|
||||
//! Connect to TCP server with address "ip_port". Use only for TCP_Client
|
||||
bool connect(const PIString & ip_port, bool threaded = true) {setPath(ip_port); return connect(threaded);}
|
||||
bool connect(const PIString & ip_port, bool threaded = true) {
|
||||
setPath(ip_port);
|
||||
return connect(threaded);
|
||||
}
|
||||
|
||||
//! Connect to TCP server with address "addr". Use only for TCP_Client
|
||||
bool connect(const Address & addr, bool threaded = true) {setPath(addr.toString()); return connect(threaded);}
|
||||
|
||||
bool connect(const Address & addr, bool threaded = true) {
|
||||
setPath(addr.toString());
|
||||
return connect(threaded);
|
||||
}
|
||||
|
||||
//! Returns if %PIEthernet connected to TCP server. Use only for TCP_Client
|
||||
bool isConnected() const {return connected_;}
|
||||
|
||||
bool isConnected() const { return connected_; }
|
||||
|
||||
//! Returns if %PIEthernet is connecting to TCP server. Use only for TCP_Client
|
||||
bool isConnecting() const {return connecting_;}
|
||||
|
||||
|
||||
bool isConnecting() const { return connecting_; }
|
||||
|
||||
|
||||
//! Start listen for incoming TCP connections on address \a readAddress(). Use only for TCP_Server
|
||||
bool listen(bool threaded = false);
|
||||
|
||||
|
||||
//! Start listen for incoming TCP connections on address "ip":"port". Use only for TCP_Server
|
||||
bool listen(const PIString & ip, int port, bool threaded = false) {return listen(PIEthernet::Address(ip, port), threaded);}
|
||||
|
||||
bool listen(const PIString & ip, int port, bool threaded = false) { return listen(PIEthernet::Address(ip, port), threaded); }
|
||||
|
||||
//! Start listen for incoming TCP connections on address "ip_port". Use only for TCP_Server
|
||||
bool listen(const PIString & ip_port, bool threaded = false) {return listen(PIEthernet::Address(ip_port), threaded);}
|
||||
bool listen(const PIString & ip_port, bool threaded = false) { return listen(PIEthernet::Address(ip_port), threaded); }
|
||||
|
||||
//! Start listen for incoming TCP connections on address "addr". Use only for TCP_Server
|
||||
bool listen(const Address & addr, bool threaded = false);
|
||||
|
||||
PIEthernet * client(int index) {return clients_[index];}
|
||||
int clientsCount() const {return clients_.size_s();}
|
||||
PIVector<PIEthernet * > clients() const {return clients_;}
|
||||
PIEthernet * client(int index) { return clients_[index]; }
|
||||
int clientsCount() const { return clients_.size_s(); }
|
||||
PIVector<PIEthernet *> clients() const { return clients_; }
|
||||
|
||||
|
||||
|
||||
//! Send data "data" with size "size" to address \a sendAddress() for UDP or \a readAddress() for TCP_Client
|
||||
bool send(const void * data, int size, bool threaded = false);
|
||||
|
||||
|
||||
//! Send data "data" with size "size" to address "ip":"port"
|
||||
bool send(const PIString & ip, int port, const void * data, int size, bool threaded = false) {return send(PIEthernet::Address(ip, port), data, size, threaded);}
|
||||
|
||||
bool send(const PIString & ip, int port, const void * data, int size, bool threaded = false) {
|
||||
return send(PIEthernet::Address(ip, port), data, size, threaded);
|
||||
}
|
||||
|
||||
//! Send data "data" with size "size" to address "ip_port"
|
||||
bool send(const PIString & ip_port, const void * data, int size, bool threaded = false) {return send(PIEthernet::Address(ip_port), data, size, threaded);}
|
||||
bool send(const PIString & ip_port, const void * data, int size, bool threaded = false) {
|
||||
return send(PIEthernet::Address(ip_port), data, size, threaded);
|
||||
}
|
||||
|
||||
//! Send data "data" with size "size" to address "addr"
|
||||
bool send(const Address & addr, const void * data, int size, bool threaded = false);
|
||||
|
||||
|
||||
//! Send data "data" to address \a sendAddress() for UDP or \a readAddress() for TCP_Client
|
||||
bool send(const PIByteArray & data, bool threaded = false);
|
||||
|
||||
|
||||
//! Send data "data" to address "ip":"port" for UDP
|
||||
bool send(const PIString & ip, int port, const PIByteArray & data, bool threaded = false) {return send(PIEthernet::Address(ip, port), data, threaded);}
|
||||
|
||||
bool send(const PIString & ip, int port, const PIByteArray & data, bool threaded = false) {
|
||||
return send(PIEthernet::Address(ip, port), data, threaded);
|
||||
}
|
||||
|
||||
//! Send data "data" to address "ip_port" for UDP
|
||||
bool send(const PIString & ip_port, const PIByteArray & data, bool threaded = false) {return send(PIEthernet::Address(ip_port), data, threaded);}
|
||||
bool send(const PIString & ip_port, const PIByteArray & data, bool threaded = false) {
|
||||
return send(PIEthernet::Address(ip_port), data, threaded);
|
||||
}
|
||||
|
||||
//! Send data "data" to address "addr" for UDP
|
||||
bool send(const Address & addr, const PIByteArray & data, bool threaded = false);
|
||||
|
||||
bool canWrite() const override {return mode() & WriteOnly;}
|
||||
|
||||
bool canWrite() const override { return mode() & WriteOnly; }
|
||||
|
||||
void interrupt() override;
|
||||
|
||||
int socket() const {return sock;}
|
||||
|
||||
EVENT1(newConnection, PIEthernet * , client);
|
||||
int socket() const { return sock; }
|
||||
|
||||
EVENT1(newConnection, PIEthernet *, client);
|
||||
EVENT0(connected);
|
||||
EVENT1(disconnected, bool, withError);
|
||||
|
||||
|
||||
|
||||
|
||||
//! Flags of network interface
|
||||
enum InterfaceFlag {
|
||||
ifActive /** Is active */ = 0x1,
|
||||
ifRunning /** Is running */ = 0x2,
|
||||
ifActive /** Is active */ = 0x1,
|
||||
ifRunning /** Is running */ = 0x2,
|
||||
ifBroadcast /** Support broadcast */ = 0x4,
|
||||
ifMulticast /** Support multicast */ = 0x8,
|
||||
ifLoopback /** Is loopback */ = 0x10,
|
||||
ifPTP /** Is point-to-point */ = 0x20
|
||||
ifLoopback /** Is loopback */ = 0x10,
|
||||
ifPTP /** Is point-to-point */ = 0x20
|
||||
};
|
||||
|
||||
|
||||
//! %PIFlags of network interface flags
|
||||
typedef PIFlags<InterfaceFlag> InterfaceFlags;
|
||||
|
||||
|
||||
|
||||
|
||||
//! Network interface descriptor
|
||||
struct PIP_EXPORT Interface {
|
||||
|
||||
//! System index
|
||||
int index;
|
||||
|
||||
|
||||
//! MTU
|
||||
int mtu;
|
||||
|
||||
|
||||
//! System name
|
||||
PIString name;
|
||||
|
||||
|
||||
//! MAC address in format "hh:hh:hh:hh:hh:hh" or empty if there is no MAC address
|
||||
PIString mac;
|
||||
|
||||
|
||||
//! IP address in format "i.i.i.i" or empty if there is no IP address
|
||||
PIString address;
|
||||
|
||||
|
||||
//! Netmask of IP address in format "i.i.i.i" or empty if there is no netmask
|
||||
PIString netmask;
|
||||
|
||||
|
||||
//! Broadcast address in format "i.i.i.i" or empty if there is no broadcast address
|
||||
PIString broadcast;
|
||||
|
||||
|
||||
//! Point-to-point address or empty if there is no point-to-point address
|
||||
PIString ptp;
|
||||
|
||||
|
||||
//! Flags of interface
|
||||
InterfaceFlags flags;
|
||||
|
||||
|
||||
//! Returns if interface is active
|
||||
bool isActive() const {return flags[PIEthernet::ifActive];}
|
||||
|
||||
bool isActive() const { return flags[PIEthernet::ifActive]; }
|
||||
|
||||
//! Returns if interface is running
|
||||
bool isRunning() const {return flags[PIEthernet::ifRunning];}
|
||||
|
||||
bool isRunning() const { return flags[PIEthernet::ifRunning]; }
|
||||
|
||||
//! Returns if interface support broadcast
|
||||
bool isBroadcast() const {return flags[PIEthernet::ifBroadcast];}
|
||||
|
||||
bool isBroadcast() const { return flags[PIEthernet::ifBroadcast]; }
|
||||
|
||||
//! Returns if interface support multicast
|
||||
bool isMulticast() const {return flags[PIEthernet::ifMulticast];}
|
||||
|
||||
bool isMulticast() const { return flags[PIEthernet::ifMulticast]; }
|
||||
|
||||
//! Returns if interface is loopback
|
||||
bool isLoopback() const {return flags[PIEthernet::ifLoopback];}
|
||||
|
||||
bool isLoopback() const { return flags[PIEthernet::ifLoopback]; }
|
||||
|
||||
//! Returns if interface is point-to-point
|
||||
bool isPTP() const {return flags[PIEthernet::ifPTP];}
|
||||
bool isPTP() const { return flags[PIEthernet::ifPTP]; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//! Array of \a Interface with some features
|
||||
class PIP_EXPORT InterfaceList: public PIVector<PIEthernet::Interface> {
|
||||
public:
|
||||
InterfaceList(): PIVector<PIEthernet::Interface>() {}
|
||||
|
||||
|
||||
//! Get interface with system index "index" or 0 if there is no one
|
||||
const Interface * getByIndex(int index) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].index == index) return &((*this)[i]); return 0;}
|
||||
|
||||
const Interface * getByIndex(int index) const {
|
||||
for (int i = 0; i < size_s(); ++i)
|
||||
if ((*this)[i].index == index) return &((*this)[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get interface with system name "name" or 0 if there is no one
|
||||
const Interface * getByName(const PIString & name) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].name == name) return &((*this)[i]); return 0;}
|
||||
|
||||
const Interface * getByName(const PIString & name) const {
|
||||
for (int i = 0; i < size_s(); ++i)
|
||||
if ((*this)[i].name == name) return &((*this)[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get interface with IP address "address" or 0 if there is no one
|
||||
const Interface * getByAddress(const PIString & address) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].address == address) return &((*this)[i]); return 0;}
|
||||
|
||||
const Interface * getByAddress(const PIString & address) const {
|
||||
for (int i = 0; i < size_s(); ++i)
|
||||
if ((*this)[i].address == address) return &((*this)[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get loopback interface or 0 if there is no one
|
||||
const Interface * getLoopback() const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].isLoopback()) return &((*this)[i]); return 0;}
|
||||
const Interface * getLoopback() const {
|
||||
for (int i = 0; i < size_s(); ++i)
|
||||
if ((*this)[i].isLoopback()) return &((*this)[i]);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//! Returns all system network interfaces
|
||||
static InterfaceList interfaces();
|
||||
|
||||
|
||||
static PIEthernet::Address interfaceAddress(const PIString & interface_);
|
||||
|
||||
|
||||
//! Returns all system network IP addresses
|
||||
static PIVector<PIEthernet::Address> allAddresses();
|
||||
|
||||
static PIString macFromBytes(const PIByteArray & mac);
|
||||
static PIByteArray macToBytes(const PIString & mac);
|
||||
static PIString applyMask(const PIString & ip, const PIString & mask);
|
||||
static Address applyMask(const Address & ip, const Address & mask);
|
||||
static Address applyMask(const Address & ip, const Address & mask);
|
||||
static PIString getBroadcast(const PIString & ip, const PIString & mask);
|
||||
static Address getBroadcast(const Address & ip, const Address & mask);
|
||||
static Address getBroadcast(const Address & ip, const Address & mask);
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void newConnection(PIEthernet * client)
|
||||
//! \brief Raise on new TCP connection received
|
||||
|
||||
|
||||
//! \fn void connected()
|
||||
//! \brief Raise if succesfull TCP connection
|
||||
|
||||
@@ -439,32 +490,32 @@ public:
|
||||
#ifdef DOXYGEN
|
||||
//! \brief read ip, default ""
|
||||
string ip;
|
||||
|
||||
|
||||
//! \brief read port, default 0
|
||||
int port;
|
||||
|
||||
|
||||
//! \brief ethernet parameters
|
||||
int parameters;
|
||||
|
||||
|
||||
//! \brief read timeout, default 1000 ms
|
||||
double readTimeout;
|
||||
|
||||
|
||||
//! \brief write timeout, default 1000 ms
|
||||
double writeTimeout;
|
||||
|
||||
|
||||
//! \brief time-to-live, default 64
|
||||
int TTL;
|
||||
|
||||
|
||||
//! \brief time-to-live for multicast, default 1
|
||||
int multicastTTL;
|
||||
#endif
|
||||
//! \}
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
explicit PIEthernet(int sock, PIString ip_port);
|
||||
|
||||
void propertyChanged(const char * name) override;
|
||||
|
||||
|
||||
PIString constructFullPathDevice() const override;
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
@@ -475,7 +526,7 @@ protected:
|
||||
DeviceInfoFlags deviceInfoFlags() const override;
|
||||
|
||||
//! Executes when any read function was successful. Default implementation does nothing
|
||||
virtual void received(const void * data, int size) {;}
|
||||
virtual void received(const void * data, int size) { ; }
|
||||
|
||||
void construct();
|
||||
bool init();
|
||||
@@ -485,7 +536,7 @@ protected:
|
||||
void applyTimeouts();
|
||||
void applyTimeout(int fd, int opt, double ms);
|
||||
void applyOptInt(int level, int opt, int val);
|
||||
|
||||
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
int sock, sock_s;
|
||||
std::atomic_bool connected_, connecting_, listen_threaded, server_bounded;
|
||||
@@ -493,7 +544,7 @@ protected:
|
||||
Type eth_type;
|
||||
PIThread server_thread_;
|
||||
PIMutex clients_mutex;
|
||||
PIVector<PIEthernet * > clients_;
|
||||
PIVector<PIEthernet *> clients_;
|
||||
PIQueue<PIString> mcast_queue;
|
||||
PIStringList mcast_groups;
|
||||
PIFlags<PIEthernet::Parameters> params;
|
||||
@@ -518,15 +569,30 @@ private:
|
||||
static int ethSetsockoptBool(int sock, int level, int optname, bool value = true);
|
||||
static void ethNonblocking(int sock);
|
||||
static bool ethIsWriteable(int sock);
|
||||
|
||||
};
|
||||
|
||||
inline bool operator <(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {return (v0.name < v1.name);}
|
||||
inline bool operator ==(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {return (v0.name == v1.name && v0.address == v1.address && v0.netmask == v1.netmask);}
|
||||
inline bool operator !=(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {return (v0.name != v1.name || v0.address != v1.address || v0.netmask != v1.netmask);}
|
||||
inline PICout operator <<(PICout s, const PIEthernet::Address & v) {s.space(); s.saveAndSetControls(0); s << "Address(" << v.toString() << ")"; s.restoreControls(); return s;}
|
||||
inline bool operator<(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {
|
||||
return (v0.name < v1.name);
|
||||
}
|
||||
inline bool operator==(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {
|
||||
return (v0.name == v1.name && v0.address == v1.address && v0.netmask == v1.netmask);
|
||||
}
|
||||
inline bool operator!=(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {
|
||||
return (v0.name != v1.name || v0.address != v1.address || v0.netmask != v1.netmask);
|
||||
}
|
||||
inline PICout operator<<(PICout s, const PIEthernet::Address & v) {
|
||||
s.space();
|
||||
s.saveAndSetControls(0);
|
||||
s << "Address(" << v.toString() << ")";
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
inline bool operator ==(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {return (v0.ip() == v1.ip() && v0.port() == v1.port());}
|
||||
inline bool operator !=(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {return (v0.ip() != v1.ip() || v0.port() != v1.port());}
|
||||
inline bool operator==(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {
|
||||
return (v0.ip() == v1.ip() && v0.port() == v1.port());
|
||||
}
|
||||
inline bool operator!=(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {
|
||||
return (v0.ip() != v1.ip() || v0.port() != v1.port());
|
||||
}
|
||||
|
||||
#endif // PIETHERNET_H
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "pifile.h"
|
||||
|
||||
#include "pidir.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piiostream.h"
|
||||
#include "pitime_win.h"
|
||||
#ifdef WINDOWS
|
||||
@@ -36,38 +37,38 @@
|
||||
# define S_IFCHR 0x10
|
||||
# define S_IFSOCK 0x20
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/time.h>
|
||||
# include <fcntl.h>
|
||||
# include <utime.h>
|
||||
#endif
|
||||
#define S_IFHDN 0x40
|
||||
#define S_IFHDN 0x40
|
||||
#if defined(QNX) || defined(ANDROID) || defined(FREERTOS)
|
||||
# define _fopen_call_ fopen
|
||||
# define _fseek_call_ fseek
|
||||
# define _ftell_call_ ftell
|
||||
# define _stat_struct_ struct stat
|
||||
# define _stat_call_ stat
|
||||
# define _stat_link_ lstat
|
||||
# define _fopen_call_ fopen
|
||||
# define _fseek_call_ fseek
|
||||
# define _ftell_call_ ftell
|
||||
# define _stat_struct_ struct stat
|
||||
# define _stat_call_ stat
|
||||
# define _stat_link_ lstat
|
||||
#else
|
||||
# if defined(MAC_OS)
|
||||
# define _fopen_call_ fopen
|
||||
# define _fseek_call_ fseek
|
||||
# define _ftell_call_ ftell
|
||||
# define _fopen_call_ fopen
|
||||
# define _fseek_call_ fseek
|
||||
# define _ftell_call_ ftell
|
||||
# else
|
||||
# ifdef CC_GCC
|
||||
# define _fopen_call_ fopen64
|
||||
# define _fseek_call_ fseeko64
|
||||
# define _ftell_call_ ftello64
|
||||
# else
|
||||
# define _fopen_call_ fopen
|
||||
# define _fseek_call_ fseek
|
||||
# define _ftell_call_ ftell
|
||||
# endif
|
||||
# ifdef CC_GCC
|
||||
# define _fopen_call_ fopen64
|
||||
# define _fseek_call_ fseeko64
|
||||
# define _ftell_call_ ftello64
|
||||
# else
|
||||
# define _fopen_call_ fopen
|
||||
# define _fseek_call_ fseek
|
||||
# define _ftell_call_ ftell
|
||||
# endif
|
||||
# endif
|
||||
# define _stat_struct_ struct stat64
|
||||
# define _stat_call_ stat64
|
||||
# define _stat_link_ lstat64
|
||||
# define _stat_struct_ struct stat64
|
||||
# define _stat_call_ stat64
|
||||
# define _stat_link_ lstat64
|
||||
#endif
|
||||
|
||||
|
||||
@@ -152,10 +153,7 @@ PIString PIFile::FileInfo::dir() const {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIFile::PIFile(): PIIODevice() {
|
||||
}
|
||||
PIFile::PIFile(): PIIODevice() {}
|
||||
|
||||
|
||||
PIFile::PIFile(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode) {
|
||||
@@ -196,7 +194,7 @@ bool PIFile::openDevice() {
|
||||
}
|
||||
}
|
||||
PRIVATE->fd = _fopen_call_(p.data(), strType(mode_).data());
|
||||
//piCout << "fopen " << path() << ": " << strType(mode_).data() << PRIVATE->fd;
|
||||
// piCout << "fopen " << path() << ": " << strType(mode_).data() << PRIVATE->fd;
|
||||
bool opened = (PRIVATE->fd != 0);
|
||||
if (opened) {
|
||||
fdi = fileno(PRIVATE->fd);
|
||||
@@ -210,19 +208,19 @@ bool PIFile::openDevice() {
|
||||
_fseek_call_(PRIVATE->fd, 0, SEEK_SET);
|
||||
clearerr(PRIVATE->fd);
|
||||
}
|
||||
//piCout << "open file" << PRIVATE->fd << opened_;
|
||||
// piCout << "open file" << PRIVATE->fd << opened_;
|
||||
return opened;
|
||||
}
|
||||
|
||||
|
||||
bool PIFile::closeDevice() {
|
||||
//piCout << "close file" << PRIVATE->fd << opened_;
|
||||
// piCout << "close file" << PRIVATE->fd << opened_;
|
||||
if (isClosed() || PRIVATE->fd == 0) return true;
|
||||
bool cs = (fclose(PRIVATE->fd) == 0);
|
||||
if (cs) PRIVATE->fd = 0;
|
||||
fdi = -1;
|
||||
fdi = -1;
|
||||
_size = -1;
|
||||
//piCout << "closed file" << PRIVATE->fd << opened_;
|
||||
// piCout << "closed file" << PRIVATE->fd << opened_;
|
||||
return cs;
|
||||
}
|
||||
|
||||
@@ -232,9 +230,9 @@ llong PIFile::readAll(void * data) {
|
||||
seekToBegin();
|
||||
if (s < 0) {
|
||||
while (!isEnd())
|
||||
read(&(((char*)data)[++i]), 1);
|
||||
read(&(((char *)data)[++i]), 1);
|
||||
} else
|
||||
read((char * )data, s);
|
||||
read((char *)data, s);
|
||||
seek(cp);
|
||||
return s;
|
||||
}
|
||||
@@ -264,9 +262,11 @@ PIByteArray PIFile::readAll(bool forceRead) {
|
||||
llong PIFile::size() const {
|
||||
if (isClosed()) return -1;
|
||||
llong s, cp = pos();
|
||||
_fseek_call_(PRIVATE->fd, 0, SEEK_END); clearerr(PRIVATE->fd);
|
||||
_fseek_call_(PRIVATE->fd, 0, SEEK_END);
|
||||
clearerr(PRIVATE->fd);
|
||||
s = pos();
|
||||
_fseek_call_(PRIVATE->fd, cp, SEEK_SET); clearerr(PRIVATE->fd);
|
||||
_fseek_call_(PRIVATE->fd, cp, SEEK_SET);
|
||||
clearerr(PRIVATE->fd);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -289,10 +289,9 @@ void PIFile::resize(llong new_size, uchar fill_) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PIFile::isExists(const PIString & path) {
|
||||
FILE * f = _fopen_call_(PIString(path).data(), "r");
|
||||
bool ok = (f != 0);
|
||||
bool ok = (f != 0);
|
||||
if (ok) fclose(f);
|
||||
return ok;
|
||||
}
|
||||
@@ -304,7 +303,7 @@ bool PIFile::remove(const PIString & path) {
|
||||
return RemoveDirectoryA(path.data()) > 0;
|
||||
else
|
||||
#endif
|
||||
return ::remove(path.data()) == 0;
|
||||
return ::remove(path.data()) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -378,7 +377,7 @@ void PIFile::seekToLine(llong line) {
|
||||
if (isClosed()) return;
|
||||
seekToBegin();
|
||||
PIIOTextStream ts(this);
|
||||
piForTimes (line) ts.readLine();
|
||||
piForTimes(line) ts.readLine();
|
||||
clearerr(PRIVATE->fd);
|
||||
}
|
||||
|
||||
@@ -410,8 +409,7 @@ bool PIFile::isEnd() const {
|
||||
if (isClosed()) return true;
|
||||
bool ret = (feof(PRIVATE->fd) || ferror(PRIVATE->fd));
|
||||
if (!ret && (_size >= 0)) {
|
||||
if (pos() > _size)
|
||||
ret = true;
|
||||
if (pos() > _size) ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -455,7 +453,7 @@ void PIFile::clear() {
|
||||
PRIVATE->fd = fopen(path().data(), "w");
|
||||
if (PRIVATE->fd != 0) fclose(PRIVATE->fd);
|
||||
PRIVATE->fd = 0;
|
||||
opened_ = false;
|
||||
opened_ = false;
|
||||
open();
|
||||
}
|
||||
|
||||
@@ -466,14 +464,12 @@ void PIFile::remove() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIFile::FileInfo PIFile::fileInfo(const PIString & path) {
|
||||
FileInfo ret;
|
||||
if (path.isEmpty()) return ret;
|
||||
ret.path = path.replacedAll("\\", PIDir::separator);
|
||||
ret.path = path.replacedAll("\\", PIDir::separator);
|
||||
PIString n = ret.name();
|
||||
//piCout << "open" << path;
|
||||
// piCout << "open" << path;
|
||||
#ifdef WINDOWS
|
||||
DWORD attr = GetFileAttributesA((LPCSTR)(path.data()));
|
||||
if (attr == 0xFFFFFFFF) return ret;
|
||||
@@ -490,51 +486,53 @@ PIFile::FileInfo PIFile::fileInfo(const PIString & path) {
|
||||
LARGE_INTEGER filesize;
|
||||
filesize.LowPart = filesize.HighPart = 0;
|
||||
if (fi.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ret.flags |= FileInfo::Hidden;
|
||||
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ret.flags |= FileInfo::Dir;
|
||||
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
ret.flags |= FileInfo::Dir;
|
||||
else {
|
||||
ret.flags |= FileInfo::File;
|
||||
filesize.LowPart = fi.nFileSizeLow;
|
||||
filesize.LowPart = fi.nFileSizeLow;
|
||||
filesize.HighPart = fi.nFileSizeHigh;
|
||||
}
|
||||
PIString ext = ret.extension();
|
||||
ret.perm_user = FileInfo::Permissions(true, (attr & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY, ext == "bat" || ext == "exe");
|
||||
ret.perm_user =
|
||||
FileInfo::Permissions(true, (attr & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY, ext == "bat" || ext == "exe");
|
||||
ret.perm_group = ret.perm_other = ret.perm_user;
|
||||
ret.size = filesize.QuadPart;
|
||||
ret.time_access = FILETIME2PIDateTime(fi.ftLastAccessTime);
|
||||
ret.time_modification = FILETIME2PIDateTime(fi.ftLastWriteTime);
|
||||
ret.size = filesize.QuadPart;
|
||||
ret.time_access = FILETIME2PIDateTime(fi.ftLastAccessTime);
|
||||
ret.time_modification = FILETIME2PIDateTime(fi.ftLastWriteTime);
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
#else
|
||||
_stat_struct_ fs;
|
||||
memset(&fs, 0, sizeof(fs));
|
||||
_stat_call_(path.data(), &fs);
|
||||
int mode = fs.st_mode;
|
||||
ret.size = fs.st_size;
|
||||
ret.id_user = fs.st_uid;
|
||||
ret.id_group = fs.st_gid;
|
||||
#ifdef ANDROID
|
||||
ret.time_access = PIDateTime::fromSystemTime(PISystemTime(fs.st_atime, fs.st_atime_nsec));
|
||||
int mode = fs.st_mode;
|
||||
ret.size = fs.st_size;
|
||||
ret.id_user = fs.st_uid;
|
||||
ret.id_group = fs.st_gid;
|
||||
# ifdef ANDROID
|
||||
ret.time_access = PIDateTime::fromSystemTime(PISystemTime(fs.st_atime, fs.st_atime_nsec));
|
||||
ret.time_modification = PIDateTime::fromSystemTime(PISystemTime(fs.st_mtime, fs.st_mtime_nsec));
|
||||
#else
|
||||
# if defined(QNX) || defined(FREERTOS)
|
||||
ret.time_access = PIDateTime::fromSecondSinceEpoch(fs.st_atime);
|
||||
ret.time_modification = PIDateTime::fromSecondSinceEpoch(fs.st_mtime);
|
||||
# else
|
||||
# ifdef MAC_OS
|
||||
# define ATIME st_atimespec
|
||||
# define MTIME st_ctimespec
|
||||
# else
|
||||
# define ATIME st_atim
|
||||
# define MTIME st_mtim
|
||||
# endif
|
||||
ret.time_access = PIDateTime::fromSystemTime(PISystemTime(fs.ATIME.tv_sec, fs.ATIME.tv_nsec));
|
||||
# if defined(QNX) || defined(FREERTOS)
|
||||
ret.time_access = PIDateTime::fromSecondSinceEpoch(fs.st_atime);
|
||||
ret.time_modification = PIDateTime::fromSecondSinceEpoch(fs.st_mtime);
|
||||
# else
|
||||
# ifdef MAC_OS
|
||||
# define ATIME st_atimespec
|
||||
# define MTIME st_ctimespec
|
||||
# else
|
||||
# define ATIME st_atim
|
||||
# define MTIME st_mtim
|
||||
# endif
|
||||
ret.time_access = PIDateTime::fromSystemTime(PISystemTime(fs.ATIME.tv_sec, fs.ATIME.tv_nsec));
|
||||
ret.time_modification = PIDateTime::fromSystemTime(PISystemTime(fs.MTIME.tv_sec, fs.MTIME.tv_nsec));
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#ifndef MICRO_PIP
|
||||
ret.perm_user = FileInfo::Permissions((mode & S_IRUSR) == S_IRUSR, (mode & S_IWUSR) == S_IWUSR, (mode & S_IXUSR) == S_IXUSR);
|
||||
ret.perm_group = FileInfo::Permissions((mode & S_IRGRP) == S_IRGRP, (mode & S_IWGRP) == S_IWGRP, (mode & S_IXGRP) == S_IXGRP);
|
||||
ret.perm_other = FileInfo::Permissions((mode & S_IROTH) == S_IROTH, (mode & S_IWOTH) == S_IWOTH, (mode & S_IXOTH) == S_IXOTH);
|
||||
# ifndef MICRO_PIP
|
||||
ret.perm_user = FileInfo::Permissions((mode & S_IRUSR) == S_IRUSR, (mode & S_IWUSR) == S_IWUSR, (mode & S_IXUSR) == S_IXUSR);
|
||||
ret.perm_group = FileInfo::Permissions((mode & S_IRGRP) == S_IRGRP, (mode & S_IWGRP) == S_IWGRP, (mode & S_IXGRP) == S_IXGRP);
|
||||
ret.perm_other = FileInfo::Permissions((mode & S_IROTH) == S_IROTH, (mode & S_IWOTH) == S_IWOTH, (mode & S_IXOTH) == S_IXOTH);
|
||||
memset(&fs, 0, sizeof(fs));
|
||||
_stat_link_(path.data(), &fs);
|
||||
mode &= ~S_IFLNK;
|
||||
@@ -544,7 +542,7 @@ PIFile::FileInfo PIFile::fileInfo(const PIString & path) {
|
||||
if ((mode & S_IFREG) == S_IFREG) ret.flags |= FileInfo::File;
|
||||
if ((mode & S_IFLNK) == S_IFLNK) ret.flags |= FileInfo::SymbolicLink;
|
||||
if ((mode & S_IFHDN) == S_IFHDN) ret.flags |= FileInfo::Hidden;
|
||||
#endif
|
||||
# endif
|
||||
#endif
|
||||
if (n == ".") ret.flags = FileInfo::Dir | FileInfo::Dot;
|
||||
if (n == "..") ret.flags = FileInfo::Dir | FileInfo::DotDot;
|
||||
@@ -567,7 +565,13 @@ bool PIFile::applyFileInfo(const PIString & path, const PIFile::FileInfo & info)
|
||||
}
|
||||
HANDLE hFile = 0;
|
||||
if ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
|
||||
hFile = CreateFileA(path.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
hFile = CreateFileA(path.data(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
0);
|
||||
} else {
|
||||
hFile = CreateFileA(path.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
|
||||
}
|
||||
@@ -580,15 +584,15 @@ bool PIFile::applyFileInfo(const PIString & path, const PIFile::FileInfo & info)
|
||||
CloseHandle(hFile);
|
||||
#else
|
||||
int mode(0);
|
||||
if (info.perm_user.read) mode |= S_IRUSR;
|
||||
if (info.perm_user.write) mode |= S_IWUSR;
|
||||
if (info.perm_user.exec) mode |= S_IXUSR;
|
||||
if (info.perm_group.read) mode |= S_IRGRP;
|
||||
if (info.perm_user.read) mode |= S_IRUSR;
|
||||
if (info.perm_user.write) mode |= S_IWUSR;
|
||||
if (info.perm_user.exec) mode |= S_IXUSR;
|
||||
if (info.perm_group.read) mode |= S_IRGRP;
|
||||
if (info.perm_group.write) mode |= S_IWGRP;
|
||||
if (info.perm_group.exec) mode |= S_IXGRP;
|
||||
if (info.perm_other.read) mode |= S_IROTH;
|
||||
if (info.perm_group.exec) mode |= S_IXGRP;
|
||||
if (info.perm_other.read) mode |= S_IROTH;
|
||||
if (info.perm_other.write) mode |= S_IWOTH;
|
||||
if (info.perm_other.exec) mode |= S_IXOTH;
|
||||
if (info.perm_other.exec) mode |= S_IXOTH;
|
||||
if (chmod(fp.data(), mode) != 0) {
|
||||
piCout << "[PIFile] applyFileInfo: \"chmod\" error:" << errorString();
|
||||
}
|
||||
@@ -597,11 +601,11 @@ bool PIFile::applyFileInfo(const PIString & path, const PIFile::FileInfo & info)
|
||||
}
|
||||
struct timeval tm[2];
|
||||
PISystemTime st = info.time_access.toSystemTime();
|
||||
tm[0].tv_sec = st.seconds;
|
||||
tm[0].tv_usec = st.nanoseconds / 1000;
|
||||
st = info.time_modification.toSystemTime();
|
||||
tm[1].tv_sec = st.seconds;
|
||||
tm[1].tv_usec = st.nanoseconds / 1000;
|
||||
tm[0].tv_sec = st.seconds;
|
||||
tm[0].tv_usec = st.nanoseconds / 1000;
|
||||
st = info.time_modification.toSystemTime();
|
||||
tm[1].tv_sec = st.seconds;
|
||||
tm[1].tv_usec = st.nanoseconds / 1000;
|
||||
if (utimes(fp.data(), tm) != 0) {
|
||||
piCout << "[PIFile] applyFileInfo: \"utimes\" error:" << errorString();
|
||||
}
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Локальный файл
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIFILE_H
|
||||
@@ -34,11 +34,10 @@
|
||||
//! \~\brief
|
||||
//! \~english Local file.
|
||||
//! \~russian Локальный файл.
|
||||
class PIP_EXPORT PIFile: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIFile: public PIIODevice {
|
||||
PIIODEVICE(PIFile, "file");
|
||||
|
||||
public:
|
||||
|
||||
//! \~english Constructs file with empty path
|
||||
//! \~russian Создает файл с пустым путём
|
||||
explicit PIFile();
|
||||
@@ -55,20 +54,23 @@ public:
|
||||
//! \~english Local file or directory information.
|
||||
//! \~russian Информация о локальном файле или директории.
|
||||
struct PIP_EXPORT FileInfo {
|
||||
|
||||
//! \~english Constructs %FileInfo with path "path_". No information gathered
|
||||
//! \~russian Создает %FileInfo с путём "path_". Информация не собирается
|
||||
FileInfo(const PIString & path_ = PIString()) {path = path_; size = 0; id_group = id_user = 0;}
|
||||
|
||||
FileInfo(const PIString & path_ = PIString()) {
|
||||
path = path_;
|
||||
size = 0;
|
||||
id_group = id_user = 0;
|
||||
}
|
||||
|
||||
//! \~english Type flags
|
||||
//! \~russian Флаги типа
|
||||
enum Flag {
|
||||
File /*! \~english File \~russian Файл */ = 0x01,
|
||||
Dir /*! \~english Directory \~russian Директория */ = 0x02,
|
||||
Dot /*! \~english '.', current directory \~russian '.', текущая директория */ = 0x04,
|
||||
DotDot /*! \~english '..', parent directory \~russian '..', родительская директория */ = 0x08,
|
||||
SymbolicLink /*! \~english Symbolic link \~russian Символическая ссылка */ = 0x10,
|
||||
Hidden /*! \~english Hidden \~russian Скрытый */ = 0x20
|
||||
File /*! \~english File \~russian Файл */ = 0x01,
|
||||
Dir /*! \~english Directory \~russian Директория */ = 0x02,
|
||||
Dot /*! \~english '.', current directory \~russian '.', текущая директория */ = 0x04,
|
||||
DotDot /*! \~english '..', parent directory \~russian '..', родительская директория */ = 0x08,
|
||||
SymbolicLink /*! \~english Symbolic link \~russian Символическая ссылка */ = 0x10,
|
||||
Hidden /*! \~english Hidden \~russian Скрытый */ = 0x20
|
||||
};
|
||||
typedef PIFlags<FileInfo::Flag> Flags;
|
||||
|
||||
@@ -78,16 +80,23 @@ public:
|
||||
//! \~russian Разрешения локального файла или директории.
|
||||
struct PIP_EXPORT Permissions {
|
||||
Permissions(uchar r = 0): raw(r) {}
|
||||
Permissions(bool r, bool w, bool e): raw(0) {read = r; write = w; exec = e;}
|
||||
Permissions(bool r, bool w, bool e): raw(0) {
|
||||
read = r;
|
||||
write = w;
|
||||
exec = e;
|
||||
}
|
||||
|
||||
//! \~english Returns as string (from "---" to "rwx")
|
||||
//! \~russian Возвращает как строку (от "---" до "rwx")
|
||||
PIString toString() const {return PIString(read ? "r" : "-") + PIString(write ? "w" : "-") + PIString(exec ? "x" : "-");}
|
||||
PIString toString() const { return PIString(read ? "r" : "-") + PIString(write ? "w" : "-") + PIString(exec ? "x" : "-"); }
|
||||
|
||||
//! \~english Convertion to \c int
|
||||
//! \~russian Преобразование в \c int
|
||||
operator int() const {return raw;}
|
||||
Permissions & operator =(int v) {raw = v; return *this;}
|
||||
operator int() const { return raw; }
|
||||
Permissions & operator=(int v) {
|
||||
raw = v;
|
||||
return *this;
|
||||
}
|
||||
union {
|
||||
uchar raw;
|
||||
struct {
|
||||
@@ -97,7 +106,7 @@ public:
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//! \~english Path
|
||||
//! \~russian Путь
|
||||
PIString path;
|
||||
@@ -137,7 +146,7 @@ public:
|
||||
//! \~english Permissions for other
|
||||
//! \~russian Разрешения для остальных
|
||||
Permissions perm_other;
|
||||
|
||||
|
||||
|
||||
//! \~english Returns name, without directory
|
||||
//! \~russian Возвращает имя, без директории
|
||||
@@ -157,43 +166,42 @@ public:
|
||||
|
||||
//! \~english Returns if it`s directory
|
||||
//! \~russian Возвращает директория ли это
|
||||
bool isDir() const {return flags[Dir];}
|
||||
bool isDir() const { return flags[Dir]; }
|
||||
|
||||
//! \~english Returns if it`s file
|
||||
//! \~russian Возвращает файл ли это
|
||||
bool isFile() const {return flags[File];}
|
||||
bool isFile() const { return flags[File]; }
|
||||
|
||||
//! \~english Returns if it`s symbolic link
|
||||
//! \~russian Возвращает символическая ссылка ли это
|
||||
bool isSymbolicLink() const {return flags[SymbolicLink];}
|
||||
bool isSymbolicLink() const { return flags[SymbolicLink]; }
|
||||
|
||||
//! \~english Returns if Hidden flag set
|
||||
//! \~russian Возвращает установлен ли флаг Hidden
|
||||
bool isHidden() const {return flags[Hidden];}
|
||||
|
||||
bool isHidden() const { return flags[Hidden]; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
//! \~english Open temporary file with open mode "mode"
|
||||
//! \~russian Открывает временный файл с режимом открытия "mode"
|
||||
bool openTemporary(PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
|
||||
|
||||
//! \~english Immediate write all buffered data to disk
|
||||
//! \~russian Немедленно записывает все буферизированные данные на диск
|
||||
void flush() override;
|
||||
|
||||
|
||||
//! \~english Move read/write position to "position"
|
||||
//! \~russian Перемещает позицию чтения/записи на "position"
|
||||
void seek(llong position);
|
||||
|
||||
|
||||
//! \~english Move read/write position to the begin of the file
|
||||
//! \~russian Перемещает позицию чтения/записи на начало файла
|
||||
void seekToBegin();
|
||||
|
||||
|
||||
//! \~english Move read/write position to the end of the file
|
||||
//! \~russian Перемещает позицию чтения/записи на конец файла
|
||||
void seekToEnd();
|
||||
|
||||
|
||||
//! \~english Move read/write position to text line number "line" beginning
|
||||
//! \~russian Перемещает позицию чтения/записи на начало текстовой строки номер "line"
|
||||
void seekToLine(llong line);
|
||||
@@ -201,47 +209,47 @@ public:
|
||||
//! \~english Skip "bytes" bytes (move position next to "bytes" bytes)
|
||||
//! \~russian Пропускает "bytes" байт (перемещает позицию на "bytes" байт вперёд)
|
||||
void skip(llong bytes);
|
||||
|
||||
|
||||
//! \~english Read one char and return it
|
||||
//! \~russian Читает один байт и возвращает его
|
||||
char readChar();
|
||||
|
||||
|
||||
|
||||
//! \~english Read all file content to "data" and return readed bytes count. Position leaved unchanged
|
||||
//! \~russian Читает всё содержимое файла в "data" и возвращает количество прочитанных байт. Позиция остаётся неизменной
|
||||
llong readAll(void * data);
|
||||
|
||||
|
||||
//! \~english Read all file content to byte array and return it. Position leaved unchanged
|
||||
//! \~russian Читает всё содержимое файла и возвращает его как массив байтов. Позиция остаётся неизменной
|
||||
PIByteArray readAll(bool forceRead = false);
|
||||
|
||||
|
||||
|
||||
|
||||
//! \~english Set file path to "path" and reopen file if need
|
||||
//! \~russian Устанавливает путь файла на "path" и переоткрывает его при необходимости
|
||||
void setPath(const PIString & path);
|
||||
|
||||
|
||||
//! \~english Returns file size in bytes
|
||||
//! \~russian Возвращает размер файла в байтах
|
||||
llong size() const;
|
||||
|
||||
ssize_t bytesAvailable() const override {return size() - pos();}
|
||||
ssize_t bytesAvailable() const override { return size() - pos(); }
|
||||
|
||||
//! \~english Returns read/write position
|
||||
//! \~russian Возвращает позицию чтения/записи
|
||||
llong pos() const;
|
||||
|
||||
|
||||
//! \~english Returns if position is at the end of file
|
||||
//! \~russian Возвращает достигнут ли конец файла
|
||||
bool isEnd() const;
|
||||
|
||||
|
||||
//! \~english Returns if file is empty
|
||||
//! \~russian Возвращает пустой ли файл
|
||||
bool isEmpty() const {return (size() <= 0);}
|
||||
|
||||
bool isEmpty() const { return (size() <= 0); }
|
||||
|
||||
//! \~english Returns \a PIFile::FileInfo of current file
|
||||
//! \~russian Возвращает \a PIFile::FileInfo текущего файла
|
||||
FileInfo fileInfo() const {return fileInfo(path());}
|
||||
|
||||
FileInfo fileInfo() const { return fileInfo(path()); }
|
||||
|
||||
|
||||
//! \~english Write size and content of "v" (serialize)
|
||||
//! \~russian Пишет в файл размер и содержимое "v" (сериализация)
|
||||
@@ -250,48 +258,48 @@ public:
|
||||
//! \~english Read size of byte array and it content (deserialize)
|
||||
//! \~russian Читает из файла размер байтового массива и его содержимое (десериализация)
|
||||
PIByteArray get();
|
||||
|
||||
|
||||
EVENT_HANDLER(void, clear);
|
||||
EVENT_HANDLER(void, remove);
|
||||
EVENT_HANDLER1(void, resize, llong, new_size) {resize(new_size, 0);}
|
||||
EVENT_HANDLER1(void, resize, llong, new_size) { resize(new_size, 0); }
|
||||
EVENT_HANDLER2(void, resize, llong, new_size, uchar, fill);
|
||||
|
||||
|
||||
|
||||
//! \~english Returns if file with path "path" exists
|
||||
//! \~russian Возвращает существует ли файл с путём "path"
|
||||
static bool isExists(const PIString & path);
|
||||
|
||||
|
||||
//! \~english Remove file with path "path" and returns if remove successful
|
||||
//! \~russian Удаляет файл с путём "path" и возвращает успешность операции
|
||||
static bool remove(const PIString & path);
|
||||
|
||||
|
||||
//! \~english Rename file with path "from" to path "to" and returns if rename successful
|
||||
//! \~russian Переименовывает файл с путём "path" на "to" и возвращает успешность операции
|
||||
static bool rename(const PIString & from, const PIString & to);
|
||||
|
||||
|
||||
//! \~english Returns \a PIFile::FileInfo of file or dir with path "path"
|
||||
//! \~russian Возвращает \a PIFile::FileInfo файла или директории с путём "path"
|
||||
static FileInfo fileInfo(const PIString & path);
|
||||
|
||||
|
||||
//! \~english Apply "info" parameters to file or dir with path "path"
|
||||
//! \~russian Применяет параметры "info" к файлу или директории с путём "path"
|
||||
static bool applyFileInfo(const PIString & path, const FileInfo & info);
|
||||
|
||||
|
||||
//! \~english Apply "info" parameters to file or dir with path "info".path
|
||||
//! \~russian Применяет параметры "info" к файлу или директории с путём "info".path
|
||||
static bool applyFileInfo(const FileInfo & info) {return applyFileInfo(info.path, info);}
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
static bool applyFileInfo(const FileInfo & info) { return applyFileInfo(info.path, info); }
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void clear()
|
||||
//! \~english Clear content of file
|
||||
//! \~russian Очищает содержимое файла
|
||||
|
||||
|
||||
//! \fn void resize(llong new_size)
|
||||
//! \~english Resize file to "new_size" with null-byte fill
|
||||
//! \~russian Изменяет размер файла на "new_size" с заполнением нулевыми байтами
|
||||
|
||||
|
||||
//! \fn void resize(llong new_size, uchar fill)
|
||||
//! \~english Resize file to "new_size" with "fill" fill
|
||||
//! \~russian Изменяет размер файла на "new_size" с заполнением байтами "fill"
|
||||
@@ -305,7 +313,7 @@ public:
|
||||
//! \{
|
||||
#ifdef DOXYGEN
|
||||
#endif
|
||||
//! \}
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
PIString constructFullPathDevice() const override;
|
||||
@@ -316,28 +324,26 @@ protected:
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Sequential | PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Sequential | PIIODevice::Reliable; }
|
||||
|
||||
private:
|
||||
PIString strType(const PIIODevice::DeviceMode type);
|
||||
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
int fdi = -1;
|
||||
int fdi = -1;
|
||||
llong _size = -1;
|
||||
PIString prec_str;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PICout
|
||||
//! \~english Output operator to \a PICout
|
||||
//! \~russian Оператор вывода в \a PICout
|
||||
inline PICout operator <<(PICout s, const PIFile::FileInfo & v) {
|
||||
inline PICout operator<<(PICout s, const PIFile::FileInfo & v) {
|
||||
s.saveAndSetControls(0);
|
||||
s << "FileInfo(\"" << v.path << "\", " << PIString::readableSize(v.size) << ", "
|
||||
<< v.perm_user.toString() << " " << v.perm_group.toString() << " " << v.perm_other.toString() << ", "
|
||||
<< v.time_access.toString() << ", " << v.time_modification.toString()
|
||||
<< ", 0x" << PICoutManipulators::Hex << v.flags << ")";
|
||||
s << "FileInfo(\"" << v.path << "\", " << PIString::readableSize(v.size) << ", " << v.perm_user.toString() << " "
|
||||
<< v.perm_group.toString() << " " << v.perm_other.toString() << ", " << v.time_access.toString() << ", "
|
||||
<< v.time_modification.toString() << ", 0x" << PICoutManipulators::Hex << v.flags << ")";
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
@@ -347,8 +353,8 @@ inline PICout operator <<(PICout s, const PIFile::FileInfo & v) {
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIFile::FileInfo) {
|
||||
s << v.path << v.size << v.time_access << v.time_modification <<
|
||||
v.flags << v.id_user << v.id_group << v.perm_user.raw << v.perm_group.raw << v.perm_other.raw;
|
||||
s << v.path << v.size << v.time_access << v.time_modification << v.flags << v.id_user << v.id_group << v.perm_user.raw
|
||||
<< v.perm_group.raw << v.perm_other.raw;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -356,8 +362,8 @@ BINARY_STREAM_WRITE(PIFile::FileInfo) {
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ(PIFile::FileInfo) {
|
||||
s >> v.path >> v.size >> v.time_access >> v.time_modification >>
|
||||
v.flags >> v.id_user >> v.id_group >> v.perm_user.raw >> v.perm_group.raw >> v.perm_other.raw;
|
||||
s >> v.path >> v.size >> v.time_access >> v.time_modification >> v.flags >> v.id_user >> v.id_group >> v.perm_user.raw >>
|
||||
v.perm_group.raw >> v.perm_other.raw;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
GPIO
|
||||
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
GPIO
|
||||
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pigpio.h"
|
||||
@@ -22,9 +22,9 @@
|
||||
# define GPIO_SYS_CLASS
|
||||
#endif
|
||||
#ifdef GPIO_SYS_CLASS
|
||||
# include <cstdlib>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -64,8 +64,7 @@
|
||||
//!
|
||||
|
||||
|
||||
PIGPIO::PIGPIO(): PIThread() {
|
||||
}
|
||||
PIGPIO::PIGPIO(): PIThread() {}
|
||||
|
||||
|
||||
PIGPIO::~PIGPIO() {
|
||||
@@ -74,7 +73,7 @@ PIGPIO::~PIGPIO() {
|
||||
PIMutexLocker ml(mutex);
|
||||
#ifdef GPIO_SYS_CLASS
|
||||
PIVector<int> ids = gpio_.keys();
|
||||
for(int i = 0; i < ids.size_s(); i++) {
|
||||
for (int i = 0; i < ids.size_s(); i++) {
|
||||
GPIOData & g(gpio_[ids[i]]);
|
||||
if (g.fd != -1) {
|
||||
::close(g.fd);
|
||||
@@ -92,7 +91,6 @@ PIGPIO * PIGPIO::instance() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIString PIGPIO::GPIOName(int gpio_num) {
|
||||
return PIStringAscii("gpio") + PIString::fromNumber(gpio_num);
|
||||
}
|
||||
@@ -101,13 +99,13 @@ PIString PIGPIO::GPIOName(int gpio_num) {
|
||||
void PIGPIO::exportGPIO(int gpio_num) {
|
||||
#ifdef GPIO_SYS_CLASS
|
||||
PIString valfile = "/sys/class/gpio/" + GPIOName(gpio_num) + "/value";
|
||||
int fd = ::open(valfile.dataAscii(), O_RDONLY);
|
||||
int fd = ::open(valfile.dataAscii(), O_RDONLY);
|
||||
if (fd != -1) {
|
||||
::close(fd);
|
||||
return;
|
||||
}
|
||||
int ret = 0;
|
||||
ret = system(PIString("echo " + PIString::fromNumber(gpio_num) + " >> /sys/class/gpio/export").dataAscii());
|
||||
ret = system(PIString("echo " + PIString::fromNumber(gpio_num) + " >> /sys/class/gpio/export").dataAscii());
|
||||
if (ret == 0) {
|
||||
PITimeMeasurer tm;
|
||||
while (tm.elapsed_s() < 1.) {
|
||||
@@ -130,8 +128,8 @@ void PIGPIO::openGPIO(GPIOData & g) {
|
||||
g.fd = -1;
|
||||
}
|
||||
PIString fp = "/sys/class/gpio/" + g.name + "/value";
|
||||
g.fd = ::open(fp.dataAscii(), O_RDWR);
|
||||
//piCoutObj << "initGPIO" << g.num << ":" << fp << g.fd << errorString();
|
||||
g.fd = ::open(fp.dataAscii(), O_RDWR);
|
||||
// piCoutObj << "initGPIO" << g.num << ":" << fp << g.fd << errorString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -139,7 +137,7 @@ void PIGPIO::openGPIO(GPIOData & g) {
|
||||
bool PIGPIO::getPinState(int gpio_num) {
|
||||
#ifdef GPIO_SYS_CLASS
|
||||
GPIOData & g(gpio_[gpio_num]);
|
||||
char r = 0;
|
||||
char r = 0;
|
||||
int ret = 0;
|
||||
if (g.fd != -1) {
|
||||
::lseek(g.fd, 0, SEEK_SET);
|
||||
@@ -149,7 +147,7 @@ bool PIGPIO::getPinState(int gpio_num) {
|
||||
if (r == '0') return false;
|
||||
}
|
||||
}
|
||||
//piCoutObj << "pinState" << gpio_num << ":" << ret << (int)r << errorString();
|
||||
// piCoutObj << "pinState" << gpio_num << ":" << ret << (int)r << errorString();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -159,7 +157,7 @@ void PIGPIO::begin() {
|
||||
PIMutexLocker ml(mutex);
|
||||
if (watch_state.isEmpty()) return;
|
||||
PIVector<int> ids = watch_state.keys();
|
||||
for(int i = 0; i < ids.size_s(); i++) {
|
||||
for (int i = 0; i < ids.size_s(); i++) {
|
||||
GPIOData & g(gpio_[ids[i]]);
|
||||
if (g.num != -1 && !g.name.isEmpty()) {
|
||||
openGPIO(g);
|
||||
@@ -181,7 +179,7 @@ void PIGPIO::run() {
|
||||
GPIOData & g(gpio_[it.key()]);
|
||||
if (g.num == -1 || g.name.isEmpty()) continue;
|
||||
bool v = getPinState(g.num);
|
||||
//piCoutObj << "*** pin state ***" << ids[i] << "=" << v;
|
||||
// piCoutObj << "*** pin state ***" << ids[i] << "=" << v;
|
||||
if (watch_state[g.num] != v) {
|
||||
watch_state[g.num] = v;
|
||||
changed.push_back({g.num, v});
|
||||
@@ -197,7 +195,7 @@ void PIGPIO::end() {
|
||||
PIMutexLocker ml(mutex);
|
||||
if (watch_state.isEmpty()) return;
|
||||
PIVector<int> ids = watch_state.keys();
|
||||
for(int i = 0; i < ids.size_s(); i++) {
|
||||
for (int i = 0; i < ids.size_s(); i++) {
|
||||
GPIOData & g(gpio_[ids[i]]);
|
||||
if (g.fd != -1) {
|
||||
#ifdef GPIO_SYS_CLASS
|
||||
@@ -214,20 +212,16 @@ void PIGPIO::initPin(int gpio_num, Direction dir) {
|
||||
PIMutexLocker ml(mutex);
|
||||
GPIOData & g(gpio_[gpio_num]);
|
||||
if (g.num == -1) {
|
||||
g.num = gpio_num;
|
||||
g.num = gpio_num;
|
||||
g.name = GPIOName(gpio_num);
|
||||
exportGPIO(gpio_num);
|
||||
}
|
||||
g.dir = dir;
|
||||
g.dir = dir;
|
||||
int ret = 0;
|
||||
NO_UNUSED(ret);
|
||||
switch(dir) {
|
||||
case In:
|
||||
ret = system(("echo in >> /sys/class/gpio/" + g.name + "/direction").dataAscii());
|
||||
break;
|
||||
case Out:
|
||||
ret = system(("echo out >> /sys/class/gpio/" + g.name + "/direction").dataAscii());
|
||||
break;
|
||||
switch (dir) {
|
||||
case In: ret = system(("echo in >> /sys/class/gpio/" + g.name + "/direction").dataAscii()); break;
|
||||
case Out: ret = system(("echo out >> /sys/class/gpio/" + g.name + "/direction").dataAscii()); break;
|
||||
default: break;
|
||||
}
|
||||
openGPIO(g);
|
||||
@@ -242,10 +236,12 @@ void PIGPIO::pinSet(int gpio_num, bool value) {
|
||||
int ret = 0;
|
||||
NO_UNUSED(ret);
|
||||
if (g.fd != -1) {
|
||||
if (value) ret = ::write(g.fd, "1", 1);
|
||||
else ret = ::write(g.fd, "0", 1);
|
||||
if (value)
|
||||
ret = ::write(g.fd, "1", 1);
|
||||
else
|
||||
ret = ::write(g.fd, "0", 1);
|
||||
}
|
||||
//piCoutObj << "pinSet" << gpio_num << ":" << ret << errorString();
|
||||
// piCoutObj << "pinSet" << gpio_num << ":" << ret << errorString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -306,5 +302,5 @@ void PIGPIO::clearWatch() {
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
//# pragma GCC diagnostic pop
|
||||
// # pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -3,24 +3,24 @@
|
||||
* \~\brief
|
||||
* \~english GPIO
|
||||
* \~russian GPIO
|
||||
*/
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
GPIO
|
||||
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
GPIO
|
||||
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIGPIO_H
|
||||
@@ -33,15 +33,14 @@
|
||||
//! \~\brief
|
||||
//! \~english GPIO support.
|
||||
//! \~russian Поддержка GPIO.
|
||||
class PIP_EXPORT PIGPIO: public PIThread
|
||||
{
|
||||
class PIP_EXPORT PIGPIO: public PIThread {
|
||||
PIOBJECT_SUBCLASS(PIGPIO, PIThread);
|
||||
public:
|
||||
|
||||
public:
|
||||
//! \~english Work mode for pin
|
||||
//! \~russian Режим работы пина
|
||||
enum Direction {
|
||||
In /** \~english Input direction (read) \~russian Входной (чтение) */,
|
||||
In /** \~english Input direction (read) \~russian Входной (чтение) */,
|
||||
Out /** \~english Output direction (write) \~russian Выходной (запись) */
|
||||
};
|
||||
|
||||
@@ -55,15 +54,15 @@ public:
|
||||
|
||||
//! \~english Set pin "gpio_num" value to "value"
|
||||
//! \~russian Устанавливает значение пина "gpio_num" в "value"
|
||||
void pinSet (int gpio_num, bool value);
|
||||
void pinSet(int gpio_num, bool value);
|
||||
|
||||
//! \~english Set pin "gpio_num" value to \b true
|
||||
//! \~russian Устанавливает значение пина "gpio_num" в \b true
|
||||
void pinHigh (int gpio_num) {pinSet(gpio_num, true );}
|
||||
void pinHigh(int gpio_num) { pinSet(gpio_num, true); }
|
||||
|
||||
//! \~english Set pin "gpio_num" value to \b false
|
||||
//! \~russian Устанавливает значение пина "gpio_num" в \b false
|
||||
void pinLow (int gpio_num) {pinSet(gpio_num, false);}
|
||||
void pinLow(int gpio_num) { pinSet(gpio_num, false); }
|
||||
|
||||
//!
|
||||
//! \~english Returns pin "gpio_num" state
|
||||
@@ -76,7 +75,7 @@ public:
|
||||
|
||||
//! \~english End watch for pin "gpio_num"
|
||||
//! \~russian Заканчивает наблюдение за пином "gpio_num"
|
||||
void pinEndWatch (int gpio_num);
|
||||
void pinEndWatch(int gpio_num);
|
||||
|
||||
//! \~english End watch for all pins
|
||||
//! \~russian Заканчивает наблюдение за всеми пинами
|
||||
@@ -87,13 +86,13 @@ public:
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void pinChanged(int gpio_num, bool new_value)
|
||||
//! \~english Raise on pin "gpio_num" state changes to "new_value"
|
||||
//! \~russian Вызывается по смене состояния пина "gpio_num" на "new_value"
|
||||
//! \~\details
|
||||
//! \~\warning
|
||||
//! \~english This event raised only when thread started.
|
||||
//! \~russian Это событие вызывается только при запущенном потоке.
|
||||
//! \fn void pinChanged(int gpio_num, bool new_value)
|
||||
//! \~english Raise on pin "gpio_num" state changes to "new_value"
|
||||
//! \~russian Вызывается по смене состояния пина "gpio_num" на "new_value"
|
||||
//! \~\details
|
||||
//! \~\warning
|
||||
//! \~english This event raised only when thread started.
|
||||
//! \~russian Это событие вызывается только при запущенном потоке.
|
||||
|
||||
//! \}
|
||||
|
||||
@@ -103,7 +102,10 @@ private:
|
||||
NO_COPY_CLASS(PIGPIO);
|
||||
|
||||
struct PIP_EXPORT GPIOData {
|
||||
GPIOData() {dir = PIGPIO::In; num = fd = -1;}
|
||||
GPIOData() {
|
||||
dir = PIGPIO::In;
|
||||
num = fd = -1;
|
||||
}
|
||||
PIString name;
|
||||
int dir;
|
||||
int num;
|
||||
@@ -121,7 +123,6 @@ private:
|
||||
PIMap<int, GPIOData> gpio_;
|
||||
PIMap<int, bool> watch_state;
|
||||
PIMutex mutex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIByteArray
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIByteArray
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piiobytearray.h"
|
||||
@@ -31,37 +31,37 @@
|
||||
//!
|
||||
|
||||
|
||||
PIIOByteArray::PIIOByteArray(PIByteArray *buffer, PIIODevice::DeviceMode mode) {
|
||||
PIIOByteArray::PIIOByteArray(PIByteArray * buffer, PIIODevice::DeviceMode mode) {
|
||||
open(buffer, mode);
|
||||
}
|
||||
|
||||
|
||||
PIIOByteArray::PIIOByteArray(const PIByteArray &buffer) {
|
||||
PIIOByteArray::PIIOByteArray(const PIByteArray & buffer) {
|
||||
open(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool PIIOByteArray::open(PIByteArray *buffer, PIIODevice::DeviceMode mode) {
|
||||
bool PIIOByteArray::open(PIByteArray * buffer, PIIODevice::DeviceMode mode) {
|
||||
data_ = buffer;
|
||||
mode_ = mode;
|
||||
return PIIODevice::open(mode);
|
||||
}
|
||||
|
||||
|
||||
bool PIIOByteArray::open(const PIByteArray &buffer) {
|
||||
data_ = const_cast<PIByteArray*>(&buffer);
|
||||
bool PIIOByteArray::open(const PIByteArray & buffer) {
|
||||
data_ = const_cast<PIByteArray *>(&buffer);
|
||||
mode_ = PIIODevice::ReadOnly;
|
||||
return PIIODevice::open(PIIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
|
||||
ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
|
||||
// piCout << "PIIOByteArray::read" << data_ << size << canRead();
|
||||
// piCout << "PIIOByteArray::read" << data_ << size << canRead();
|
||||
if (!canRead() || !data_) return -1;
|
||||
int ret = piMini(size, data_->size_s() - pos);
|
||||
if (ret <= 0) return -1;
|
||||
memcpy(read_to, data_->data(pos), ret);
|
||||
// piCout << "readed" << ret;
|
||||
// piCout << "readed" << ret;
|
||||
pos += size;
|
||||
if (pos > data_->size_s()) pos = data_->size_s();
|
||||
return ret;
|
||||
@@ -69,19 +69,19 @@ ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
|
||||
|
||||
|
||||
ssize_t PIIOByteArray::writeDevice(const void * data, ssize_t size) {
|
||||
// piCout << "PIIOByteArray::write" << data << size << canWrite();
|
||||
// piCout << "PIIOByteArray::write" << data << size << canWrite();
|
||||
if (!canWrite() || !data) return -1;
|
||||
//piCout << "write" << data;
|
||||
// piCout << "write" << data;
|
||||
if (pos > data_->size_s()) pos = data_->size_s();
|
||||
PIByteArray rs = PIByteArray(data, size);
|
||||
// piCoutObj << rs;
|
||||
// piCoutObj << rs;
|
||||
data_->insert(pos, rs);
|
||||
pos += rs.size_s();
|
||||
return rs.size_s();
|
||||
}
|
||||
|
||||
|
||||
int PIIOByteArray::writeByteArray(const PIByteArray &ba) {
|
||||
int PIIOByteArray::writeByteArray(const PIByteArray & ba) {
|
||||
if (!canWrite() || !data_) return -1;
|
||||
if (pos > data_->size_s()) pos = data_->size_s();
|
||||
data_->insert(pos, ba);
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Обертка PIIODevice вокруг PIByteArray
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIByteArray
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIByteArray
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIIOBYTEARRAY_H
|
||||
@@ -33,71 +33,81 @@
|
||||
//! \~\brief
|
||||
//! \~english PIIODevice wrapper around PIByteArray
|
||||
//! \~russian Обёртка PIIODevice вокруг PIByteArray
|
||||
class PIP_EXPORT PIIOByteArray: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIIOByteArray: public PIIODevice {
|
||||
PIIODEVICE(PIIOByteArray, "");
|
||||
|
||||
public:
|
||||
|
||||
//! \~english Contructs %PIIOByteArray with "buffer" content and "mode" open mode
|
||||
//! \~russian Создает %PIIOByteArray с содержимым "buffer" и режимом открытия "mode"
|
||||
explicit PIIOByteArray(PIByteArray * buffer = 0, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
|
||||
|
||||
//! \~english Contructs %PIIOByteArray with "buffer" content only for read
|
||||
//! \~russian Создает %PIIOByteArray с содержимым "buffer" только для чтения
|
||||
explicit PIIOByteArray(const PIByteArray & buffer);
|
||||
|
||||
|
||||
//! \~english Returns content
|
||||
//! \~russian Возвращает содержимое
|
||||
PIByteArray * byteArray() const {return data_;}
|
||||
|
||||
PIByteArray * byteArray() const { return data_; }
|
||||
|
||||
//! \~english Clear content buffer
|
||||
//! \~russian Очищает содержимое буфера
|
||||
void clear() {if (data_) data_->clear(); pos = 0;}
|
||||
|
||||
void clear() {
|
||||
if (data_) data_->clear();
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
//! \~english Open "buffer" content with "mode" open mode
|
||||
//! \~russian Открывает содержимое "buffer" с режимом открытия "mode"
|
||||
bool open(PIByteArray * buffer, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
|
||||
|
||||
//! \~english Open "buffer" content only for read
|
||||
//! \~russian Открывает содержимое "buffer" только для чтения
|
||||
bool open(const PIByteArray & buffer);
|
||||
|
||||
|
||||
//! \~english Returns if position is at the end of content
|
||||
//! \~russian Возвращает в конце содержимого ли позиция
|
||||
bool isEnd() const {if (!data_) return true; return pos >= data_->size_s();}
|
||||
|
||||
|
||||
bool isEnd() const {
|
||||
if (!data_) return true;
|
||||
return pos >= data_->size_s();
|
||||
}
|
||||
|
||||
|
||||
//! \~english Move read/write position to "position"
|
||||
//! \~russian Перемещает позицию чтения/записи на "position"
|
||||
void seek(llong position) {pos = position;}
|
||||
|
||||
void seek(llong position) { pos = position; }
|
||||
|
||||
//! \~english Move read/write position to the beginning of the buffer
|
||||
//! \~russian Перемещает позицию чтения/записи на начало буфера
|
||||
void seekToBegin() {if (data_) pos = 0;}
|
||||
|
||||
void seekToBegin() {
|
||||
if (data_) pos = 0;
|
||||
}
|
||||
|
||||
//! \~english Move read/write position to the end of the buffer
|
||||
//! \~russian Перемещает позицию чтения/записи на конец буфера
|
||||
void seekToEnd() {if (data_) pos = data_->size_s();}
|
||||
|
||||
|
||||
void seekToEnd() {
|
||||
if (data_) pos = data_->size_s();
|
||||
}
|
||||
|
||||
|
||||
//! \~english Insert data "ba" into content at current position
|
||||
//! \~russian Вставляет данные "ba" в содержимое буфера в текущую позицию
|
||||
int writeByteArray(const PIByteArray & ba);
|
||||
|
||||
ssize_t bytesAvailable() const override {
|
||||
if (data_) return data_->size();
|
||||
else return 0;
|
||||
if (data_)
|
||||
return data_->size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
bool openDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t size) override;
|
||||
ssize_t writeDevice(const void * data_, ssize_t size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Sequential | PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Sequential | PIIODevice::Reliable; }
|
||||
|
||||
ssize_t pos;
|
||||
PIByteArray * data_;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIIOBYTEARRAY_H
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piiodevice.h"
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "piconnection.h"
|
||||
#include "pipropertystorage.h"
|
||||
@@ -235,8 +236,7 @@ bool PIIODevice::isThreadedWrite() const {
|
||||
|
||||
|
||||
void PIIODevice::startThreadedWrite() {
|
||||
if (!write_thread.isRunning())
|
||||
write_thread.startOnce();
|
||||
if (!write_thread.isRunning()) write_thread.startOnce();
|
||||
}
|
||||
|
||||
|
||||
@@ -313,11 +313,13 @@ void PIIODevice::_init() {
|
||||
#else
|
||||
threaded_read_buffer_size = 4096;
|
||||
#endif
|
||||
read_thread .setName("__S__.PIIODevice.read_thread" );
|
||||
read_thread.setName("__S__.PIIODevice.read_thread");
|
||||
write_thread.setName("__S__.PIIODevice.write_thread");
|
||||
CONNECT(void, &write_thread, started, this, write_func);
|
||||
CONNECTL(&read_thread, started, [this](){if (!isOpened()) open();});
|
||||
read_thread.setSlot([this](void*){read_func();});
|
||||
CONNECTL(&read_thread, started, [this]() {
|
||||
if (!isOpened()) open();
|
||||
});
|
||||
read_thread.setSlot([this](void *) { read_func(); });
|
||||
}
|
||||
|
||||
|
||||
@@ -339,8 +341,7 @@ void PIIODevice::write_func() {
|
||||
PIIODevice * PIIODevice::newDeviceByPrefix(const char * prefix) {
|
||||
if (!prefix) return nullptr;
|
||||
auto fi = fabrics().value(prefix);
|
||||
if (fi.fabricator)
|
||||
return fi.fabricator();
|
||||
if (fi.fabricator) return fi.fabricator();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -364,10 +365,10 @@ void PIIODevice::read_func() {
|
||||
ssize_t readed_ = read(buffer_tr.data(), buffer_tr.size_s());
|
||||
if (readed_ <= 0) {
|
||||
piMSleep(10);
|
||||
//cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
||||
// cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
||||
return;
|
||||
}
|
||||
//piCoutObj << "readed" << readed_;// << ", " << errno << ", " << errorString();
|
||||
// piCoutObj << "readed" << readed_;// << ", " << errno << ", " << errorString();
|
||||
threadedRead(buffer_tr.data(), readed_);
|
||||
threadedReadEvent(buffer_tr.data(), readed_);
|
||||
}
|
||||
@@ -381,8 +382,10 @@ PIByteArray PIIODevice::readForTime(double timeout_ms) {
|
||||
tm.reset();
|
||||
while (tm.elapsed_m() < timeout_ms) {
|
||||
ret = read(td, threaded_read_buffer_size);
|
||||
if (ret <= 0) piMinSleep();
|
||||
else str.append(td, ret);
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else
|
||||
str.append(td, ret);
|
||||
}
|
||||
delete[] td;
|
||||
return str;
|
||||
@@ -442,8 +445,10 @@ bool PIIODevice::configure(const PIString & config_file, const PIString & sectio
|
||||
if (!conf.isOpened()) return false;
|
||||
bool ex = true;
|
||||
PIConfig::Entry em;
|
||||
if (section.isEmpty()) em = conf.rootEntry();
|
||||
else em = conf.getValue(section, PIString(), &ex);
|
||||
if (section.isEmpty())
|
||||
em = conf.rootEntry();
|
||||
else
|
||||
em = conf.getValue(section, PIString(), &ex);
|
||||
if (!ex) return false;
|
||||
PIConfig::Entry * ep = 0;
|
||||
if (parent_section) ep = em.parent();
|
||||
@@ -470,7 +475,7 @@ PIString PIIODevice::constructFullPath() const {
|
||||
|
||||
void PIIODevice::configureFromFullPath(const PIString & full_path) {
|
||||
PIString fp;
|
||||
DeviceMode dm = ReadWrite;
|
||||
DeviceMode dm = ReadWrite;
|
||||
DeviceOptions op = 0;
|
||||
splitFullPath(full_path, &fp, &dm, &op);
|
||||
setMode(dm);
|
||||
@@ -481,8 +486,8 @@ void PIIODevice::configureFromFullPath(const PIString & full_path) {
|
||||
|
||||
PIVariantTypes::IODevice PIIODevice::constructVariant() const {
|
||||
PIVariantTypes::IODevice ret;
|
||||
ret.prefix = fullPathPrefix();
|
||||
ret.mode = mode();
|
||||
ret.prefix = fullPathPrefix();
|
||||
ret.mode = mode();
|
||||
ret.options = options();
|
||||
ret.set(constructVariantDevice());
|
||||
return ret;
|
||||
@@ -497,22 +502,25 @@ void PIIODevice::configureFromVariant(const PIVariantTypes::IODevice & d) {
|
||||
|
||||
|
||||
void PIIODevice::splitFullPath(PIString fpwm, PIString * full_path, DeviceMode * mode, DeviceOptions * opts) {
|
||||
int dm = 0;
|
||||
int dm = 0;
|
||||
DeviceOptions op = 0;
|
||||
if (fpwm.find('(') > 0 && fpwm.find(')') > 0) {
|
||||
PIString dms(fpwm.right(fpwm.length() - fpwm.findLast('(')).takeRange('(', ')').trim().toLowerCase().removeAll(' '));
|
||||
PIStringList opts(dms.split(","));
|
||||
piForeachC (PIString & o, opts) {
|
||||
//piCout << dms;
|
||||
piForeachC(PIString & o, opts) {
|
||||
// piCout << dms;
|
||||
if (o == PIStringAscii("r") || o == PIStringAscii("ro") || o == PIStringAscii("read") || o == PIStringAscii("readonly"))
|
||||
dm |= ReadOnly;
|
||||
if (o == PIStringAscii("w") || o == PIStringAscii("wo") || o == PIStringAscii("write") || o == PIStringAscii("writeonly"))
|
||||
dm |= WriteOnly;
|
||||
if (o == PIStringAscii("br") || o == PIStringAscii("blockr") || o == PIStringAscii("blockread") || o == PIStringAscii("blockingread"))
|
||||
if (o == PIStringAscii("br") || o == PIStringAscii("blockr") || o == PIStringAscii("blockread") ||
|
||||
o == PIStringAscii("blockingread"))
|
||||
op |= BlockingRead;
|
||||
if (o == PIStringAscii("bw") || o == PIStringAscii("blockw") || o == PIStringAscii("blockwrite") || o == PIStringAscii("blockingwrite"))
|
||||
if (o == PIStringAscii("bw") || o == PIStringAscii("blockw") || o == PIStringAscii("blockwrite") ||
|
||||
o == PIStringAscii("blockingwrite"))
|
||||
op |= BlockingWrite;
|
||||
if (o == PIStringAscii("brw") || o == PIStringAscii("bwr") || o == PIStringAscii("blockrw") || o == PIStringAscii("blockwr") || o == PIStringAscii("blockreadrite") || o == PIStringAscii("blockingreadwrite"))
|
||||
if (o == PIStringAscii("brw") || o == PIStringAscii("bwr") || o == PIStringAscii("blockrw") || o == PIStringAscii("blockwr") ||
|
||||
o == PIStringAscii("blockreadrite") || o == PIStringAscii("blockingreadwrite"))
|
||||
op |= BlockingRead | BlockingWrite;
|
||||
}
|
||||
fpwm.cutRight(fpwm.length() - fpwm.findLast('(')).trim();
|
||||
@@ -542,12 +550,12 @@ PIStringList PIIODevice::availableClasses() {
|
||||
|
||||
void PIIODevice::registerDevice(PIConstChars prefix, PIConstChars classname, PIIODevice * (*fabric)()) {
|
||||
if (prefix.isEmpty()) return;
|
||||
//printf("registerDevice %s %d %d\n", prefix, p.isEmpty(), fabrics().size());
|
||||
// printf("registerDevice %s %d %d\n", prefix, p.isEmpty(), fabrics().size());
|
||||
if (!fabrics().contains(prefix)) {
|
||||
FabricInfo fi;
|
||||
fi.prefix = prefix;
|
||||
fi.classname = classname;
|
||||
fi.fabricator = fabric;
|
||||
fi.prefix = prefix;
|
||||
fi.classname = classname;
|
||||
fi.fabricator = fabric;
|
||||
fabrics()[prefix] = fi;
|
||||
}
|
||||
}
|
||||
@@ -557,10 +565,26 @@ PIString PIIODevice::fullPathOptions() const {
|
||||
if (mode_ == ReadWrite && options_ == 0) return PIString();
|
||||
PIString ret(" (");
|
||||
bool f = true;
|
||||
if (mode_ == ReadOnly) {if (!f) ret += ","; f = false; ret += "ro";}
|
||||
if (mode_ == WriteOnly) {if (!f) ret += ","; f = false; ret += "wo";}
|
||||
if (options_[BlockingRead]) {if (!f) ret += ","; f = false; ret += "br";}
|
||||
if (options_[BlockingWrite]) {if (!f) ret += ","; f = false; ret += "bw";}
|
||||
if (mode_ == ReadOnly) {
|
||||
if (!f) ret += ",";
|
||||
f = false;
|
||||
ret += "ro";
|
||||
}
|
||||
if (mode_ == WriteOnly) {
|
||||
if (!f) ret += ",";
|
||||
f = false;
|
||||
ret += "wo";
|
||||
}
|
||||
if (options_[BlockingRead]) {
|
||||
if (!f) ret += ",";
|
||||
f = false;
|
||||
ret += "br";
|
||||
}
|
||||
if (options_[BlockingWrite]) {
|
||||
if (!f) ret += ",";
|
||||
f = false;
|
||||
ret += "bw";
|
||||
}
|
||||
return ret + ")";
|
||||
}
|
||||
|
||||
@@ -599,7 +623,7 @@ PIString PIIODevice::normalizeFullPath(const PIString & full_path) {
|
||||
}
|
||||
nfp_mutex.unlock();
|
||||
PIIODevice * d = createFromFullPath(full_path);
|
||||
//piCout << "normalizeFullPath" << d;
|
||||
// piCout << "normalizeFullPath" << d;
|
||||
if (d == 0) return PIString();
|
||||
ret = d->constructFullPath();
|
||||
delete d;
|
||||
@@ -619,8 +643,8 @@ PIMap<PIConstChars, PIIODevice::FabricInfo> & PIIODevice::fabrics() {
|
||||
}
|
||||
|
||||
|
||||
bool PIIODevice::threadedRead(const uchar *readed, ssize_t size) {
|
||||
// piCout << "iodevice threaded read";
|
||||
bool PIIODevice::threadedRead(const uchar * readed, ssize_t size) {
|
||||
// piCout << "iodevice threaded read";
|
||||
if (func_read) return func_read(readed, size, ret_data_);
|
||||
return true;
|
||||
}
|
||||
@@ -636,5 +660,3 @@ PIPropertyStorage PIIODevice::constructVariantDevice() const {
|
||||
void PIIODevice::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
setPath(d.propertyValueByName("path").toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,30 +5,30 @@
|
||||
* \~russian Базовый класс утройств ввода/вывода
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIIODEVICE_H
|
||||
#define PIIODEVICE_H
|
||||
|
||||
#include "piinit.h"
|
||||
#include "pitimer.h"
|
||||
#include "piqueue.h"
|
||||
#include "pitimer.h"
|
||||
|
||||
/// TODO: написать документацию, тут ничего не понятно
|
||||
// function executed from threaded read, pass readedData, sizeOfData, ThreadedReadData
|
||||
@@ -56,18 +56,26 @@ typedef std::function<bool(const uchar *, int, void *)> ReadRetFunc;
|
||||
|
||||
#else
|
||||
|
||||
# define REGISTER_DEVICE(name) \
|
||||
STATIC_INITIALIZER_BEGIN \
|
||||
PIIODevice::registerDevice(name::fullPathPrefixS(), #name, []()->PIIODevice*{return new name();});\
|
||||
STATIC_INITIALIZER_END
|
||||
# define REGISTER_DEVICE(name) \
|
||||
STATIC_INITIALIZER_BEGIN \
|
||||
PIIODevice::registerDevice(name::fullPathPrefixS(), #name, []() -> PIIODevice * { return new name(); }); \
|
||||
STATIC_INITIALIZER_END
|
||||
|
||||
# define PIIODEVICE(name, prefix) \
|
||||
PIOBJECT_SUBCLASS(name, PIIODevice) \
|
||||
PIIODevice * copy() const override {return new name();} \
|
||||
public: \
|
||||
PIConstChars fullPathPrefix() const override {return prefix;} \
|
||||
static PIConstChars fullPathPrefixS() {return prefix;} \
|
||||
private:
|
||||
# define PIIODEVICE(name, prefix) \
|
||||
PIOBJECT_SUBCLASS(name, PIIODevice) \
|
||||
PIIODevice * copy() const override { \
|
||||
return new name(); \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
PIConstChars fullPathPrefix() const override { \
|
||||
return prefix; \
|
||||
} \
|
||||
static PIConstChars fullPathPrefixS() { \
|
||||
return prefix; \
|
||||
} \
|
||||
\
|
||||
private:
|
||||
|
||||
|
||||
#endif
|
||||
@@ -76,13 +84,13 @@ typedef std::function<bool(const uchar *, int, void *)> ReadRetFunc;
|
||||
//! \~\brief
|
||||
//! \~english Base class for input/output devices.
|
||||
//! \~russian Базовый класс утройств ввода/вывода.
|
||||
class PIP_EXPORT PIIODevice: public PIObject
|
||||
{
|
||||
class PIP_EXPORT PIIODevice: public PIObject {
|
||||
PIOBJECT_SUBCLASS(PIIODevice, PIObject);
|
||||
friend void __DevicePool_threadReadDP(void * ddp);
|
||||
|
||||
public:
|
||||
NO_COPY_CLASS(PIIODevice);
|
||||
|
||||
|
||||
//! \~english Constructs a empty %PIIODevice
|
||||
//! \~russian Создает пустой %PIIODevice
|
||||
explicit PIIODevice();
|
||||
@@ -90,29 +98,33 @@ public:
|
||||
//! \~english Open modes for PIIODevice
|
||||
//! \~russian Режимы открытия для PIIODevice
|
||||
enum DeviceMode {
|
||||
ReadOnly /*! \~english Device can only read \~russian Устройство может только читать */ = 0x01,
|
||||
WriteOnly /*! \~english Device can only write \~russian Устройство может только писать */ = 0x02,
|
||||
ReadOnly /*! \~english Device can only read \~russian Устройство может только читать */ = 0x01,
|
||||
WriteOnly /*! \~english Device can only write \~russian Устройство может только писать */ = 0x02,
|
||||
ReadWrite /*! \~english Device can both read and write \~russian Устройство может читать и писать */ = 0x03
|
||||
};
|
||||
|
||||
//! \~english Options for PIIODevice, works with some devices
|
||||
//! \~russian Опции для PIIODevice, работает для некоторых устройств
|
||||
enum DeviceOption {
|
||||
BlockingRead /*! \~english \a read() block until data is received, default off \~russian \a read() блокируется, пока данные не поступят, по умолчанию выключено */ = 0x01,
|
||||
BlockingWrite /*! \~english \a write() block until data is sent, default off \~russian \a write() блокируется, пока данные не запишутся, по умолчанию выключено */ = 0x02
|
||||
BlockingRead /*! \~english \a read() block until data is received, default off \~russian \a read() блокируется, пока данные не
|
||||
поступят, по умолчанию выключено */
|
||||
= 0x01,
|
||||
BlockingWrite /*! \~english \a write() block until data is sent, default off \~russian \a write() блокируется, пока данные не
|
||||
запишутся, по умолчанию выключено */
|
||||
= 0x02
|
||||
};
|
||||
|
||||
//! \~english Characteristics of PIIODevice channel
|
||||
//! \~russian Характеристики канала PIIODevice
|
||||
enum DeviceInfoFlag {
|
||||
Sequential /*! \~english Continuous bytestream without packets \~russian Непрерывный поток байт, без пакетирования */ = 0x01,
|
||||
Reliable /*! \~english Channel without data errors or corruptions \~russian Канал без ошибок или повреждений данных */ = 0x02
|
||||
Sequential /*! \~english Continuous bytestream without packets \~russian Непрерывный поток байт, без пакетирования */ = 0x01,
|
||||
Reliable /*! \~english Channel without data errors or corruptions \~russian Канал без ошибок или повреждений данных */ = 0x02
|
||||
};
|
||||
|
||||
struct FabricInfo {
|
||||
PIConstChars prefix;
|
||||
PIConstChars classname;
|
||||
PIIODevice*(*fabricator)() = nullptr;
|
||||
PIIODevice * (*fabricator)() = nullptr;
|
||||
};
|
||||
|
||||
typedef PIFlags<DeviceOption> DeviceOptions;
|
||||
@@ -126,19 +138,19 @@ public:
|
||||
|
||||
//! \~english Returns current open mode of device
|
||||
//! \~russian Возвращает текущий режим открытия устройства
|
||||
DeviceMode mode() const {return mode_;}
|
||||
|
||||
DeviceMode mode() const { return mode_; }
|
||||
|
||||
//! \~english Set open mode of device. Don`t reopen device
|
||||
//! \~russian Устанавливает режим открытия устройства. Не переоткрывает устройство
|
||||
void setMode(DeviceMode m) {mode_ = m;}
|
||||
void setMode(DeviceMode m) { mode_ = m; }
|
||||
|
||||
//! \~english Returns current device options
|
||||
//! \~russian Возвращает текущие опции устройства
|
||||
DeviceOptions options() const {return options_;}
|
||||
DeviceOptions options() const { return options_; }
|
||||
|
||||
//! \~english Returns current device option "o" state
|
||||
//! \~russian Возвращает текущее состояние опции "o"
|
||||
bool isOptionSet(DeviceOption o) const {return options_[o];}
|
||||
bool isOptionSet(DeviceOption o) const { return options_[o]; }
|
||||
|
||||
//! \~english Set device options
|
||||
//! \~russian Устанавливает опции устройства
|
||||
@@ -150,95 +162,95 @@ public:
|
||||
|
||||
//! \~english Returns device characteristic flags
|
||||
//! \~russian Возвращает характеристики канала
|
||||
DeviceInfoFlags infoFlags() const {return deviceInfoFlags();}
|
||||
DeviceInfoFlags infoFlags() const { return deviceInfoFlags(); }
|
||||
|
||||
//! \~english Returns current path of device
|
||||
//! \~russian Возвращает текущий путь устройства
|
||||
PIString path() const {return property("path").toString();}
|
||||
|
||||
PIString path() const { return property("path").toString(); }
|
||||
|
||||
//! \~english Set path of device. Don`t reopen device
|
||||
//! \~russian Устанавливает путь устройства. Не переоткрывает устройство
|
||||
void setPath(const PIString & path) {setProperty("path", path);}
|
||||
|
||||
void setPath(const PIString & path) { setProperty("path", path); }
|
||||
|
||||
//! \~english Returns if mode is ReadOnly or ReadWrite
|
||||
//! \~russian Возвращает равен ли режим открытия ReadOnly или ReadWrite
|
||||
bool isReadable() const {return (mode_ & ReadOnly);}
|
||||
|
||||
bool isReadable() const { return (mode_ & ReadOnly); }
|
||||
|
||||
//! \~english Returns if mode is WriteOnly or ReadWrite
|
||||
//! \~russian Возвращает равен ли режим открытия WriteOnly или ReadWrite
|
||||
bool isWriteable() const {return (mode_ & WriteOnly);}
|
||||
|
||||
bool isWriteable() const { return (mode_ & WriteOnly); }
|
||||
|
||||
//! \~english Returns if device is successfully opened
|
||||
//! \~russian Возвращает успешно ли открыто устройство
|
||||
bool isOpened() const {return opened_;}
|
||||
|
||||
bool isOpened() const { return opened_; }
|
||||
|
||||
//! \~english Returns if device is closed
|
||||
//! \~russian Возвращает закрыто ли устройство
|
||||
bool isClosed() const {return !opened_;}
|
||||
|
||||
bool isClosed() const { return !opened_; }
|
||||
|
||||
//! \~english Returns if device can read \b now
|
||||
//! \~russian Возвращает может ли устройство читать \b сейчас
|
||||
virtual bool canRead() const {return opened_ && (mode_ & ReadOnly);}
|
||||
|
||||
virtual bool canRead() const { return opened_ && (mode_ & ReadOnly); }
|
||||
|
||||
//! \~english Returns if device can write \b now
|
||||
//! \~russian Возвращает может ли устройство писать \b сейчас
|
||||
virtual bool canWrite() const {return opened_ && (mode_ & WriteOnly);}
|
||||
virtual bool canWrite() const { return opened_ && (mode_ & WriteOnly); }
|
||||
|
||||
|
||||
//! \~english Set calling of \a open() enabled while threaded read on closed device
|
||||
//! \~russian Устанавливает возможность вызова \a open() при потоковом чтении на закрытом устройстве
|
||||
void setReopenEnabled(bool yes = true);
|
||||
|
||||
|
||||
//! \~english Set timeout in milliseconds between \a open() tryings if reopen is enabled
|
||||
//! \~russian Устанавливает задержку в миллисекундах между вызовами \a open() если переоткрытие активно
|
||||
void setReopenTimeout(int msecs);
|
||||
|
||||
//! \~english Returns reopen enable
|
||||
//! \~russian Возвращает активно ли переоткрытие
|
||||
bool isReopenEnabled() const {return property("reopenEnabled").toBool();}
|
||||
|
||||
bool isReopenEnabled() const { return property("reopenEnabled").toBool(); }
|
||||
|
||||
//! \~english Returns reopen timeout in milliseconds
|
||||
//! \~russian Возвращает задержку переоткрытия в миллисекундах
|
||||
int reopenTimeout() {return property("reopenTimeout").toInt();}
|
||||
int reopenTimeout() { return property("reopenTimeout").toInt(); }
|
||||
|
||||
|
||||
//! \~english Set threaded read callback
|
||||
//! \~russian Устанавливает callback потокового чтения
|
||||
void setThreadedReadSlot(ReadRetFunc func);
|
||||
|
||||
|
||||
//! \~english Set custom data that will be passed to threaded read callback
|
||||
//! \~russian Устанавливает произвольный указатель, который будет передан в callback потокового чтения
|
||||
void setThreadedReadData(void * d) {ret_data_ = d;}
|
||||
|
||||
void setThreadedReadData(void * d) { ret_data_ = d; }
|
||||
|
||||
//! \~english Set size of threaded read buffer
|
||||
//! \~russian Устанавливает размер буфера потокового чтения
|
||||
void setThreadedReadBufferSize(int new_size);
|
||||
|
||||
//! \~english Returns size of threaded read buffer
|
||||
//! \~russian Возвращает размер буфера потокового чтения
|
||||
int threadedReadBufferSize() const {return threaded_read_buffer_size;}
|
||||
|
||||
int threadedReadBufferSize() const { return threaded_read_buffer_size; }
|
||||
|
||||
//! \~english Returns content of threaded read buffer
|
||||
//! \~russian Возвращает содержимое буфера потокового чтения
|
||||
const uchar * threadedReadBuffer() const {return buffer_tr.data();}
|
||||
const uchar * threadedReadBuffer() const { return buffer_tr.data(); }
|
||||
|
||||
//! \~english Returns custom data that will be passed to threaded read callback
|
||||
//! \~russian Возвращает произвольный указатель, который будет передан в callback потокового чтения
|
||||
void * threadedReadData() const {return ret_data_;}
|
||||
void * threadedReadData() const { return ret_data_; }
|
||||
|
||||
|
||||
|
||||
//! \~english Returns if threaded read is started
|
||||
//! \~russian Возвращает запущен ли поток чтения
|
||||
bool isThreadedRead() const;
|
||||
|
||||
|
||||
//! \~english Start threaded read
|
||||
//! \~russian Запускает потоковое чтение
|
||||
void startThreadedRead();
|
||||
|
||||
|
||||
//! \~english Start threaded read and assign threaded read callback to "func"
|
||||
//! \~russian Запускает потоковое чтение и устанавливает callback потокового чтения в "func"
|
||||
void startThreadedRead(ReadRetFunc func);
|
||||
|
||||
|
||||
//! \~english Stop threaded read.
|
||||
//! \~russian Останавливает потоковое чтение.
|
||||
void stopThreadedRead();
|
||||
@@ -246,16 +258,16 @@ public:
|
||||
//! \~english Wait for threaded read finish no longer than "timeout_ms" milliseconds.
|
||||
//! \~russian Ожидает завершения потокового чтения в течении не более "timeout_ms" миллисекунд.
|
||||
bool waitThreadedReadFinished(int timeout_ms = -1);
|
||||
|
||||
|
||||
|
||||
|
||||
//! \~english Returns if threaded write is started
|
||||
//! \~russian Возвращает запущен ли поток записи
|
||||
bool isThreadedWrite() const;
|
||||
|
||||
|
||||
//! \~english Start threaded write
|
||||
//! \~russian Запускает потоковую запись
|
||||
void startThreadedWrite();
|
||||
|
||||
|
||||
//! \~english Stop threaded write.
|
||||
//! \~russian Останавливает потоковую запись.
|
||||
void stopThreadedWrite();
|
||||
@@ -268,11 +280,11 @@ public:
|
||||
//! \~russian Очищает очередь потоковой записи
|
||||
void clearThreadedWriteQueue();
|
||||
|
||||
|
||||
|
||||
//! \~english Start both threaded read and threaded write
|
||||
//! \~russian Запускает потоковое чтение и запись
|
||||
void start();
|
||||
|
||||
|
||||
//! \~english Stop both threaded read and threaded write.
|
||||
//! \~russian Останавливает потоковое чтение и запись.
|
||||
void stop();
|
||||
@@ -307,7 +319,7 @@ public:
|
||||
//! \~russian Эта функция как правило используется чтобы знать какой
|
||||
//! размер буфера нужен в памяти для чтения.
|
||||
//! Если функция возвращает -1 это значит что количество байт для чтения не известно.
|
||||
virtual ssize_t bytesAvailable() const {return -1;}
|
||||
virtual ssize_t bytesAvailable() const { return -1; }
|
||||
|
||||
//! \~english Write maximum "max_size" bytes of "data" to device
|
||||
//! \~russian Пишет в устройство не более "max_size" байт из "data"
|
||||
@@ -318,28 +330,28 @@ public:
|
||||
//! \~russian Читает из устройства в течении "timeout_ms" миллисекунд и возвращает данные как PIByteArray.
|
||||
//! Таймаут должен быть больше 0
|
||||
PIByteArray readForTime(double timeout_ms);
|
||||
|
||||
|
||||
|
||||
//! \~english Add task to threaded write queue and return task ID
|
||||
//! \~russian Добавляет данные в очередь на потоковую запись и возвращает ID задания
|
||||
ullong writeThreaded(const void * data, ssize_t max_size) {return writeThreaded(PIByteArray(data, uint(max_size)));}
|
||||
|
||||
ullong writeThreaded(const void * data, ssize_t max_size) { return writeThreaded(PIByteArray(data, uint(max_size))); }
|
||||
|
||||
//! \~english Add task to threaded write queue and return task ID
|
||||
//! \~russian Добавляет данные в очередь на потоковую запись и возвращает ID задания
|
||||
ullong writeThreaded(const PIByteArray & data);
|
||||
|
||||
|
||||
|
||||
|
||||
//! \~english Configure device from section "section" of file "config_file", if "parent_section" parent section also will be read
|
||||
//! \~russian
|
||||
bool configure(const PIString & config_file, const PIString & section, bool parent_section = false);
|
||||
|
||||
|
||||
|
||||
|
||||
//! \~english Returns full unambiguous string prefix. \ref PIIODevice_sec7
|
||||
//! \~russian Возвращает префикс устройства. \ref PIIODevice_sec7
|
||||
virtual PIConstChars fullPathPrefix() const {return "";}
|
||||
virtual PIConstChars fullPathPrefix() const { return ""; }
|
||||
|
||||
static PIConstChars fullPathPrefixS() { return ""; }
|
||||
|
||||
static PIConstChars fullPathPrefixS() {return "";}
|
||||
|
||||
//! \~english Returns full unambiguous string, describes this device, \a fullPathPrefix() + "://" + ...
|
||||
//! \~russian Возвращает строку полного описания для этого устройства, \a fullPathPrefix() + "://" + ...
|
||||
PIString constructFullPath() const;
|
||||
@@ -363,7 +375,7 @@ public:
|
||||
//! \~english Try to create new device by prefix, configure it with \a configureFromVariant() and returns it.
|
||||
//! \~russian Пытается создать новое устройство по префиксу, настраивает с помощью \a configureFromVariant() и возвращает его
|
||||
static PIIODevice * createFromVariant(const PIVariantTypes::IODevice & d);
|
||||
|
||||
|
||||
static PIString normalizeFullPath(const PIString & full_path);
|
||||
|
||||
static void splitFullPath(PIString fpwm, PIString * full_path, DeviceMode * mode = 0, DeviceOptions * opts = 0);
|
||||
@@ -376,9 +388,9 @@ public:
|
||||
//! \~russian Возвращает имена классов всех зарегистрированных устройств
|
||||
static PIStringList availableClasses();
|
||||
|
||||
static void registerDevice(PIConstChars prefix, PIConstChars classname, PIIODevice*(*fabric)());
|
||||
static void registerDevice(PIConstChars prefix, PIConstChars classname, PIIODevice * (*fabric)());
|
||||
|
||||
|
||||
|
||||
EVENT_HANDLER(bool, open);
|
||||
EVENT_HANDLER1(bool, open, const PIString &, _path);
|
||||
bool open(DeviceMode _mode);
|
||||
@@ -388,17 +400,17 @@ public:
|
||||
|
||||
//! \~english Write memory block "mb" to device
|
||||
//! \~russian Пишет в устройство блок памяти "mb"
|
||||
ssize_t write(const PIMemoryBlock & mb) {return write(mb.data(), mb.size());}
|
||||
ssize_t write(const PIMemoryBlock & mb) { return write(mb.data(), mb.size()); }
|
||||
|
||||
EVENT_VHANDLER(void, flush) { ; }
|
||||
|
||||
EVENT_VHANDLER(void, flush) {;}
|
||||
|
||||
EVENT(opened);
|
||||
EVENT(closed);
|
||||
EVENT2(threadedReadEvent, const uchar * , readed, ssize_t, size);
|
||||
EVENT2(threadedReadEvent, const uchar *, readed, ssize_t, size);
|
||||
EVENT2(threadedWriteEvent, ullong, id, ssize_t, written_size);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn bool open()
|
||||
//! \~english Open device
|
||||
@@ -424,17 +436,17 @@ public:
|
||||
//! \~english Write "data" to device
|
||||
//! \~russian Пишет "data" в устройство
|
||||
|
||||
//! \}
|
||||
//! \vhandlers
|
||||
//! \{
|
||||
//! \}
|
||||
//! \vhandlers
|
||||
//! \{
|
||||
|
||||
//! \fn void flush()
|
||||
//! \~english Immediate write all buffers
|
||||
//! \~russian Немедленно записать все буферизированные данные
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void opened()
|
||||
//! \~english Raise if succesfull open
|
||||
@@ -459,55 +471,61 @@ public:
|
||||
//! \~english setReopenEnabled, default "true"
|
||||
//! \~russian setReopenEnabled, по умолчанию "true"
|
||||
bool reopenEnabled;
|
||||
|
||||
|
||||
//! \~english setReopenTimeout in milliseconds, default 1000
|
||||
//! \~russian setReopenTimeout в миллисекундах, по умолчанию 1000
|
||||
int reopenTimeout;
|
||||
|
||||
|
||||
//! \~english setThreadedReadBufferSize in bytes, default 4096
|
||||
//! \~russian setThreadedReadBufferSize в байтах, по умолчанию 4096
|
||||
int threadedReadBufferSize;
|
||||
#endif
|
||||
//! \}
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
//! \~english Reimplement to configure device from entries "e_main" and "e_parent", cast arguments to \a PIConfig::Entry*
|
||||
//! \~russian
|
||||
virtual bool configureDevice(const void * e_main, const void * e_parent = 0) {return true;}
|
||||
|
||||
virtual bool configureDevice(const void * e_main, const void * e_parent = 0) { return true; }
|
||||
|
||||
//! \~english Reimplement to open device, return value will be set to "opened_" variable.
|
||||
//! Don't call this function in subclass, use \a open()!
|
||||
//! \~russian Переопределите для открытия устройства, возвращаемое значение будет установлено в
|
||||
//! переменную "opened_". Не используйте напрямую, только через \a open()!
|
||||
virtual bool openDevice() = 0; // use path_, type_, opened_, init_ variables
|
||||
|
||||
|
||||
//! \~english Reimplement to close device, inverse return value will be set to "opened_" variable
|
||||
//! \~russian Переопределите для закрытия устройства, обратное возвращаемое значение будет установлено в переменную "opened_"
|
||||
virtual bool closeDevice() {return true;} // use path_, type_, opened_, init_ variables
|
||||
virtual bool closeDevice() { return true; } // use path_, type_, opened_, init_ variables
|
||||
|
||||
//! \~english Reimplement this function to read from your device
|
||||
//! \~russian Переопределите для чтения данных из устройства
|
||||
virtual ssize_t readDevice(void * read_to, ssize_t max_size) {piCoutObj << "\"read\" is not implemented!"; return -2;}
|
||||
virtual ssize_t readDevice(void * read_to, ssize_t max_size) {
|
||||
piCoutObj << "\"read\" is not implemented!";
|
||||
return -2;
|
||||
}
|
||||
|
||||
//! \~english Reimplement this function to write to your device
|
||||
//! \~russian Переопределите для записи данных в устройство
|
||||
virtual ssize_t writeDevice(const void * data, ssize_t max_size) {piCoutObj << "\"write\" is not implemented!"; return -2;}
|
||||
virtual ssize_t writeDevice(const void * data, ssize_t max_size) {
|
||||
piCoutObj << "\"write\" is not implemented!";
|
||||
return -2;
|
||||
}
|
||||
|
||||
//! \~english Function executed when thread read some data, default implementation execute external callback "ret_func_"
|
||||
//! \~russian Метод вызывается после каждого успешного потокового чтения, по умолчанию вызывает callback "ret_func_"
|
||||
virtual bool threadedRead(const uchar * readed, ssize_t size);
|
||||
|
||||
|
||||
//! \~english Reimplement to construct full unambiguous string, describes this device.
|
||||
//! Default implementation returns \a path()
|
||||
//! \~russian Переопределите для создания строки полного описания устройства.
|
||||
//! По умолчанию возвращает \a path()
|
||||
virtual PIString constructFullPathDevice() const {return path();}
|
||||
virtual PIString constructFullPathDevice() const { return path(); }
|
||||
|
||||
//! \~english Reimplement to configure your device with parameters of full unambiguous string.
|
||||
//! Default implementation call \a setPath()
|
||||
//! \~russian Переопределите для настройки устройства из строки полного описания.
|
||||
//! По умолчанию вызывает \a setPath()
|
||||
virtual void configureFromFullPathDevice(const PIString & full_path) {setPath(full_path);}
|
||||
virtual void configureFromFullPathDevice(const PIString & full_path) { setPath(full_path); }
|
||||
|
||||
//! \~english Reimplement to construct device properties.
|
||||
//! Default implementation return PIPropertyStorage with \"path\" entry
|
||||
@@ -523,19 +541,19 @@ protected:
|
||||
|
||||
//! \~english Reimplement to apply new device options
|
||||
//! \~russian Переопределите для применения новых опций устройства
|
||||
virtual void optionsChanged() {;}
|
||||
virtual void optionsChanged() { ; }
|
||||
|
||||
//! \~english Reimplement to return correct \a DeviceInfoFlags. Default implementation returns 0
|
||||
//! \~russian Переопределите для возврата правильных \a DeviceInfoFlags. По умолчанию возвращает 0
|
||||
virtual DeviceInfoFlags deviceInfoFlags() const {return 0;}
|
||||
virtual DeviceInfoFlags deviceInfoFlags() const { return 0; }
|
||||
|
||||
//! \~english Reimplement to apply new \a threadedReadBufferSize()
|
||||
//! \~russian Переопределите для применения нового \a threadedReadBufferSize()
|
||||
virtual void threadedReadBufferSizeChanged() {;}
|
||||
virtual void threadedReadBufferSizeChanged() { ; }
|
||||
|
||||
static PIIODevice * newDeviceByPrefix(const char * prefix);
|
||||
|
||||
bool isThreadedReadStopping() const {return read_thread.isStopping();}
|
||||
bool isThreadedReadStopping() const { return read_thread.isStopping(); }
|
||||
|
||||
DeviceMode mode_;
|
||||
DeviceOptions options_;
|
||||
@@ -547,7 +565,7 @@ private:
|
||||
EVENT_HANDLER(void, read_func);
|
||||
EVENT_HANDLER(void, write_func);
|
||||
|
||||
virtual PIIODevice * copy() const {return nullptr;}
|
||||
virtual PIIODevice * copy() const { return nullptr; }
|
||||
PIString fullPathOptions() const;
|
||||
void _init();
|
||||
static void cacheFullPath(const PIString & full_path, const PIIODevice * d);
|
||||
@@ -556,14 +574,13 @@ private:
|
||||
PITimeMeasurer tm, reopen_tm;
|
||||
PIThread read_thread, write_thread;
|
||||
PIByteArray buffer_in, buffer_tr;
|
||||
PIQueue<PIPair<PIByteArray, ullong> > write_queue;
|
||||
PIQueue<PIPair<PIByteArray, ullong>> write_queue;
|
||||
ullong tri = 0;
|
||||
uint threaded_read_buffer_size, reopen_timeout = 1000;
|
||||
bool reopen_enabled = true, destroying = false;
|
||||
|
||||
static PIMutex nfp_mutex;
|
||||
static PIMap<PIString, PIString> nfp_cache;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIIODEVICE_H
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//! \defgroup IO IO
|
||||
//! \~\brief
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Функциональность PIBinaryStream для PIIODevice
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIBinaryStream functionality for PIIODevice
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIBinaryStream functionality for PIIODevice
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIIOSTREAM_H
|
||||
@@ -38,14 +38,13 @@
|
||||
//! \~russian Подробнее \ref iostream
|
||||
class PIP_EXPORT PIIOBinaryStream: public PIBinaryStream<PIIOBinaryStream> {
|
||||
public:
|
||||
|
||||
//! \~english Contructs %PIIOBinaryStream for "device" device
|
||||
//! \~russian Создает %PIIOBinaryStream для устройства "device"
|
||||
PIIOBinaryStream(PIIODevice * device = nullptr): dev(device) {}
|
||||
|
||||
//! \~english Assign "device" device
|
||||
//! \~russian Назначает устройство "device"
|
||||
void setDevice(PIIODevice * device) {dev = device;}
|
||||
void setDevice(PIIODevice * device) { dev = device; }
|
||||
|
||||
bool binaryStreamAppendImp(const void * d, size_t s) {
|
||||
if (!dev) return false;
|
||||
@@ -64,7 +63,6 @@ public:
|
||||
|
||||
private:
|
||||
PIIODevice * dev;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -74,7 +72,6 @@ private:
|
||||
//! \~russian Функциональность PITextStream для PIIODevice.
|
||||
class PIP_EXPORT PIIOTextStream: public PITextStream<PIIOBinaryStream> {
|
||||
public:
|
||||
|
||||
//! \~english Contructs %PIIOTextStream for "device" device
|
||||
//! \~russian Создает %PIIOTextStream для устройства "device"
|
||||
PIIOTextStream(PIIODevice * device): PITextStream<PIIOBinaryStream>(&bin_stream), bin_stream(device) {}
|
||||
@@ -87,8 +84,7 @@ public:
|
||||
}
|
||||
|
||||
~PIIOTextStream() {
|
||||
if (io_string)
|
||||
delete io_string;
|
||||
if (io_string) delete io_string;
|
||||
}
|
||||
|
||||
void setDevice(PIIODevice * device) {
|
||||
@@ -99,7 +95,6 @@ public:
|
||||
private:
|
||||
PIIOString * io_string = nullptr;
|
||||
PIIOBinaryStream bin_stream;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIString
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIString
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piiostring.h"
|
||||
@@ -48,7 +48,7 @@ bool PIIOString::open(PIString * string, PIIODevice::DeviceMode mode) {
|
||||
|
||||
|
||||
bool PIIOString::open(const PIString & string) {
|
||||
str = const_cast<PIString*>(&string);
|
||||
str = const_cast<PIString *>(&string);
|
||||
return PIIODevice::open(PIIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ PIString PIIOString::readLine() {
|
||||
if ((*str)[np] == '\n') break;
|
||||
}
|
||||
PIString ret = str->mid(pos, np - pos);
|
||||
pos = piMini(np + 1, str->size_s());
|
||||
pos = piMini(np + 1, str->size_s());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ ssize_t PIIOString::readDevice(void * read_to, ssize_t max_size) {
|
||||
pos += max_size;
|
||||
if (pos > str->size_s()) pos = str->size_s();
|
||||
const char * cc = rs.data();
|
||||
int ret = strlen(cc);
|
||||
int ret = strlen(cc);
|
||||
memcpy(read_to, cc, ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ ssize_t PIIOString::readDevice(void * read_to, ssize_t max_size) {
|
||||
|
||||
ssize_t PIIOString::writeDevice(const void * data, ssize_t max_size) {
|
||||
if (!canWrite() || !str) return -1;
|
||||
//piCout << "write" << data;
|
||||
// piCout << "write" << data;
|
||||
if (pos > str->size_s()) pos = str->size_s();
|
||||
PIString rs = PIString::fromUTF8((const char *)data);
|
||||
if (rs.size_s() > max_size) rs.resize(max_size);
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Обертка PIIODevice вокруг PIString
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIString
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice wrapper around PIString
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIIOSTRING_H
|
||||
@@ -33,75 +33,85 @@
|
||||
//! \~\brief
|
||||
//! \~english PIIODevice wrapper around PIString.
|
||||
//! \~russian Обёртка PIIODevice вокруг PIString.
|
||||
class PIP_EXPORT PIIOString: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIIOString: public PIIODevice {
|
||||
PIIODEVICE(PIIOString, "");
|
||||
|
||||
public:
|
||||
|
||||
//! \~english Contructs %PIIOString with "string" content and "mode" open mode
|
||||
//! \~russian Создает %PIIOString с содержимым "string" и режимом открытия "mode"
|
||||
explicit PIIOString(PIString * string = 0, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
|
||||
|
||||
//! \~english Contructs %PIIOString with "string" content only for read
|
||||
//! \~russian Создает %PIIOString с содержимым "string" только для чтения
|
||||
explicit PIIOString(const PIString & string);
|
||||
|
||||
|
||||
//! \~english Returns content
|
||||
//! \~russian Возвращает содержимое
|
||||
PIString * string() const {return str;}
|
||||
|
||||
PIString * string() const { return str; }
|
||||
|
||||
//! \~english Clear content string
|
||||
//! \~russian Очищает содержимое строки
|
||||
void clear() {if (str) str->clear(); pos = 0;}
|
||||
|
||||
void clear() {
|
||||
if (str) str->clear();
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
//! \~english Open "string" content with "mode" open mode
|
||||
//! \~russian Открывает содержимое "string" с режимом открытия "mode"
|
||||
bool open(PIString * string, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
|
||||
|
||||
//! \~english Open "string" content only for read
|
||||
//! \~russian Открывает содержимое "string" только для чтения
|
||||
bool open(const PIString & string);
|
||||
|
||||
|
||||
//! \~english Returns if position is at the end of content
|
||||
//! \~russian Возвращает в конце содержимого ли позиция
|
||||
bool isEnd() const {if (!str) return true; return pos >= str->size_s();}
|
||||
|
||||
|
||||
bool isEnd() const {
|
||||
if (!str) return true;
|
||||
return pos >= str->size_s();
|
||||
}
|
||||
|
||||
|
||||
//! \~english Move read/write position to "position"
|
||||
//! \~russian Перемещает позицию чтения/записи на "position"
|
||||
void seek(llong position) {pos = position;}
|
||||
|
||||
void seek(llong position) { pos = position; }
|
||||
|
||||
//! \~english Move read/write position to the beginning of the string
|
||||
//! \~russian Перемещает позицию чтения/записи на начало строки
|
||||
void seekToBegin() {if (str) pos = 0;}
|
||||
|
||||
void seekToBegin() {
|
||||
if (str) pos = 0;
|
||||
}
|
||||
|
||||
//! \~english Move read/write position to the end of the string
|
||||
//! \~russian Перемещает позицию чтения/записи на конец строки
|
||||
void seekToEnd() {if (str) pos = str->size_s();}
|
||||
|
||||
|
||||
void seekToEnd() {
|
||||
if (str) pos = str->size_s();
|
||||
}
|
||||
|
||||
|
||||
//! \~english Read one text line and return it
|
||||
//! \~russian Читает одну строку и возвращает её
|
||||
PIString readLine();
|
||||
|
||||
|
||||
//! \~english Insert string "string" into content at current position
|
||||
//! \~russian Вставляет строку "string" в содержимое буфера в текущую позицию
|
||||
int writeString(const PIString & string);
|
||||
|
||||
|
||||
ssize_t bytesAvailable() const override {
|
||||
if (str) return str->size() - pos;
|
||||
else return 0;
|
||||
if (str)
|
||||
return str->size() - pos;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool openDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Sequential | PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Sequential | PIIODevice::Reliable; }
|
||||
|
||||
ssize_t pos;
|
||||
PIString * str;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIIOSTRING_H
|
||||
|
||||
@@ -1,49 +1,61 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pipeer.h"
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "pidatatransfer.h"
|
||||
#include "pipropertystorage.h"
|
||||
|
||||
#define _PIPEER_MSG_SIZE 4000
|
||||
#define _PIPEER_MSG_TTL 100
|
||||
#define _PIPEER_MULTICAST_TTL 4
|
||||
#define _PIPEER_MULTICAST_IP "232.13.3.12"
|
||||
#define _PIPEER_LOOPBACK_PORT_S 13313
|
||||
#define _PIPEER_LOOPBACK_PORT_E (13313+32)
|
||||
#define _PIPEER_MULTICAST_PORT 13360
|
||||
#define _PIPEER_TCP_PORT _PIPEER_MULTICAST_PORT
|
||||
#define _PIPEER_BROADCAST_PORT 13361
|
||||
#define _PIPEER_TRAFFIC_PORT_S 13400
|
||||
#define _PIPEER_TRAFFIC_PORT_E 14000
|
||||
#define _PIPEER_PING_TIMEOUT 5.0
|
||||
#define _PIPEER_MSG_SIZE 4000
|
||||
#define _PIPEER_MSG_TTL 100
|
||||
#define _PIPEER_MULTICAST_TTL 4
|
||||
#define _PIPEER_MULTICAST_IP "232.13.3.12"
|
||||
#define _PIPEER_LOOPBACK_PORT_S 13313
|
||||
#define _PIPEER_LOOPBACK_PORT_E (13313 + 32)
|
||||
#define _PIPEER_MULTICAST_PORT 13360
|
||||
#define _PIPEER_TCP_PORT _PIPEER_MULTICAST_PORT
|
||||
#define _PIPEER_BROADCAST_PORT 13361
|
||||
#define _PIPEER_TRAFFIC_PORT_S 13400
|
||||
#define _PIPEER_TRAFFIC_PORT_E 14000
|
||||
#define _PIPEER_PING_TIMEOUT 5.0
|
||||
|
||||
class PIPeer::PeerData: public PIObject {
|
||||
PIOBJECT_SUBCLASS(PeerData, PIObject);
|
||||
|
||||
public:
|
||||
PeerData(const PIString & n);
|
||||
~PeerData();
|
||||
EVENT_HANDLER1(void, dtSendRequestIn, PIByteArray &, data) {data.push_front(uchar(2)); sendRequest(name(), data);}
|
||||
EVENT_HANDLER1(void, dtSendRequestOut, PIByteArray &, data) {data.push_front(uchar(3)); sendRequest(name(), data);}
|
||||
EVENT_HANDLER1(void, dtReceiveFinishedIn, bool, ok) {if (ok) received(name(), dt_in.data());}
|
||||
EVENT_HANDLER1(void, dtReceiveFinishedOut, bool, ok) {if (ok) received(name(), dt_out.data());}
|
||||
EVENT_HANDLER1(void, dtSendRequestIn, PIByteArray &, data) {
|
||||
data.push_front(uchar(2));
|
||||
sendRequest(name(), data);
|
||||
}
|
||||
EVENT_HANDLER1(void, dtSendRequestOut, PIByteArray &, data) {
|
||||
data.push_front(uchar(3));
|
||||
sendRequest(name(), data);
|
||||
}
|
||||
EVENT_HANDLER1(void, dtReceiveFinishedIn, bool, ok) {
|
||||
if (ok) received(name(), dt_in.data());
|
||||
}
|
||||
EVENT_HANDLER1(void, dtReceiveFinishedOut, bool, ok) {
|
||||
if (ok) received(name(), dt_out.data());
|
||||
}
|
||||
EVENT_HANDLER(void, dtThread);
|
||||
EVENT2(received, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT2(sendRequest, const PIString &, to, const PIByteArray &, data);
|
||||
@@ -73,19 +85,18 @@ PIPeer::PeerData::~PeerData() {
|
||||
dt_in.stop();
|
||||
dt_out.stop();
|
||||
t.stop();
|
||||
if (!t.waitForFinish(1000))
|
||||
t.terminate();
|
||||
if (!t.waitForFinish(1000)) t.terminate();
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::PeerData::dtThread() {
|
||||
dt_out.send(data);
|
||||
//piCoutObj << "send DT done";
|
||||
// piCoutObj << "send DT done";
|
||||
}
|
||||
|
||||
|
||||
bool PIPeer::PeerData::send(const PIByteArray & d) {
|
||||
//piCout << "send ..." << t.isRunning();
|
||||
// piCout << "send ..." << t.isRunning();
|
||||
if (t.isRunning()) return false;
|
||||
data = d;
|
||||
t.startOnce();
|
||||
@@ -95,13 +106,11 @@ bool PIPeer::PeerData::send(const PIByteArray & d) {
|
||||
|
||||
void PIPeer::PeerData::receivedPacket(uchar type, const PIByteArray & d) {
|
||||
PIDataTransfer * dt = 0;
|
||||
if (type == 3)
|
||||
dt = &dt_in;
|
||||
if (type == 2)
|
||||
dt = &dt_out;
|
||||
//piCoutObj << "DT received" << int(type) << d.size_s() << "...";
|
||||
if (type == 3) dt = &dt_in;
|
||||
if (type == 2) dt = &dt_out;
|
||||
// piCoutObj << "DT received" << int(type) << d.size_s() << "...";
|
||||
if (dt) dt->received(d);
|
||||
//piCoutObj << "DT received" << int(type) << d.size_s() << "done";
|
||||
// piCoutObj << "DT received" << int(type) << d.size_s() << "done";
|
||||
}
|
||||
|
||||
|
||||
@@ -110,10 +119,8 @@ void PIPeer::PeerData::setDist(int dist) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIPeer::PeerInfo::PeerAddress::PeerAddress(const PIEthernet::Address & a, const PIEthernet::Address & m): address(a), netmask(m) {
|
||||
ping = -1.;
|
||||
ping = -1.;
|
||||
wait_ping = false;
|
||||
last_ping = PISystemTime::current(true);
|
||||
}
|
||||
@@ -121,10 +128,12 @@ PIPeer::PeerInfo::PeerAddress::PeerAddress(const PIEthernet::Address & a, const
|
||||
|
||||
int PIPeer::PeerInfo::ping() const {
|
||||
int ret = -1;
|
||||
piForeachC (PeerAddress & a, addresses)
|
||||
piForeachC(PeerAddress & a, addresses)
|
||||
if (a.ping > 0.) {
|
||||
if (ret < 0) ret = piRoundd(a.ping);
|
||||
else ret = piMini(ret, piRoundd(a.ping));
|
||||
if (ret < 0)
|
||||
ret = piRoundd(a.ping);
|
||||
else
|
||||
ret = piMini(ret, piRoundd(a.ping));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -144,10 +153,10 @@ void PIPeer::PeerInfo::destroy() {
|
||||
PIEthernet::Address PIPeer::PeerInfo::fastestAddress() const {
|
||||
double mp = -1.;
|
||||
PIEthernet::Address ret;
|
||||
piForeachC (PeerAddress & a, addresses) {
|
||||
piForeachC(PeerAddress & a, addresses) {
|
||||
if (a.ping <= 0.) continue;
|
||||
if ((mp < 0) || (mp > a.ping)) {
|
||||
mp = a.ping;
|
||||
mp = a.ping;
|
||||
ret = a.address;
|
||||
}
|
||||
}
|
||||
@@ -157,9 +166,15 @@ PIEthernet::Address PIPeer::PeerInfo::fastestAddress() const {
|
||||
|
||||
REGISTER_DEVICE(PIPeer)
|
||||
|
||||
PIPeer::PIPeer(const PIString & n): PIIODevice(), inited__(false), eth_tcp_srv(PIEthernet::TCP_Server), eth_tcp_cli(PIEthernet::TCP_Client), diag_s(false), diag_d(false) {
|
||||
PIPeer::PIPeer(const PIString & n)
|
||||
: PIIODevice()
|
||||
, inited__(false)
|
||||
, eth_tcp_srv(PIEthernet::TCP_Server)
|
||||
, eth_tcp_cli(PIEthernet::TCP_Client)
|
||||
, diag_s(false)
|
||||
, diag_d(false) {
|
||||
sync_timer.setName("__S__.PIPeer.sync_timer");
|
||||
//piCout << " PIPeer" << uint(this);
|
||||
// piCout << " PIPeer" << uint(this);
|
||||
destroyed = false;
|
||||
setDebug(false);
|
||||
PIMutexLocker mbl(mc_mutex);
|
||||
@@ -169,18 +184,18 @@ PIPeer::PIPeer(const PIString & n): PIIODevice(), inited__(false), eth_tcp_srv(P
|
||||
changeName(n);
|
||||
setReopenTimeout(100);
|
||||
read_buffer_size = 128;
|
||||
self_info.dist = 0;
|
||||
self_info.time = PISystemTime::current();
|
||||
self_info.dist = 0;
|
||||
self_info.time = PISystemTime::current();
|
||||
randomize();
|
||||
CONNECT2(void, void *, int, &sync_timer, tickEvent, this, timerEvent);
|
||||
prev_ifaces = PIEthernet::interfaces();
|
||||
no_timer = false;
|
||||
no_timer = false;
|
||||
sync_timer.addDelimiter(5);
|
||||
}
|
||||
|
||||
|
||||
PIPeer::~PIPeer() {
|
||||
//piCout << "~PIPeer" << uint(this);
|
||||
// piCout << "~PIPeer" << uint(this);
|
||||
stop();
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
@@ -188,18 +203,18 @@ PIPeer::~PIPeer() {
|
||||
diag_s.stop();
|
||||
diag_d.stop();
|
||||
PIMutexLocker ml(peers_mutex);
|
||||
piForeach (PeerInfo & p, peers)
|
||||
piForeach(PeerInfo & p, peers)
|
||||
if (p._data) {
|
||||
p._data->dt_in.stop();
|
||||
p._data->dt_out.stop();
|
||||
p._data->t.stopAndWait();
|
||||
}
|
||||
destroyEths();
|
||||
piForeach (PIEthernet * i, eths_mcast) {
|
||||
piForeach(PIEthernet * i, eths_mcast) {
|
||||
if (!i) continue;
|
||||
i->stopThreadedRead();
|
||||
}
|
||||
piForeach (PIEthernet * i, eths_bcast) {
|
||||
piForeach(PIEthernet * i, eths_bcast) {
|
||||
if (!i) continue;
|
||||
i->stopThreadedRead();
|
||||
}
|
||||
@@ -209,20 +224,20 @@ PIPeer::~PIPeer() {
|
||||
sendSelfRemove();
|
||||
destroyMBcasts();
|
||||
eth_send.close();
|
||||
piForeach (PeerInfo & p, peers)
|
||||
piForeach(PeerInfo & p, peers)
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::timerEvent(void * data, int delim) {
|
||||
// piCoutObj << "timerEvent" << delim;
|
||||
// piCoutObj << "timerEvent" << delim;
|
||||
if (no_timer) return;
|
||||
switch (delim) {
|
||||
case 1: // every 1 s
|
||||
syncPeers();
|
||||
piMSleep(100);
|
||||
pingNeighbours();
|
||||
//piCoutObj << "isOpened" << isOpened();
|
||||
// piCoutObj << "isOpened" << isOpened();
|
||||
break;
|
||||
case 5: // every 5 s
|
||||
checkNetwork();
|
||||
@@ -232,10 +247,10 @@ void PIPeer::timerEvent(void * data, int delim) {
|
||||
|
||||
|
||||
void PIPeer::initEths(PIStringList al) {
|
||||
// piCoutObj << "initEths start";
|
||||
// piCoutObj << "initEths start";
|
||||
PIEthernet * ce;
|
||||
const PIEthernet::Interface * cint = 0;
|
||||
piForeachC (PIString & a, al) {
|
||||
piForeachC(PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_traffic_eth_rec_" + a);
|
||||
@@ -249,8 +264,8 @@ void PIPeer::initEths(PIStringList al) {
|
||||
self_info.addresses << PeerInfo::PeerAddress(ce->path(), cint == 0 ? "255.255.255.0" : cint->netmask);
|
||||
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, dataRead);
|
||||
ce->startThreadedRead();
|
||||
// piCoutObj << "dc binded to" << ce->path();
|
||||
// piCoutObj << "add eth" << a;
|
||||
// piCoutObj << "dc binded to" << ce->path();
|
||||
// piCoutObj << "add eth" << a;
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
@@ -260,7 +275,7 @@ void PIPeer::initEths(PIStringList al) {
|
||||
eth_send.setDebug(false);
|
||||
eth_send.setName("__S__PIPeer_traffic_eth_send");
|
||||
eth_send.setParameters(0);
|
||||
// piCoutObj << "initEths ok";
|
||||
// piCoutObj << "initEths ok";
|
||||
}
|
||||
|
||||
|
||||
@@ -269,9 +284,9 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
const PIEthernet::Interface * cint;
|
||||
PIString nm;
|
||||
al << _PIPEER_MULTICAST_IP;
|
||||
// piCoutObj << "initMBcasts start" << al;
|
||||
piForeachC (PIString & a, al) {
|
||||
//piCout << "mcast try" << a;
|
||||
// piCoutObj << "initMBcasts start" << al;
|
||||
piForeachC(PIString & a, al) {
|
||||
// piCout << "mcast try" << a;
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_mcast_eth_" + a);
|
||||
@@ -284,31 +299,31 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
eths_mcast << ce;
|
||||
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mbcastRead);
|
||||
ce->startThreadedRead();
|
||||
// piCout << "mcast bind to" << a << ce->sendIP();
|
||||
// piCout << "mcast bind to" << a << ce->sendIP();
|
||||
} else {
|
||||
delete ce;
|
||||
//piCoutObj << "invalid address for mcast" << a;
|
||||
// piCoutObj << "invalid address for mcast" << a;
|
||||
}
|
||||
}
|
||||
al.removeAll(_PIPEER_MULTICAST_IP);
|
||||
piForeachC (PIString & a, al) {
|
||||
piForeachC(PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_bcast_eth_" + a);
|
||||
ce->setParameters(PIEthernet::Broadcast);
|
||||
cint = prev_ifaces.getByAddress(a);
|
||||
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||
ce->setSendAddress(PIEthernet::getBroadcast(a, nm), _PIPEER_BROADCAST_PORT);
|
||||
ce->setReadAddress(a, _PIPEER_BROADCAST_PORT);
|
||||
if (ce->open()) {
|
||||
eths_bcast << ce;
|
||||
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mbcastRead);
|
||||
ce->startThreadedRead();
|
||||
// piCout << "mc BC try" << a << nm << ce->sendIP();
|
||||
// piCout << "bcast bind to" << a << nm;
|
||||
// piCout << "mc BC try" << a << nm << ce->sendIP();
|
||||
// piCout << "bcast bind to" << a << nm;
|
||||
} else {
|
||||
delete ce;
|
||||
//piCoutObj << "invalid address for bcast" << a;
|
||||
// piCoutObj << "invalid address for bcast" << a;
|
||||
}
|
||||
}
|
||||
eth_lo.setName("__S__PIPeer_eth_loopback");
|
||||
@@ -321,8 +336,8 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
eth_lo.setSendIP("127.0.0.1");
|
||||
CONNECT2(void, const uchar *, ssize_t, ð_lo, threadedReadEvent, this, mbcastRead);
|
||||
eth_lo.startThreadedRead();
|
||||
// piCout << "lo binded to" << eth_lo.readAddress() << eth_lo.sendAddress();
|
||||
//piCout << "add eth" << ta;
|
||||
// piCout << "lo binded to" << eth_lo.readAddress() << eth_lo.sendAddress();
|
||||
// piCout << "add eth" << ta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -339,16 +354,18 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
CONNECT2(void, const uchar *, ssize_t, ð_tcp_cli, threadedReadEvent, this, mbcastRead);
|
||||
CONNECTU(ð_tcp_cli, disconnected, this, tcpClientReconnect);
|
||||
eth_tcp_cli.startThreadedRead();
|
||||
if (eths_mcast.isEmpty() && eths_bcast.isEmpty() && !eth_lo.isOpened()) piCoutObj << "Warning! Can`t find suitable network interface for multicast receive, check for exists at least one interface with multicasting enabled!";
|
||||
// piCoutObj << "initMBcasts ok";
|
||||
if (eths_mcast.isEmpty() && eths_bcast.isEmpty() && !eth_lo.isOpened())
|
||||
piCoutObj << "Warning! Can`t find suitable network interface for multicast receive, check for exists at least one interface with "
|
||||
"multicasting enabled!";
|
||||
// piCoutObj << "initMBcasts ok";
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::destroyEths() {
|
||||
piForeach (PIEthernet * i, eths_traffic) {
|
||||
piForeach(PIEthernet * i, eths_traffic) {
|
||||
if (!i) continue;
|
||||
((PIThread*)i)->stop();
|
||||
((PIThread*)i)->waitForFinish(100);
|
||||
((PIThread *)i)->stop();
|
||||
((PIThread *)i)->waitForFinish(100);
|
||||
i->stopThreadedRead();
|
||||
i->close();
|
||||
delete i;
|
||||
@@ -359,10 +376,10 @@ void PIPeer::destroyEths() {
|
||||
|
||||
|
||||
void PIPeer::destroyMBcasts() {
|
||||
piForeach (PIEthernet * i, eths_mcast) {
|
||||
piForeach(PIEthernet * i, eths_mcast) {
|
||||
if (!i) continue;
|
||||
((PIThread*)i)->stop();
|
||||
((PIThread*)i)->waitForFinish(100);
|
||||
((PIThread *)i)->stop();
|
||||
((PIThread *)i)->waitForFinish(100);
|
||||
i->stopThreadedRead();
|
||||
i->leaveMulticastGroup(_PIPEER_MULTICAST_IP);
|
||||
i->close();
|
||||
@@ -370,18 +387,18 @@ void PIPeer::destroyMBcasts() {
|
||||
i = 0;
|
||||
}
|
||||
eths_mcast.clear();
|
||||
piForeach (PIEthernet * i, eths_bcast) {
|
||||
piForeach(PIEthernet * i, eths_bcast) {
|
||||
if (!i) continue;
|
||||
((PIThread*)i)->stop();
|
||||
((PIThread*)i)->waitForFinish(100);
|
||||
((PIThread *)i)->stop();
|
||||
((PIThread *)i)->waitForFinish(100);
|
||||
i->stopThreadedRead();
|
||||
i->close();
|
||||
delete i;
|
||||
i = 0;
|
||||
}
|
||||
eths_bcast.clear();
|
||||
((PIThread*)ð_lo)->stop();
|
||||
((PIThread*)ð_lo)->waitForFinish(100);
|
||||
((PIThread *)ð_lo)->stop();
|
||||
((PIThread *)ð_lo)->waitForFinish(100);
|
||||
eth_lo.stopThreadedRead();
|
||||
eth_lo.close();
|
||||
eth_tcp_srv.stop();
|
||||
@@ -390,8 +407,8 @@ void PIPeer::destroyMBcasts() {
|
||||
|
||||
PIPeer::PeerInfo * PIPeer::quickestPeer(const PIString & to) {
|
||||
if (!peers_map.contains(to)) return 0;
|
||||
//piCout << "*** search quickest peer" << to;
|
||||
PIVector<PeerInfo * > tp = addresses_map.value(to);
|
||||
// piCout << "*** search quickest peer" << to;
|
||||
PIVector<PeerInfo *> tp = addresses_map.value(to);
|
||||
if (tp.isEmpty()) return 0;
|
||||
return tp.back();
|
||||
}
|
||||
@@ -399,12 +416,12 @@ PIPeer::PeerInfo * PIPeer::quickestPeer(const PIString & to) {
|
||||
|
||||
bool PIPeer::send(const PIString & to, const void * data, int size) {
|
||||
PIByteArray ba(data, size);
|
||||
// piCoutObj << "send" << ba.size_s() << "bytes" << _PIPEER_MSG_SIZE;
|
||||
// piCoutObj << "send" << ba.size_s() << "bytes" << _PIPEER_MSG_SIZE;
|
||||
if (ba.size_s() <= _PIPEER_MSG_SIZE) {
|
||||
ba.insert(0, uchar(1));
|
||||
return sendInternal(to, ba);
|
||||
} else {
|
||||
//ba.insert(0, uchar(2));
|
||||
// ba.insert(0, uchar(2));
|
||||
PIMutexLocker mlocker(peers_mutex);
|
||||
PeerInfo * dp = const_cast<PeerInfo *>(getPeerByName(to));
|
||||
if (!dp) return false;
|
||||
@@ -418,14 +435,14 @@ bool PIPeer::sendInternal(const PIString & to, const PIByteArray & data) {
|
||||
PIMutexLocker mlocker(peers_mutex);
|
||||
PeerInfo * dp = quickestPeer(to);
|
||||
if (dp == 0) {
|
||||
//piCoutObj << "Can`t find peer \"" << to << "\"!";
|
||||
// piCoutObj << "Can`t find peer \"" << to << "\"!";
|
||||
return false;
|
||||
}
|
||||
PIByteArray ba;
|
||||
ba << int(4) << self_info.name << to << int(0) << data;
|
||||
// piCoutObj << "sendInternal to" << to << data.size_s() << int(data.front());
|
||||
// piCoutObj << "sendInternal to" << to << data.size_s() << int(data.front());
|
||||
if (!sendToNeighbour(dp, ba)) {
|
||||
//piCoutObj << "send error";
|
||||
// piCoutObj << "send error";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -446,7 +463,7 @@ void PIPeer::dtReceived(const PIString & from, const PIByteArray & data) {
|
||||
|
||||
bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
if (destroyed) {
|
||||
//piCout << "[PIPeer] SegFault";
|
||||
// piCout << "[PIPeer] SegFault";
|
||||
return true;
|
||||
}
|
||||
if (size < 16) return true;
|
||||
@@ -455,23 +472,22 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
PIString from, to;
|
||||
ba >> type;
|
||||
eth_mutex.lock();
|
||||
// piCout << "dataRead lock";
|
||||
// piCout << "dataRead lock";
|
||||
if (type == 5) { // ping request
|
||||
PIEthernet::Address addr;
|
||||
PISystemTime time;
|
||||
ba >> to >> from >> addr >> time;
|
||||
// piCout << "ping request" << to << from << addr;
|
||||
// piCout << "ping request" << to << from << addr;
|
||||
PIMutexLocker plocker(peers_mutex);
|
||||
if (from == self_info.name) { // send ping back
|
||||
const PeerInfo * pi = getPeerByName(to);
|
||||
if (pi) {
|
||||
if (pi->isNeighbour()) {
|
||||
sba << int(6) << to << from << addr << time;
|
||||
// piCout << " ping from" << from << addr << ", send back to" << pi->name;
|
||||
// piCout << " ping from" << from << addr << ", send back to" << pi->name;
|
||||
send_mutex.lock();
|
||||
piForeachC (PeerInfo::PeerAddress & a, pi->addresses) {
|
||||
if (eth_send.send(a.address, sba))
|
||||
diag_s.received(sba.size_s());
|
||||
piForeachC(PeerInfo::PeerAddress & a, pi->addresses) {
|
||||
if (eth_send.send(a.address, sba)) diag_s.received(sba.size_s());
|
||||
}
|
||||
send_mutex.unlock();
|
||||
}
|
||||
@@ -484,21 +500,23 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
PIEthernet::Address addr;
|
||||
PISystemTime time, ptime, ctime = PISystemTime::current(true);
|
||||
ba >> to >> from >> addr >> time;
|
||||
// piCout << "ping reply" << to << from << addr;
|
||||
// piCout << "ping reply" << to << from << addr;
|
||||
PIMutexLocker plocker(peers_mutex);
|
||||
if (to == self_info.name) { // ping echo
|
||||
piForeach (PeerInfo & p, peers) {
|
||||
piForeach(PeerInfo & p, peers) {
|
||||
if (!p.isNeighbour()) continue;
|
||||
if (p.name != from) continue;
|
||||
piForeach (PeerInfo::PeerAddress & a, p.addresses) {
|
||||
piForeach(PeerInfo::PeerAddress & a, p.addresses) {
|
||||
if (a.address != addr) continue;
|
||||
if (a.last_ping >= time) break;
|
||||
ptime = ctime - time;
|
||||
ptime = ctime - time;
|
||||
a.last_ping = time;
|
||||
a.wait_ping = false;
|
||||
if (a.ping < 0) a.ping = ptime.toMilliseconds();
|
||||
else a.ping = 0.6 * a.ping + 0.4 * ptime.toMilliseconds();
|
||||
// piCout << " ping echo" << p.name << a.address << a.ping;
|
||||
if (a.ping < 0)
|
||||
a.ping = ptime.toMilliseconds();
|
||||
else
|
||||
a.ping = 0.6 * a.ping + 0.4 * ptime.toMilliseconds();
|
||||
// piCout << " ping echo" << p.name << a.address << a.ping;
|
||||
eth_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
@@ -507,20 +525,20 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
eth_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
// piCoutObj << "received data from" << from << "packet" << type;
|
||||
// piCoutObj << "received data from" << from << "packet" << type;
|
||||
if (type != 4) {
|
||||
eth_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
diag_d.received(size);
|
||||
ba >> from >> to >> cnt >> pba;
|
||||
//piCoutObj << "Received packet" << type << from << to << pba.size_s();
|
||||
if (type == 4) { // data packet
|
||||
// piCoutObj << "Received packet" << type << from << to << pba.size_s();
|
||||
if (type == 4) { // data packet
|
||||
if (to == self_info.name) { // my packet
|
||||
uchar pt = pba.take_front();
|
||||
//piCoutObj << "Received packet" << type << from << to << int(pt) << pba.size_s();
|
||||
// piCoutObj << "Received packet" << type << from << to << int(pt) << pba.size_s();
|
||||
peers_mutex.lock();
|
||||
PeerInfo * fp = const_cast<PeerInfo * >(getPeerByName(from));
|
||||
PeerInfo * fp = const_cast<PeerInfo *>(getPeerByName(from));
|
||||
if (fp == 0) {
|
||||
peers_mutex.unlock();
|
||||
eth_mutex.unlock();
|
||||
@@ -535,8 +553,7 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
if (pt == 2 || pt == 3) {
|
||||
peers_mutex.unlock();
|
||||
eth_mutex.unlock();
|
||||
if (fp->_data)
|
||||
fp->_data->receivedPacket(pt, pba);
|
||||
if (fp->_data) fp->_data->receivedPacket(pt, pba);
|
||||
return true;
|
||||
}
|
||||
peers_mutex.unlock();
|
||||
@@ -546,14 +563,14 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
PIMutexLocker plocker(peers_mutex);
|
||||
PeerInfo * dp = quickestPeer(to);
|
||||
if (dp == 0) {
|
||||
//piCoutObj << "Can`t find peer \"" << to << "\"!";
|
||||
// piCoutObj << "Can`t find peer \"" << to << "\"!";
|
||||
eth_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
cnt++;
|
||||
if (cnt > _PIPEER_MSG_TTL || from == dp->name) return true;
|
||||
sba << type << from << to << cnt << pba;
|
||||
//piCout << "translate packet" << from << "->" << to << ", ttl =" << cnt;
|
||||
// piCout << "translate packet" << from << "->" << to << ", ttl =" << cnt;
|
||||
sendToNeighbour(dp, sba);
|
||||
}
|
||||
eth_mutex.unlock();
|
||||
@@ -563,7 +580,7 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
|
||||
|
||||
bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
if (destroyed) {
|
||||
//piCout << "[PIPeer] SegFault";
|
||||
// piCout << "[PIPeer] SegFault";
|
||||
return true;
|
||||
}
|
||||
if (size < 8) return true;
|
||||
@@ -573,17 +590,17 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
if (type <= 0 || type >= 4) return true;
|
||||
PeerInfo pi;
|
||||
ba >> pi.name;
|
||||
//piCout << "received mb from" << pi.name << "packet" << type;
|
||||
// piCout << "received mb from" << pi.name << "packet" << type;
|
||||
if (pi.name == self_info.name) return true;
|
||||
PIMutexLocker locker(mc_mutex);
|
||||
diag_s.received(size);
|
||||
const PeerInfo * rpi = 0;
|
||||
bool ch = false;
|
||||
bool ch = false;
|
||||
PIVector<PeerInfo> rpeers;
|
||||
//piCout << "analyz ...";
|
||||
// piCout << "analyz ...";
|
||||
switch (type) {
|
||||
case 1: // new peer
|
||||
//piCout << "new peer packet ...";
|
||||
// piCout << "new peer packet ...";
|
||||
peers_mutex.lock();
|
||||
if (!hasPeer(pi.name)) {
|
||||
ba >> pi;
|
||||
@@ -595,13 +612,13 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
pi.resetPing();
|
||||
addPeer(pi);
|
||||
buildMap();
|
||||
// piCoutObj << "new peer \"" << pi.name << "\"" << " dist " << pi.dist;
|
||||
// piCoutObj << mode() << opened_;
|
||||
// piCoutObj << "new peer \"" << pi.name << "\"" << " dist " << pi.dist;
|
||||
// piCoutObj << mode() << opened_;
|
||||
pi.dist++;
|
||||
sendSelfInfo();
|
||||
sendPeerInfo(pi);
|
||||
ch = true;
|
||||
//piCout << "new peer packet ok";
|
||||
// piCout << "new peer packet ok";
|
||||
}
|
||||
peers_mutex.unlock();
|
||||
if (ch) {
|
||||
@@ -610,7 +627,7 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
}
|
||||
break;
|
||||
case 2: // remove peer
|
||||
//piCout << "remove peer packet ..." << pi.name;
|
||||
// piCout << "remove peer packet ..." << pi.name;
|
||||
peers_mutex.lock();
|
||||
removeNeighbour(pi.name);
|
||||
rpi = getPeerByName(pi.name);
|
||||
@@ -618,13 +635,12 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
dist = rpi->dist;
|
||||
addToRemoved(*rpi);
|
||||
removePeer(pi.name);
|
||||
//piCoutObj << "remove peer \"" << pi.name << "\"";
|
||||
if (dist == 0)
|
||||
self_info.removeNeighbour(pi.name);
|
||||
// piCoutObj << "remove peer \"" << pi.name << "\"";
|
||||
if (dist == 0) self_info.removeNeighbour(pi.name);
|
||||
sendPeerRemove(pi.name);
|
||||
buildMap();
|
||||
ch = true;
|
||||
//piCout << "remove peer packet ok";
|
||||
// piCout << "remove peer packet ok";
|
||||
}
|
||||
peers_mutex.unlock();
|
||||
if (ch) {
|
||||
@@ -633,13 +649,13 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
}
|
||||
break;
|
||||
case 3: // sync peers
|
||||
//piCout << "sync packet ...";
|
||||
// piCout << "sync packet ...";
|
||||
ba >> pi >> rpeers;
|
||||
rpeers << pi;
|
||||
//piCoutObj << "rec sync " << rpeers.size_s() << " peers";
|
||||
// piCoutObj << "rec sync " << rpeers.size_s() << " peers";
|
||||
peers_mutex.lock();
|
||||
if (!self_info.neighbours.contains(pi.name)) {
|
||||
//piCoutObj << "add new nei to me" << pi.name;
|
||||
// piCoutObj << "add new nei to me" << pi.name;
|
||||
self_info.addNeighbour(pi.name);
|
||||
PeerInfo * np = peers_map.value(pi.name);
|
||||
if (np) {
|
||||
@@ -648,21 +664,21 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
}
|
||||
ch = true;
|
||||
}
|
||||
piForeach (PeerInfo & rpeer, rpeers) {
|
||||
//piCout << " to sync " << rpeer.name;
|
||||
piForeach(PeerInfo & rpeer, rpeers) {
|
||||
// piCout << " to sync " << rpeer.name;
|
||||
if (rpeer.name == self_info.name) continue;
|
||||
bool exist = false;
|
||||
piForeach (PeerInfo & peer, peers) {
|
||||
piForeach(PeerInfo & peer, peers) {
|
||||
if (peer.name == rpeer.name) {
|
||||
exist = true;
|
||||
if (isPeerRecent(peer, rpeer)) {
|
||||
//piCout << "synced " << peer.name;
|
||||
// piCout << "synced " << peer.name;
|
||||
for (int z = 0; z < rpeer.addresses.size_s(); ++z) {
|
||||
PeerInfo::PeerAddress & ra(rpeer.addresses[z]);
|
||||
for (int k = 0; k < peer.addresses.size_s(); ++k) {
|
||||
PeerInfo::PeerAddress & a(peer.addresses[k]);
|
||||
if (ra.address == a.address) {
|
||||
ra.ping = a.ping;
|
||||
ra.ping = a.ping;
|
||||
ra.wait_ping = a.wait_ping;
|
||||
ra.last_ping = a.last_ping;
|
||||
break;
|
||||
@@ -670,9 +686,9 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
}
|
||||
}
|
||||
peer.was_update = true;
|
||||
peer.addresses = rpeer.addresses;
|
||||
peer.cnt = rpeer.cnt;
|
||||
peer.time = rpeer.time;
|
||||
peer.addresses = rpeer.addresses;
|
||||
peer.cnt = rpeer.cnt;
|
||||
peer.time = rpeer.time;
|
||||
peer.addNeighbours(rpeer.neighbours);
|
||||
rpeer.neighbours = peer.neighbours;
|
||||
if (peer.name == pi.name) peer.sync = 0;
|
||||
@@ -690,19 +706,18 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
peerConnected(rpeer.name);
|
||||
peerConnectedEvent(rpeer.name);
|
||||
}
|
||||
//piCout << "***";
|
||||
//piCout << self_info.name << self_info.neighbours;
|
||||
piForeach (PeerInfo & i, peers) {
|
||||
// piCout << "***";
|
||||
// piCout << self_info.name << self_info.neighbours;
|
||||
piForeach(PeerInfo & i, peers) {
|
||||
if (i.dist == 0) {
|
||||
self_info.addNeighbour(i.name);
|
||||
i.addNeighbour(self_info.name);
|
||||
}
|
||||
//piCout << i.name << i.neighbours;
|
||||
// piCout << i.name << i.neighbours;
|
||||
}
|
||||
if (ch)
|
||||
buildMap();
|
||||
if (ch) buildMap();
|
||||
peers_mutex.unlock();
|
||||
//piCoutObj << "after sync " << peers.size_s() << " peers";
|
||||
// piCoutObj << "after sync " << peers.size_s() << " peers";
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -711,10 +726,10 @@ bool PIPeer::mbcastRead(const uchar * data, ssize_t size) {
|
||||
|
||||
bool PIPeer::sendToNeighbour(PIPeer::PeerInfo * peer, const PIByteArray & ba) {
|
||||
PIEthernet::Address addr = peer->fastestAddress();
|
||||
//piCout << "[PIPeer] sendToNeighbour" << peer->name << addr << ba.size_s() << "bytes ...";
|
||||
// piCout << "[PIPeer] sendToNeighbour" << peer->name << addr << ba.size_s() << "bytes ...";
|
||||
send_mutex.lock();
|
||||
bool ok = eth_send.send(addr, ba);
|
||||
//piCout << "[PIPeer] sendToNeighbour" << (ok ? "ok" : "fail");
|
||||
// piCout << "[PIPeer] sendToNeighbour" << (ok ? "ok" : "fail");
|
||||
if (ok) diag_d.sended(ba.size_s());
|
||||
send_mutex.unlock();
|
||||
return ok;
|
||||
@@ -723,39 +738,34 @@ bool PIPeer::sendToNeighbour(PIPeer::PeerInfo * peer, const PIByteArray & ba) {
|
||||
|
||||
void PIPeer::sendMBcast(const PIByteArray & ba) {
|
||||
send_mc_mutex.lock();
|
||||
// piCout << "sendMBcast" << ba.size() << "bytes ...";
|
||||
piForeach (PIEthernet * e, eths_mcast) {
|
||||
// piCout << "sendMBcast" << ba.size() << "bytes ...";
|
||||
piForeach(PIEthernet * e, eths_mcast) {
|
||||
if (e->isOpened())
|
||||
if (e->send(ba))
|
||||
diag_s.sended(ba.size_s());
|
||||
if (e->send(ba)) diag_s.sended(ba.size_s());
|
||||
}
|
||||
piForeach (PIEthernet * e, eths_bcast) {
|
||||
piForeach(PIEthernet * e, eths_bcast) {
|
||||
if (e->isOpened())
|
||||
if (e->send(ba))
|
||||
diag_s.sended(ba.size_s());
|
||||
if (e->send(ba)) diag_s.sended(ba.size_s());
|
||||
}
|
||||
for (int p = _PIPEER_LOOPBACK_PORT_S; p <= _PIPEER_LOOPBACK_PORT_E; ++p) {
|
||||
eth_lo.setSendPort(p);
|
||||
if (eth_lo.send(ba))
|
||||
diag_s.sended(ba.size_s());
|
||||
if (eth_lo.send(ba)) diag_s.sended(ba.size_s());
|
||||
}
|
||||
PIVector<PIEthernet * > cl = eth_tcp_srv.clients();
|
||||
piForeach (PIEthernet * e, cl) {
|
||||
PIVector<PIEthernet *> cl = eth_tcp_srv.clients();
|
||||
piForeach(PIEthernet * e, cl) {
|
||||
if (e->isOpened() && e->isConnected())
|
||||
if (e->send(ba))
|
||||
diag_s.sended(ba.size_s());
|
||||
if (e->send(ba)) diag_s.sended(ba.size_s());
|
||||
}
|
||||
if (eth_tcp_cli.isOpened() && eth_tcp_cli.isConnected()) {
|
||||
if (eth_tcp_cli.send(ba))
|
||||
diag_s.sended(ba.size_s());
|
||||
if (eth_tcp_cli.send(ba)) diag_s.sended(ba.size_s());
|
||||
}
|
||||
// piCout << "sendMBcast ok";
|
||||
// piCout << "sendMBcast ok";
|
||||
send_mc_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::removeNeighbour(const PIString & name) {
|
||||
piForeach (PeerInfo & p, peers)
|
||||
piForeach(PeerInfo & p, peers)
|
||||
p.neighbours.removeOne(name);
|
||||
self_info.removeNeighbour(name);
|
||||
}
|
||||
@@ -789,7 +799,7 @@ void PIPeer::sendPeerInfo(const PeerInfo & info) {
|
||||
|
||||
|
||||
void PIPeer::sendPeerRemove(const PIString & peer) {
|
||||
//piCout << name() << "sendPeerRemove" << peer;
|
||||
// piCout << name() << "sendPeerRemove" << peer;
|
||||
PIByteArray ba;
|
||||
ba << int(2) << peer;
|
||||
sendMBcast(ba);
|
||||
@@ -800,28 +810,26 @@ void PIPeer::pingNeighbours() {
|
||||
PIMutexLocker ml(peers_mutex);
|
||||
PIByteArray ba, sba;
|
||||
ba << int(5) << self_info.name;
|
||||
// piCoutObj << "*** pingNeighbours" << peers.size() << "...";
|
||||
piForeach (PeerInfo & p, peers) {
|
||||
// piCoutObj << "*** pingNeighbours" << peers.size() << "...";
|
||||
piForeach(PeerInfo & p, peers) {
|
||||
if (!p.isNeighbour()) continue;
|
||||
//piCout << " ping neighbour" << p.name << p.ping();
|
||||
// piCout << " ping neighbour" << p.name << p.ping();
|
||||
send_mutex.lock();
|
||||
piForeach (PeerInfo::PeerAddress & a, p.addresses) {
|
||||
// piCout << " address" << a.address << a.wait_ping;
|
||||
piForeach(PeerInfo::PeerAddress & a, p.addresses) {
|
||||
// piCout << " address" << a.address << a.wait_ping;
|
||||
if (a.wait_ping) {
|
||||
if ((PISystemTime::current(true) - a.last_ping).abs().toSeconds() <= _PIPEER_PING_TIMEOUT)
|
||||
continue;
|
||||
if ((PISystemTime::current(true) - a.last_ping).abs().toSeconds() <= _PIPEER_PING_TIMEOUT) continue;
|
||||
a.ping = -1.;
|
||||
}
|
||||
a.wait_ping = true;
|
||||
sba = ba;
|
||||
sba = ba;
|
||||
sba << p.name << a.address << PISystemTime::current(true);
|
||||
// piCout << "ping" << p.name << a.address << a.last_ping;
|
||||
if (eth_send.send(a.address, sba))
|
||||
diag_s.sended(sba.size_s());
|
||||
// piCout << "ping" << p.name << a.address << a.last_ping;
|
||||
if (eth_send.send(a.address, sba)) diag_s.sended(sba.size_s());
|
||||
}
|
||||
send_mutex.unlock();
|
||||
}
|
||||
//piCout << "*** pingNeighbours" << peers.size() << "done";
|
||||
// piCout << "*** pingNeighbours" << peers.size() << "done";
|
||||
}
|
||||
|
||||
|
||||
@@ -832,12 +840,13 @@ bool PIPeer::openDevice() {
|
||||
#else
|
||||
"pip.conf"
|
||||
#endif
|
||||
, PIIODevice::ReadOnly);
|
||||
,
|
||||
PIIODevice::ReadOnly);
|
||||
server_ip = conf.getValue("peer_server_ip", "").toString();
|
||||
reinit();
|
||||
diag_d.reset();
|
||||
diag_s.reset();
|
||||
//piCoutObj << "open...";
|
||||
// piCoutObj << "open...";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -848,9 +857,9 @@ bool PIPeer::closeDevice() {
|
||||
|
||||
|
||||
void PIPeer::syncPeers() {
|
||||
//piCout << "[PIPeer \"" + self_info.name + "\"] sync " << peers.size_s() << " peers";
|
||||
// piCout << "[PIPeer \"" + self_info.name + "\"] sync " << peers.size_s() << " peers";
|
||||
PIMutexLocker locker(eth_mutex);
|
||||
// piCout << "syncPeers lock";
|
||||
// piCout << "syncPeers lock";
|
||||
PIString pn;
|
||||
bool change = false;
|
||||
PIStringList dpeers;
|
||||
@@ -859,7 +868,7 @@ void PIPeer::syncPeers() {
|
||||
PeerInfo & cp(peers[i]);
|
||||
if (cp.sync > 3) {
|
||||
pn = cp.name;
|
||||
//piCout << "sync: remove " << pn;
|
||||
// piCout << "sync: remove " << pn;
|
||||
cp.destroy();
|
||||
addToRemoved(cp);
|
||||
peers.remove(i);
|
||||
@@ -874,8 +883,7 @@ void PIPeer::syncPeers() {
|
||||
cp.sync = 0;
|
||||
else
|
||||
cp.sync++;
|
||||
if (cp._data)
|
||||
cp._data->setDist(cp.dist + 1);
|
||||
if (cp._data) cp._data->setDist(cp.dist + 1);
|
||||
cp.was_update = false;
|
||||
}
|
||||
if (change) buildMap();
|
||||
@@ -885,7 +893,7 @@ void PIPeer::syncPeers() {
|
||||
ba << int(3) << self_info.name << self_info << peers;
|
||||
peers_mutex.unlock();
|
||||
sendMBcast(ba);
|
||||
piForeachC (PIString & p, dpeers) {
|
||||
piForeachC(PIString & p, dpeers) {
|
||||
peerDisconnected(p);
|
||||
peerDisconnectedEvent(p);
|
||||
}
|
||||
@@ -904,7 +912,7 @@ void PIPeer::reinit() {
|
||||
no_timer = true;
|
||||
PIMutexLocker mbl(mc_mutex);
|
||||
PIMutexLocker ethl(eth_mutex);
|
||||
// piCout << "reinit lock";
|
||||
// piCout << "reinit lock";
|
||||
PIMutexLocker pl(peers_mutex);
|
||||
PIMutexLocker sl(send_mutex);
|
||||
initNetwork();
|
||||
@@ -914,13 +922,13 @@ void PIPeer::reinit() {
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::changeName(const PIString &new_name) {
|
||||
void PIPeer::changeName(const PIString & new_name) {
|
||||
PIString name_ = new_name;
|
||||
if (name_.isEmpty()) name_ = "rnd_" + PIString::fromNumber(randomi() % 1000);
|
||||
setName(name_);
|
||||
self_info.name = name_;
|
||||
diag_d.setName(name_+"_data");
|
||||
diag_s.setName(name_+"_service");
|
||||
diag_d.setName(name_ + "_data");
|
||||
diag_s.setName(name_ + "_service");
|
||||
}
|
||||
|
||||
|
||||
@@ -933,7 +941,7 @@ ssize_t PIPeer::bytesAvailable() const {
|
||||
}
|
||||
|
||||
|
||||
ssize_t PIPeer::readDevice(void *read_to, ssize_t max_size) {
|
||||
ssize_t PIPeer::readDevice(void * read_to, ssize_t max_size) {
|
||||
read_buffer_mutex.lock();
|
||||
bool empty = read_buffer.isEmpty();
|
||||
read_buffer_mutex.unlock();
|
||||
@@ -956,18 +964,19 @@ ssize_t PIPeer::readDevice(void *read_to, ssize_t max_size) {
|
||||
}
|
||||
|
||||
|
||||
ssize_t PIPeer::writeDevice(const void *data, ssize_t size) {
|
||||
ssize_t PIPeer::writeDevice(const void * data, ssize_t size) {
|
||||
if (trust_peer.isEmpty()) {
|
||||
sendToAll(data, size);
|
||||
return size;
|
||||
}
|
||||
if (send(trust_peer, data, size))
|
||||
return size;
|
||||
else return -1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::newTcpClient(PIEthernet *client) {
|
||||
void PIPeer::newTcpClient(PIEthernet * client) {
|
||||
client->setName("__S__PIPeer_eth_TCP_ServerClient" + client->path());
|
||||
piCoutObj << "client" << client->path();
|
||||
CONNECT2(void, const uchar *, ssize_t, client, threadedReadEvent, this, mbcastRead);
|
||||
@@ -1009,45 +1018,45 @@ void PIPeer::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
|
||||
|
||||
void PIPeer::initNetwork() {
|
||||
// piCoutObj << "initNetwork ...";
|
||||
// piCoutObj << "initNetwork ...";
|
||||
eth_send.init();
|
||||
destroyEths();
|
||||
destroyMBcasts();
|
||||
piMSleep(100);
|
||||
// piCoutObj << self_info.addresses.size();
|
||||
// piCoutObj << self_info.addresses.size();
|
||||
self_info.addresses.clear();
|
||||
PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
|
||||
PIStringList sl;
|
||||
for (const PIEthernet::Address & a : al) {
|
||||
for (const PIEthernet::Address & a: al) {
|
||||
sl << a.ipString();
|
||||
}
|
||||
initEths(sl);
|
||||
// piCoutObj << sl << self_info.addresses.size();
|
||||
// piCoutObj << sl << self_info.addresses.size();
|
||||
sl.removeAll("127.0.0.1");
|
||||
initMBcasts(sl);
|
||||
diag_d.start();
|
||||
diag_s.start();
|
||||
// piCoutObj << "initNetwork done";
|
||||
// piCoutObj << "initNetwork done";
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::buildMap() {
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] buildMap";
|
||||
// piCout << "[PIPeer \"" + name_ + "\"] buildMap";
|
||||
peers_map.clear();
|
||||
addresses_map.clear();
|
||||
piForeach (PeerInfo & i, peers) {
|
||||
i.trace = -1;
|
||||
piForeach(PeerInfo & i, peers) {
|
||||
i.trace = -1;
|
||||
peers_map[i.name] = &i;
|
||||
}
|
||||
PIVector<PeerInfo * > cwave, nwave;
|
||||
int cwi = 0;
|
||||
PIVector<PeerInfo *> cwave, nwave;
|
||||
int cwi = 0;
|
||||
self_info.trace = 0;
|
||||
cwave << &self_info;
|
||||
while (!cwave.isEmpty()) {
|
||||
nwave.clear();
|
||||
++cwi;
|
||||
piForeachC (PeerInfo * p, cwave) {
|
||||
piForeachC (PIString & nn, p->neighbours) {
|
||||
piForeachC(PeerInfo * p, cwave) {
|
||||
piForeachC(PIString & nn, p->neighbours) {
|
||||
PeerInfo * np = peers_map.value(nn);
|
||||
if (!np) continue;
|
||||
if (np->trace >= 0) continue;
|
||||
@@ -1057,15 +1066,15 @@ void PIPeer::buildMap() {
|
||||
}
|
||||
cwave = nwave;
|
||||
}
|
||||
PIVector<PeerInfo * > cpath;
|
||||
piForeach (PeerInfo & c, peers) {
|
||||
PIVector<PeerInfo *> cpath;
|
||||
piForeach(PeerInfo & c, peers) {
|
||||
cpath.clear();
|
||||
cpath << &c;
|
||||
cwave << &c;
|
||||
for (int w = c.trace - 1; w >= 0; --w) {
|
||||
nwave.clear();
|
||||
piForeachC (PeerInfo * p, cwave) {
|
||||
piForeachC (PIString & nn, p->neighbours) {
|
||||
piForeachC(PeerInfo * p, cwave) {
|
||||
piForeachC(PIString & nn, p->neighbours) {
|
||||
PeerInfo * np = peers_map.value(nn);
|
||||
if (!np) continue;
|
||||
if (np->trace != w) continue;
|
||||
@@ -1076,7 +1085,7 @@ void PIPeer::buildMap() {
|
||||
cwave = nwave;
|
||||
}
|
||||
addresses_map[c.name] = cpath;
|
||||
//piCout << "map" << c.name << "=" << cpath;
|
||||
// piCout << "map" << c.name << "=" << cpath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,36 +5,36 @@
|
||||
* \~russian Элемент пиринговой сети
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node, forming self-organized peering network
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node, forming self-organized peering network
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPEER_H
|
||||
#define PIPEER_H
|
||||
|
||||
#include "piethernet.h"
|
||||
#include "pidiagnostics.h"
|
||||
#include "piethernet.h"
|
||||
|
||||
class PIP_EXPORT PIPeer: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIPeer: public PIIODevice {
|
||||
PIIODEVICE(PIPeer, "peer");
|
||||
|
||||
private:
|
||||
class PeerData;
|
||||
|
||||
|
||||
public:
|
||||
explicit PIPeer(const PIString & name = PIString());
|
||||
virtual ~PIPeer();
|
||||
@@ -42,117 +42,156 @@ public:
|
||||
class PIP_EXPORT PeerInfo {
|
||||
friend class PIPeer;
|
||||
BINARY_STREAM_FRIEND(PIPeer::PeerInfo);
|
||||
|
||||
public:
|
||||
PeerInfo() {dist = sync = cnt = 0; trace = -1; was_update = false; _data = 0;}
|
||||
PeerInfo() {
|
||||
dist = sync = cnt = 0;
|
||||
trace = -1;
|
||||
was_update = false;
|
||||
_data = 0;
|
||||
}
|
||||
~PeerInfo() {}
|
||||
|
||||
|
||||
struct PIP_EXPORT PeerAddress {
|
||||
PeerAddress(const PIEthernet::Address & a = PIEthernet::Address(), const PIEthernet::Address & m = PIEthernet::Address("255.255.255.0"));
|
||||
bool isAvailable() const {return ping > 0;}
|
||||
PeerAddress(const PIEthernet::Address & a = PIEthernet::Address(),
|
||||
const PIEthernet::Address & m = PIEthernet::Address("255.255.255.0"));
|
||||
bool isAvailable() const { return ping > 0; }
|
||||
PIEthernet::Address address;
|
||||
PIEthernet::Address netmask;
|
||||
double ping; // ms
|
||||
bool wait_ping;
|
||||
PISystemTime last_ping;
|
||||
};
|
||||
|
||||
|
||||
PIString name;
|
||||
PIVector<PeerAddress> addresses;
|
||||
int dist;
|
||||
PIStringList neighbours;
|
||||
|
||||
bool isNeighbour() const {return dist == 0;}
|
||||
|
||||
bool isNeighbour() const { return dist == 0; }
|
||||
int ping() const;
|
||||
PIEthernet::Address fastestAddress() const;
|
||||
|
||||
|
||||
protected:
|
||||
void addNeighbour(const PIString & n) {if (!neighbours.contains(n)) neighbours << n;}
|
||||
void addNeighbours(const PIStringList & l) {piForeachC (PIString & n, l) if (!neighbours.contains(n)) neighbours << n;}
|
||||
void removeNeighbour(const PIString & n) {neighbours.removeAll(n);}
|
||||
void resetPing() {for (int i = 0; i < addresses.size_s(); ++i) addresses[i].ping = -1;}
|
||||
void addNeighbour(const PIString & n) {
|
||||
if (!neighbours.contains(n)) neighbours << n;
|
||||
}
|
||||
void addNeighbours(const PIStringList & l) {
|
||||
piForeachC(PIString & n, l)
|
||||
if (!neighbours.contains(n)) neighbours << n;
|
||||
}
|
||||
void removeNeighbour(const PIString & n) { neighbours.removeAll(n); }
|
||||
void resetPing() {
|
||||
for (int i = 0; i < addresses.size_s(); ++i)
|
||||
addresses[i].ping = -1;
|
||||
}
|
||||
void init();
|
||||
void destroy();
|
||||
|
||||
|
||||
int sync, cnt, trace;
|
||||
bool was_update;
|
||||
PISystemTime time;
|
||||
PeerData * _data;
|
||||
|
||||
};
|
||||
|
||||
BINARY_STREAM_FRIEND(PIPeer::PeerInfo);
|
||||
|
||||
bool send(const PIString & to, const PIByteArray & data) {return send(to, data.data(), data.size_s());}
|
||||
bool send(const PIString & to, const PIString & data) {return send(to, data.data(), data.size_s());}
|
||||
bool send(const PIString & to, const PIByteArray & data) { return send(to, data.data(), data.size_s()); }
|
||||
bool send(const PIString & to, const PIString & data) { return send(to, data.data(), data.size_s()); }
|
||||
bool send(const PIString & to, const void * data, int size);
|
||||
bool send(const PeerInfo & to, const PIByteArray & data) {return send(to.name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo & to, const PIString & data) {return send(to.name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo & to, const void * data, int size) {return send(to.name, data, size);}
|
||||
bool send(const PeerInfo * to, const PIByteArray & data) {if (to == 0) return false; return send(to->name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo * to, const PIString & data) {if (to == 0) return false; return send(to->name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo * to, const void * data, int size) {if (to == 0) return false; return send(to->name, data, size);}
|
||||
void sendToAll(const PIByteArray & data) {piForeachC (PeerInfo & i, peers) send(i.name, data.data(), data.size_s());}
|
||||
void sendToAll(const PIString & data) {piForeachC (PeerInfo & i, peers) send(i.name, data.data(), data.size_s());}
|
||||
void sendToAll(const void * data, int size) {piForeachC (PeerInfo & i, peers) send(i.name, data, size);}
|
||||
|
||||
bool isMulticastReceive() const {return !eths_mcast.isEmpty();}
|
||||
bool isBroadcastReceive() const {return !eths_bcast.isEmpty();}
|
||||
|
||||
PIDiagnostics & diagnosticService() {return diag_s;}
|
||||
PIDiagnostics & diagnosticData() {return diag_d;}
|
||||
|
||||
const PIVector<PIPeer::PeerInfo> & allPeers() const {return peers;}
|
||||
bool isPeerExists(const PIString & name) const {return getPeerByName(name) != 0;}
|
||||
|
||||
const PeerInfo * getPeerByName(const PIString & name) const {return peers_map.value(name, 0);}
|
||||
const PeerInfo & selfInfo() const {return self_info;}
|
||||
const PIMap<PIString, PIVector<PeerInfo * > > & _peerMap() const {return addresses_map;}
|
||||
|
||||
bool send(const PeerInfo & to, const PIByteArray & data) { return send(to.name, data.data(), data.size_s()); }
|
||||
bool send(const PeerInfo & to, const PIString & data) { return send(to.name, data.data(), data.size_s()); }
|
||||
bool send(const PeerInfo & to, const void * data, int size) { return send(to.name, data, size); }
|
||||
bool send(const PeerInfo * to, const PIByteArray & data) {
|
||||
if (to == 0) return false;
|
||||
return send(to->name, data.data(), data.size_s());
|
||||
}
|
||||
bool send(const PeerInfo * to, const PIString & data) {
|
||||
if (to == 0) return false;
|
||||
return send(to->name, data.data(), data.size_s());
|
||||
}
|
||||
bool send(const PeerInfo * to, const void * data, int size) {
|
||||
if (to == 0) return false;
|
||||
return send(to->name, data, size);
|
||||
}
|
||||
void sendToAll(const PIByteArray & data) {
|
||||
piForeachC(PeerInfo & i, peers)
|
||||
send(i.name, data.data(), data.size_s());
|
||||
}
|
||||
void sendToAll(const PIString & data) {
|
||||
piForeachC(PeerInfo & i, peers)
|
||||
send(i.name, data.data(), data.size_s());
|
||||
}
|
||||
void sendToAll(const void * data, int size) {
|
||||
piForeachC(PeerInfo & i, peers)
|
||||
send(i.name, data, size);
|
||||
}
|
||||
|
||||
bool isMulticastReceive() const { return !eths_mcast.isEmpty(); }
|
||||
bool isBroadcastReceive() const { return !eths_bcast.isEmpty(); }
|
||||
|
||||
PIDiagnostics & diagnosticService() { return diag_s; }
|
||||
PIDiagnostics & diagnosticData() { return diag_d; }
|
||||
|
||||
const PIVector<PIPeer::PeerInfo> & allPeers() const { return peers; }
|
||||
bool isPeerExists(const PIString & name) const { return getPeerByName(name) != 0; }
|
||||
|
||||
const PeerInfo * getPeerByName(const PIString & name) const { return peers_map.value(name, 0); }
|
||||
const PeerInfo & selfInfo() const { return self_info; }
|
||||
const PIMap<PIString, PIVector<PeerInfo *>> & _peerMap() const { return addresses_map; }
|
||||
|
||||
void reinit();
|
||||
void lock() {peers_mutex.lock();}
|
||||
void unlock() {peers_mutex.unlock();}
|
||||
void lock() { peers_mutex.lock(); }
|
||||
void unlock() { peers_mutex.unlock(); }
|
||||
void changeName(const PIString & new_name);
|
||||
const PIString & trustPeerName() const {return trust_peer;}
|
||||
void setTrustPeerName(const PIString & peer_name) {trust_peer = peer_name;}
|
||||
void setTcpServerIP(const PIString & ip) {server_ip = ip; tcpClientReconnect();}
|
||||
const PIString & trustPeerName() const { return trust_peer; }
|
||||
void setTrustPeerName(const PIString & peer_name) { trust_peer = peer_name; }
|
||||
void setTcpServerIP(const PIString & ip) {
|
||||
server_ip = ip;
|
||||
tcpClientReconnect();
|
||||
}
|
||||
|
||||
ssize_t bytesAvailable() const override;
|
||||
|
||||
|
||||
|
||||
EVENT2(dataReceivedEvent, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT1(peerConnectedEvent, const PIString &, name);
|
||||
EVENT1(peerDisconnectedEvent, const PIString &, name);
|
||||
|
||||
// bool lockedEth() const {return eth_mutex.isLocked();}
|
||||
// bool lockedPeers() const {return peers_mutex.isLocked();}
|
||||
// bool lockedMBcasts() const {return mc_mutex.isLocked();}
|
||||
// bool lockedSends() const {return send_mutex.isLocked();}
|
||||
// bool lockedMCSends() const {return send_mc_mutex.isLocked();}
|
||||
|
||||
// bool lockedEth() const {return eth_mutex.isLocked();}
|
||||
// bool lockedPeers() const {return peers_mutex.isLocked();}
|
||||
// bool lockedMBcasts() const {return mc_mutex.isLocked();}
|
||||
// bool lockedSends() const {return send_mutex.isLocked();}
|
||||
// bool lockedMCSends() const {return send_mc_mutex.isLocked();}
|
||||
|
||||
protected:
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data) {;}
|
||||
virtual void peerConnected(const PIString & name) {;}
|
||||
virtual void peerDisconnected(const PIString & name) {;}
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data) { ; }
|
||||
virtual void peerConnected(const PIString & name) { ; }
|
||||
virtual void peerDisconnected(const PIString & name) { ; }
|
||||
|
||||
EVENT_HANDLER2(bool, dataRead, const uchar *, readed, ssize_t, size);
|
||||
EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size);
|
||||
|
||||
|
||||
private:
|
||||
EVENT_HANDLER2(void, timerEvent, void * , data, int, delim);
|
||||
EVENT_HANDLER2(void, timerEvent, void *, data, int, delim);
|
||||
EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data);
|
||||
EVENT_HANDLER2(void, dtReceived, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT_HANDLER1(void, newTcpClient, PIEthernet * , client);
|
||||
EVENT_HANDLER1(void, newTcpClient, PIEthernet *, client);
|
||||
EVENT_HANDLER(void, tcpClientReconnect);
|
||||
|
||||
bool hasPeer(const PIString & name) {piForeachC (PeerInfo & i, peers) if (i.name == name) return true; return false;}
|
||||
bool hasPeer(const PIString & name) {
|
||||
piForeachC(PeerInfo & i, peers)
|
||||
if (i.name == name) return true;
|
||||
return false;
|
||||
}
|
||||
bool removePeer(const PIString & name);
|
||||
void removeNeighbour(const PIString & name);
|
||||
void addPeer(const PeerInfo & pd);
|
||||
|
||||
void sendPeerInfo(const PeerInfo & info);
|
||||
void sendPeerRemove(const PIString & peer);
|
||||
void sendSelfInfo() {sendPeerInfo(self_info);}
|
||||
void sendSelfRemove() {sendPeerRemove(self_info.name);}
|
||||
void sendSelfInfo() { sendPeerInfo(self_info); }
|
||||
void sendSelfRemove() { sendPeerRemove(self_info.name); }
|
||||
void syncPeers();
|
||||
void checkNetwork();
|
||||
void initNetwork();
|
||||
@@ -163,39 +202,41 @@ private:
|
||||
void destroyMBcasts();
|
||||
void sendMBcast(const PIByteArray & ba);
|
||||
void pingNeighbours();
|
||||
void addToRemoved(const PeerInfo & pi) {removed[pi.name] = PIPair<int, PISystemTime>(pi.cnt, pi.time);}
|
||||
bool isRemoved(const PeerInfo & pi) const {return (removed.value(pi.name) == PIPair<int, PISystemTime>(pi.cnt, pi.time));}
|
||||
void addToRemoved(const PeerInfo & pi) { removed[pi.name] = PIPair<int, PISystemTime>(pi.cnt, pi.time); }
|
||||
bool isRemoved(const PeerInfo & pi) const { return (removed.value(pi.name) == PIPair<int, PISystemTime>(pi.cnt, pi.time)); }
|
||||
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
PIString constructFullPathDevice() const override;
|
||||
void configureFromFullPathDevice(const PIString &full_path) override;
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
PeerInfo * quickestPeer(const PIString & to);
|
||||
bool sendToNeighbour(PeerInfo * peer, const PIByteArray & ba);
|
||||
inline static bool isPeerRecent(const PeerInfo & my, const PeerInfo & income) {return (my.cnt < income.cnt) || (my.time < income.time);}
|
||||
inline static bool isPeerRecent(const PeerInfo & my, const PeerInfo & income) {
|
||||
return (my.cnt < income.cnt) || (my.time < income.time);
|
||||
}
|
||||
|
||||
// 1 - new peer, 2 - remove peer, 3 - sync peers, 4 - data, 5 - ping request, 6 - ping reply
|
||||
// Data packet: 4, from, to, ticks, data_size, data
|
||||
|
||||
protected:
|
||||
bool inited__; //for internal use
|
||||
bool inited__; // for internal use
|
||||
|
||||
private:
|
||||
PIVector<PIEthernet * > eths_traffic, eths_mcast, eths_bcast;
|
||||
PIVector<PIEthernet *> eths_traffic, eths_mcast, eths_bcast;
|
||||
PIEthernet::InterfaceList prev_ifaces;
|
||||
PIEthernet eth_send, eth_lo, eth_tcp_srv, eth_tcp_cli;
|
||||
PITimer sync_timer;
|
||||
PeerInfo self_info;
|
||||
PIVector<PeerInfo> peers;
|
||||
PIMap<PIString, PeerInfo * > peers_map;
|
||||
PIMap<PIString, PIVector<PeerInfo * > > addresses_map; // map {"to" = list of nearest peers}
|
||||
PIMap<PIString, PIPair<int, PISystemTime> > removed;
|
||||
PIMap<PIString, PeerInfo *> peers_map;
|
||||
PIMap<PIString, PIVector<PeerInfo *>> addresses_map; // map {"to" = list of nearest peers}
|
||||
PIMap<PIString, PIPair<int, PISystemTime>> removed;
|
||||
PIDiagnostics diag_s, diag_d;
|
||||
bool destroyed, no_timer;
|
||||
PIString trust_peer;
|
||||
@@ -206,30 +247,50 @@ private:
|
||||
PIMutex mc_mutex, eth_mutex, peers_mutex, send_mutex, send_mc_mutex;
|
||||
};
|
||||
|
||||
inline PICout operator <<(PICout c, const PIPeer::PeerInfo::PeerAddress & v) {c.space(); c << "PeerAddress(" << v.address << ", " << v.netmask << ", " << v.ping << ")"; return c;}
|
||||
inline PICout operator <<(PICout c, const PIPeer::PeerInfo & v) {c.space(); c << "PeerInfo(" << v.name << ", " << v.dist << ", " << v.addresses << ")"; return c;}
|
||||
inline PICout operator<<(PICout c, const PIPeer::PeerInfo::PeerAddress & v) {
|
||||
c.space();
|
||||
c << "PeerAddress(" << v.address << ", " << v.netmask << ", " << v.ping << ")";
|
||||
return c;
|
||||
}
|
||||
inline PICout operator<<(PICout c, const PIPeer::PeerInfo & v) {
|
||||
c.space();
|
||||
c << "PeerInfo(" << v.name << ", " << v.dist << ", " << v.addresses << ")";
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIPeer::PeerInfo::PeerAddress) {s << v.address << v.netmask << v.ping; return s;}
|
||||
BINARY_STREAM_WRITE(PIPeer::PeerInfo::PeerAddress) {
|
||||
s << v.address << v.netmask << v.ping;
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIPeer::PeerInfo::PeerAddress) {s >> v.address >> v.netmask >> v.ping; return s;}
|
||||
BINARY_STREAM_READ(PIPeer::PeerInfo::PeerAddress) {
|
||||
s >> v.address >> v.netmask >> v.ping;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIPeer::PeerInfo) {s << v.name << v.addresses << v.dist << v.neighbours << v.cnt << v.time; return s;}
|
||||
BINARY_STREAM_WRITE(PIPeer::PeerInfo) {
|
||||
s << v.name << v.addresses << v.dist << v.neighbours << v.cnt << v.time;
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIPeer::PeerInfo) {s >> v.name >> v.addresses >> v.dist >> v.neighbours >> v.cnt >> v.time; return s;}
|
||||
BINARY_STREAM_READ(PIPeer::PeerInfo) {
|
||||
s >> v.name >> v.addresses >> v.dist >> v.neighbours >> v.cnt >> v.time;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIPEER_H
|
||||
|
||||
@@ -1,133 +1,137 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
COM
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
COM
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "piserial.h"
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "pidir.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "piwaitevent_p.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(MICRO_PIP)
|
||||
# define PISERIAL_NO_PINS
|
||||
#endif
|
||||
#if defined(PISERIAL_NO_PINS) || defined(WINDOWS)
|
||||
# define TIOCM_LE 1
|
||||
# define TIOCM_DTR 4
|
||||
# define TIOCM_RTS 7
|
||||
# define TIOCM_CTS 8
|
||||
# define TIOCM_ST 3
|
||||
# define TIOCM_SR 2
|
||||
# define TIOCM_CAR 1
|
||||
# define TIOCM_RNG 9
|
||||
# define TIOCM_DSR 6
|
||||
# define TIOCM_LE 1
|
||||
# define TIOCM_DTR 4
|
||||
# define TIOCM_RTS 7
|
||||
# define TIOCM_CTS 8
|
||||
# define TIOCM_ST 3
|
||||
# define TIOCM_SR 2
|
||||
# define TIOCM_CAR 1
|
||||
# define TIOCM_RNG 9
|
||||
# define TIOCM_DSR 6
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
# ifndef INITGUID
|
||||
# define INITGUID
|
||||
# include <guiddef.h>
|
||||
# undef INITGUID
|
||||
# define INITGUID
|
||||
# include <guiddef.h>
|
||||
# undef INITGUID
|
||||
# else
|
||||
# include <guiddef.h>
|
||||
# include <guiddef.h>
|
||||
# endif
|
||||
// clang-format off
|
||||
# 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
|
||||
# define B300 300
|
||||
# define B600 600
|
||||
# define B1200 1200
|
||||
# define B2400 2400
|
||||
# define B4800 4800
|
||||
# define B9600 9600
|
||||
# define B14400 14400
|
||||
# define B19200 19200
|
||||
# define B38400 38400
|
||||
# define B57600 57600
|
||||
# define B115200 115200
|
||||
# define B230400 230400
|
||||
# define B460800 460800
|
||||
# define B500000 500000
|
||||
# define B576000 576000
|
||||
# define B921600 921600
|
||||
# define B1000000 1000000
|
||||
# define B1152000 1152000
|
||||
# define B1500000 1500000
|
||||
# define B2000000 2000000
|
||||
# define B2500000 2500000
|
||||
# define B3000000 3000000
|
||||
# define B3500000 3500000
|
||||
# define B4000000 4000000
|
||||
// clang-format on
|
||||
# define B50 50
|
||||
# define B75 75
|
||||
# define B110 110
|
||||
# define B300 300
|
||||
# define B600 600
|
||||
# define B1200 1200
|
||||
# define B2400 2400
|
||||
# define B4800 4800
|
||||
# define B9600 9600
|
||||
# define B14400 14400
|
||||
# define B19200 19200
|
||||
# define B38400 38400
|
||||
# define B57600 57600
|
||||
# define B115200 115200
|
||||
# define B230400 230400
|
||||
# define B460800 460800
|
||||
# define B500000 500000
|
||||
# define B576000 576000
|
||||
# define B921600 921600
|
||||
# define B1000000 1000000
|
||||
# define B1152000 1152000
|
||||
# define B1500000 1500000
|
||||
# define B2000000 2000000
|
||||
# define B2500000 2500000
|
||||
# define B3000000 3000000
|
||||
# define B3500000 3500000
|
||||
# define B4000000 4000000
|
||||
#else
|
||||
# include <termios.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <termios.h>
|
||||
# ifndef B50
|
||||
# define B50 0000001
|
||||
# define B50 0000001
|
||||
# endif
|
||||
# ifndef B75
|
||||
# define B75 0000002
|
||||
# define B75 0000002
|
||||
# endif
|
||||
# ifndef B230400
|
||||
# define B230400 0010003
|
||||
# define B230400 0010003
|
||||
# endif
|
||||
# ifndef B460800
|
||||
# define B460800 0010004
|
||||
# define B460800 0010004
|
||||
# endif
|
||||
# ifndef B500000
|
||||
# define B500000 0010005
|
||||
# define B500000 0010005
|
||||
# endif
|
||||
# ifndef B576000
|
||||
# define B576000 0010006
|
||||
# define B576000 0010006
|
||||
# endif
|
||||
# ifndef B921600
|
||||
# define B921600 0010007
|
||||
# define B921600 0010007
|
||||
# endif
|
||||
# ifndef B1000000
|
||||
# define B1000000 0010010
|
||||
# define B1000000 0010010
|
||||
# endif
|
||||
# ifndef B1152000
|
||||
# define B1152000 0010011
|
||||
# define B1152000 0010011
|
||||
# endif
|
||||
# ifndef B1500000
|
||||
# define B1500000 0010012
|
||||
# define B1500000 0010012
|
||||
# endif
|
||||
# ifndef B2000000
|
||||
# define B2000000 0010013
|
||||
# define B2000000 0010013
|
||||
# endif
|
||||
# ifndef B2500000
|
||||
# define B2500000 0010014
|
||||
# define B2500000 0010014
|
||||
# endif
|
||||
# ifndef B3000000
|
||||
# define B3000000 0010015
|
||||
# define B3000000 0010015
|
||||
# endif
|
||||
# ifndef B3500000
|
||||
# define B3500000 0010016
|
||||
# define B3500000 0010016
|
||||
# endif
|
||||
# ifndef B4000000
|
||||
# define B4000000 0010017
|
||||
# define B4000000 0010017
|
||||
# endif
|
||||
#endif
|
||||
#ifndef CRTSCTS
|
||||
@@ -174,7 +178,7 @@ PRIVATE_DEFINITION_START(PISerial)
|
||||
#ifdef WINDOWS
|
||||
PIWaitEvent event_write;
|
||||
DCB desc, sdesc;
|
||||
HANDLE hCom = nullptr;
|
||||
HANDLE hCom = nullptr;
|
||||
DWORD readed = 0, mask = 0;
|
||||
OVERLAPPED overlap, overlap_write;
|
||||
#else
|
||||
@@ -184,22 +188,19 @@ PRIVATE_DEFINITION_START(PISerial)
|
||||
PRIVATE_DEFINITION_END(PISerial)
|
||||
|
||||
|
||||
|
||||
|
||||
PIString PISerial::DeviceInfo::id() const {
|
||||
return PIString::fromNumber(vID, 16).toLowerCase().expandLeftTo(4, '0') + ":" +
|
||||
PIString::fromNumber(pID, 16).toLowerCase().expandLeftTo(4, '0');
|
||||
PIString::fromNumber(pID, 16).toLowerCase().expandLeftTo(4, '0');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
||||
construct();
|
||||
}
|
||||
|
||||
|
||||
PISerial::PISerial(const PIString & device_, PISerial::Speed speed_, PIFlags<PISerial::Parameters> params_): PIIODevice(device_, ReadWrite) {
|
||||
PISerial::PISerial(const PIString & device_, PISerial::Speed speed_, PIFlags<PISerial::Parameters> params_)
|
||||
: PIIODevice(device_, ReadWrite) {
|
||||
construct();
|
||||
setPath(device_);
|
||||
setSpeed(speed_);
|
||||
@@ -219,7 +220,7 @@ PISerial::~PISerial() {
|
||||
|
||||
void PISerial::construct() {
|
||||
sending = false;
|
||||
//setPriority(piHigh);
|
||||
// setPriority(piHigh);
|
||||
setParameters(0);
|
||||
setSpeed(S115200);
|
||||
setDataBitsCount(8);
|
||||
@@ -245,16 +246,12 @@ bool PISerial::setPin(int number, bool on) {
|
||||
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 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;
|
||||
default: piCoutObj << "Pin number " << number << " doesn`t exists!"; return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -271,32 +268,66 @@ bool PISerial::isPin(int number) const {
|
||||
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;
|
||||
default: piCoutObj << "Pin number " << number << " doesn`t exists!"; return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PISerial::setLE(bool on) {return setBit(TIOCM_LE, on, "LE");}
|
||||
bool PISerial::setDTR(bool on) {return setBit(TIOCM_DTR, on, "DTR");}
|
||||
bool PISerial::setRTS(bool on) {return setBit(TIOCM_RTS, on, "RTS");}
|
||||
bool PISerial::setCTS(bool on) {return setBit(TIOCM_CTS, on, "CTS");}
|
||||
bool PISerial::setST(bool on) {return setBit(TIOCM_ST, on, "ST");}
|
||||
bool PISerial::setSR(bool on) {return setBit(TIOCM_SR, on, "SR");}
|
||||
bool PISerial::setCAR(bool on) {return setBit(TIOCM_CAR, on, "CAR");}
|
||||
bool PISerial::setRNG(bool on) {return setBit(TIOCM_RNG, on, "RNG");}
|
||||
bool PISerial::setDSR(bool on) {return setBit(TIOCM_DSR, on, "DSR");}
|
||||
bool PISerial::setLE(bool on) {
|
||||
return setBit(TIOCM_LE, on, "LE");
|
||||
}
|
||||
bool PISerial::setDTR(bool on) {
|
||||
return setBit(TIOCM_DTR, on, "DTR");
|
||||
}
|
||||
bool PISerial::setRTS(bool on) {
|
||||
return setBit(TIOCM_RTS, on, "RTS");
|
||||
}
|
||||
bool PISerial::setCTS(bool on) {
|
||||
return setBit(TIOCM_CTS, on, "CTS");
|
||||
}
|
||||
bool PISerial::setST(bool on) {
|
||||
return setBit(TIOCM_ST, on, "ST");
|
||||
}
|
||||
bool PISerial::setSR(bool on) {
|
||||
return setBit(TIOCM_SR, on, "SR");
|
||||
}
|
||||
bool PISerial::setCAR(bool on) {
|
||||
return setBit(TIOCM_CAR, on, "CAR");
|
||||
}
|
||||
bool PISerial::setRNG(bool on) {
|
||||
return setBit(TIOCM_RNG, on, "RNG");
|
||||
}
|
||||
bool PISerial::setDSR(bool on) {
|
||||
return setBit(TIOCM_DSR, on, "DSR");
|
||||
}
|
||||
|
||||
bool PISerial::isLE() const {return isBit(TIOCM_LE, "LE");}
|
||||
bool PISerial::isDTR() const {return isBit(TIOCM_DTR, "DTR");}
|
||||
bool PISerial::isRTS() const {return isBit(TIOCM_RTS, "RTS");}
|
||||
bool PISerial::isCTS() const {return isBit(TIOCM_CTS, "CTS");}
|
||||
bool PISerial::isST() const {return isBit(TIOCM_ST, "ST");}
|
||||
bool PISerial::isSR() const {return isBit(TIOCM_SR, "SR");}
|
||||
bool PISerial::isCAR() const {return isBit(TIOCM_CAR, "CAR");}
|
||||
bool PISerial::isRNG() const {return isBit(TIOCM_RNG, "RNG");}
|
||||
bool PISerial::isDSR() const {return isBit(TIOCM_DSR, "DSR");}
|
||||
bool PISerial::isLE() const {
|
||||
return isBit(TIOCM_LE, "LE");
|
||||
}
|
||||
bool PISerial::isDTR() const {
|
||||
return isBit(TIOCM_DTR, "DTR");
|
||||
}
|
||||
bool PISerial::isRTS() const {
|
||||
return isBit(TIOCM_RTS, "RTS");
|
||||
}
|
||||
bool PISerial::isCTS() const {
|
||||
return isBit(TIOCM_CTS, "CTS");
|
||||
}
|
||||
bool PISerial::isST() const {
|
||||
return isBit(TIOCM_ST, "ST");
|
||||
}
|
||||
bool PISerial::isSR() const {
|
||||
return isBit(TIOCM_SR, "SR");
|
||||
}
|
||||
bool PISerial::isCAR() const {
|
||||
return isBit(TIOCM_CAR, "CAR");
|
||||
}
|
||||
bool PISerial::isRNG() const {
|
||||
return isBit(TIOCM_RNG, "RNG");
|
||||
}
|
||||
bool PISerial::isDSR() const {
|
||||
return isBit(TIOCM_DSR, "DSR");
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
@@ -349,9 +380,9 @@ bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
||||
}
|
||||
#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_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];
|
||||
int action = (on ? bit_map_on : bit_map_off)[bit];
|
||||
if (action > 0) {
|
||||
if (EscapeCommFunction(PRIVATE->hCom, action) == 0) {
|
||||
piCoutObj << "setBit" << bname << " error: " << errorString();
|
||||
@@ -381,8 +412,7 @@ bool PISerial::isBit(int bit, const PIString & bname) const {
|
||||
# ifdef WINDOWS
|
||||
# else
|
||||
int ret = 0;
|
||||
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
||||
piCoutObj << "isBit" << bname << " error: " << errorString();
|
||||
if (ioctl(fd, TIOCMGET, &ret) < 0) piCoutObj << "isBit" << bname << " error: " << errorString();
|
||||
return ret & bit;
|
||||
# endif
|
||||
#endif
|
||||
@@ -464,21 +494,23 @@ bool PISerial::read(void * data, int size, double timeout_ms) {
|
||||
int ret, all = 0;
|
||||
if (timeout_ms > 0.) {
|
||||
bool br = setOption(BlockingRead, false);
|
||||
all = readDevice(data, 1);
|
||||
all = readDevice(data, 1);
|
||||
tm_.reset();
|
||||
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
||||
ret = readDevice(&((uchar * )data)[all], size - all);
|
||||
if (ret > 0) all += ret;
|
||||
else piMinSleep();
|
||||
ret = readDevice(&((uchar *)data)[all], size - all);
|
||||
if (ret > 0)
|
||||
all += ret;
|
||||
else
|
||||
piMinSleep();
|
||||
}
|
||||
setOption(BlockingRead, br);
|
||||
received(data, all);
|
||||
return (all == size);
|
||||
} else {
|
||||
bool br = setOption(BlockingRead, true);
|
||||
all = readDevice(data, 1);
|
||||
all = readDevice(data, 1);
|
||||
while (all < size) {
|
||||
ret = readDevice(&((uchar * )data)[all], size - all);
|
||||
ret = readDevice(&((uchar *)data)[all], size - all);
|
||||
if (ret > 0) all += ret;
|
||||
}
|
||||
setOption(BlockingRead, br);
|
||||
@@ -518,15 +550,18 @@ PIString PISerial::readString(int size, double timeout_ms) {
|
||||
if (size <= 0) {
|
||||
while (tm_.elapsed_m() < timeout_ms) {
|
||||
ret = readDevice(td, 1024);
|
||||
if (ret <= 0) piMinSleep();
|
||||
else str += PIString((char*)td, ret);
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else
|
||||
str += PIString((char *)td, ret);
|
||||
}
|
||||
} else {
|
||||
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
||||
ret = readDevice(td, size - all);
|
||||
if (ret <= 0) piMinSleep();
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else {
|
||||
str += PIString((char*)td, ret);
|
||||
str += PIString((char *)td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
@@ -534,13 +569,14 @@ PIString PISerial::readString(int size, double timeout_ms) {
|
||||
setOption(BlockingRead, br);
|
||||
} else {
|
||||
bool br = setOption(BlockingRead, true);
|
||||
all = readDevice(td, 1);
|
||||
str += PIString((char*)td, all);
|
||||
all = readDevice(td, 1);
|
||||
str += PIString((char *)td, all);
|
||||
while (all < size) {
|
||||
ret = readDevice(td, size - all);
|
||||
if (ret <= 0) piMinSleep();
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else {
|
||||
str += PIString((char*)td, ret);
|
||||
str += PIString((char *)td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
@@ -580,13 +616,16 @@ PIByteArray PISerial::readData(int size, double timeout_ms) {
|
||||
if (size <= 0) {
|
||||
while (tm_.elapsed_m() < timeout_ms) {
|
||||
ret = readDevice(td, 1024);
|
||||
if (ret <= 0) piMinSleep();
|
||||
else str.append(td, ret);
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else
|
||||
str.append(td, ret);
|
||||
}
|
||||
} else {
|
||||
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
||||
ret = readDevice(td, size - all);
|
||||
if (ret <= 0) piMinSleep();
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else {
|
||||
str.append(td, ret);
|
||||
all += ret;
|
||||
@@ -596,11 +635,12 @@ PIByteArray PISerial::readData(int size, double timeout_ms) {
|
||||
setOption(BlockingRead, br);
|
||||
} else {
|
||||
bool br = setOption(BlockingRead, true);
|
||||
all = readDevice(td, 1);
|
||||
all = readDevice(td, 1);
|
||||
str.append(td, all);
|
||||
while (all < size) {
|
||||
ret = readDevice(td, size - all);
|
||||
if (ret <= 0) piMinSleep();
|
||||
if (ret <= 0)
|
||||
piMinSleep();
|
||||
else {
|
||||
str.append(td, ret);
|
||||
all += ret;
|
||||
@@ -617,17 +657,18 @@ bool PISerial::send(const void * data, int size) {
|
||||
int ret = 0;
|
||||
int wsz = 0;
|
||||
do {
|
||||
ret = write(&(((uchar*)data)[wsz]), size - wsz);
|
||||
ret = write(&(((uchar *)data)[wsz]), size - wsz);
|
||||
if (ret > 0) wsz += ret;
|
||||
//piCout << ret << wsz;
|
||||
else return false;
|
||||
// piCout << ret << wsz;
|
||||
else
|
||||
return false;
|
||||
} while (wsz < size);
|
||||
return (wsz == size);
|
||||
}
|
||||
|
||||
|
||||
void PISerial::interrupt() {
|
||||
//piCoutObj << "interrupt";
|
||||
// piCoutObj << "interrupt";
|
||||
PRIVATE->event.interrupt();
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->event_write.interrupt();
|
||||
@@ -636,13 +677,13 @@ void PISerial::interrupt() {
|
||||
|
||||
|
||||
bool PISerial::openDevice() {
|
||||
PIString p = path();
|
||||
//piCout << "ser open" << p;
|
||||
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) {
|
||||
piForeachC(DeviceInfo & d, devs) {
|
||||
if (d.id() == pl) {
|
||||
p = d.path;
|
||||
break;
|
||||
@@ -655,9 +696,15 @@ bool PISerial::openDevice() {
|
||||
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 = "//./" + p;
|
||||
if (isReadable()) {
|
||||
ds |= GENERIC_READ;
|
||||
sm |= FILE_SHARE_READ;
|
||||
}
|
||||
if (isWriteable()) {
|
||||
ds |= GENERIC_WRITE;
|
||||
sm |= FILE_SHARE_WRITE;
|
||||
}
|
||||
PIString wp = "//./" + p;
|
||||
PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
|
||||
if (PRIVATE->hCom == INVALID_HANDLE_VALUE) {
|
||||
piCoutObj << "Unable to open \"" << p << "\"";
|
||||
@@ -679,7 +726,7 @@ bool PISerial::openDevice() {
|
||||
}
|
||||
tcgetattr(fd, &PRIVATE->desc);
|
||||
PRIVATE->sdesc = PRIVATE->desc;
|
||||
//piCoutObj << "Initialized " << p;
|
||||
// piCoutObj << "Initialized " << p;
|
||||
#endif
|
||||
applySettings();
|
||||
PRIVATE->event.create();
|
||||
@@ -699,7 +746,7 @@ bool PISerial::closeDevice() {
|
||||
#ifdef WINDOWS
|
||||
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
||||
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
|
||||
// piCoutObj << "close" <<
|
||||
// piCoutObj << "close" <<
|
||||
CloseHandle(PRIVATE->hCom);
|
||||
PRIVATE->hCom = 0;
|
||||
#else
|
||||
@@ -723,10 +770,11 @@ void PISerial::applySettings() {
|
||||
GetCommMask(PRIVATE->hCom, &PRIVATE->mask);
|
||||
SetCommMask(PRIVATE->hCom, EV_RXCHAR);
|
||||
GetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
||||
// piCoutObj << PRIVATE->sdesc.fBinary << PRIVATE->sdesc.fAbortOnError << PRIVATE->sdesc.fDsrSensitivity << PRIVATE->sdesc.fDtrControl << PRIVATE->sdesc.fDummy2 << PRIVATE->sdesc.fErrorChar;
|
||||
PRIVATE->desc = PRIVATE->sdesc;
|
||||
// piCoutObj << PRIVATE->sdesc.fBinary << PRIVATE->sdesc.fAbortOnError << PRIVATE->sdesc.fDsrSensitivity << PRIVATE->sdesc.fDtrControl
|
||||
//<< PRIVATE->sdesc.fDummy2 << PRIVATE->sdesc.fErrorChar;
|
||||
PRIVATE->desc = PRIVATE->sdesc;
|
||||
PRIVATE->desc.DCBlength = sizeof(PRIVATE->desc);
|
||||
PRIVATE->desc.BaudRate = convertSpeed(outSpeed());
|
||||
PRIVATE->desc.BaudRate = convertSpeed(outSpeed());
|
||||
if (dataBitsCount() >= 5 && dataBitsCount() <= 8)
|
||||
PRIVATE->desc.ByteSize = dataBitsCount();
|
||||
else
|
||||
@@ -734,7 +782,7 @@ void PISerial::applySettings() {
|
||||
PIFlags<Parameters> params = parameters();
|
||||
if (params[PISerial::ParityControl]) {
|
||||
PRIVATE->desc.fParity = 1;
|
||||
PRIVATE->desc.Parity = params[PISerial::ParityOdd] ? 1 : 2;
|
||||
PRIVATE->desc.Parity = params[PISerial::ParityOdd] ? 1 : 2;
|
||||
}
|
||||
PRIVATE->desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
|
||||
if (SetCommState(PRIVATE->hCom, &PRIVATE->desc) == -1) {
|
||||
@@ -745,13 +793,14 @@ void PISerial::applySettings() {
|
||||
if (fd == -1) return;
|
||||
tcgetattr(fd, &PRIVATE->desc);
|
||||
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
|
||||
PRIVATE->desc.c_iflag = IGNBRK;
|
||||
PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
|
||||
PRIVATE->desc.c_iflag = IGNBRK;
|
||||
PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
|
||||
switch (dataBitsCount()) {
|
||||
case 5: PRIVATE->desc.c_cflag |= (CSIZE & CS5); break;
|
||||
case 6: PRIVATE->desc.c_cflag |= (CSIZE & CS6); break;
|
||||
case 7: PRIVATE->desc.c_cflag |= (CSIZE & CS7); break;
|
||||
case 8: default: PRIVATE->desc.c_cflag |= (CSIZE & CS8); break;
|
||||
case 8:
|
||||
default: PRIVATE->desc.c_cflag |= (CSIZE & CS8); break;
|
||||
};
|
||||
if (isReadable()) PRIVATE->desc.c_cflag |= CREAD;
|
||||
PIFlags<Parameters> params = parameters();
|
||||
@@ -761,7 +810,7 @@ void PISerial::applySettings() {
|
||||
PRIVATE->desc.c_cflag |= PARENB;
|
||||
if (params[PISerial::ParityOdd]) PRIVATE->desc.c_cflag |= PARODD;
|
||||
}
|
||||
PRIVATE->desc.c_cc[VMIN] = 1;
|
||||
PRIVATE->desc.c_cc[VMIN] = 1;
|
||||
PRIVATE->desc.c_cc[VTIME] = vtime;
|
||||
|
||||
cfsetispeed(&PRIVATE->desc, convertSpeed(inSpeed()));
|
||||
@@ -781,13 +830,12 @@ void PISerial::applySettings() {
|
||||
void PISerial::setTimeouts() {
|
||||
#ifdef WINDOWS
|
||||
COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = isOptionSet(BlockingRead) ? vtime : MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = isOptionSet(BlockingRead) ? 0 : 1;
|
||||
times.ReadTotalTimeoutMultiplier = isOptionSet(BlockingRead) ? 0 : MAXDWORD;
|
||||
times.WriteTotalTimeoutConstant = isOptionSet(BlockingWrite) ? 0 : 1;
|
||||
times.ReadIntervalTimeout = isOptionSet(BlockingRead) ? vtime : MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = isOptionSet(BlockingRead) ? 0 : 1;
|
||||
times.ReadTotalTimeoutMultiplier = isOptionSet(BlockingRead) ? 0 : MAXDWORD;
|
||||
times.WriteTotalTimeoutConstant = isOptionSet(BlockingWrite) ? 0 : 1;
|
||||
times.WriteTotalTimeoutMultiplier = 0;
|
||||
if (SetCommTimeouts(PRIVATE->hCom, ×) == -1)
|
||||
piCoutObj << "Unable to set timeouts for \"" << path() << "\"";
|
||||
if (SetCommTimeouts(PRIVATE->hCom, ×) == -1) piCoutObj << "Unable to set timeouts for \"" << path() << "\"";
|
||||
#else
|
||||
fcntl(fd, F_SETFL, isOptionSet(BlockingRead) ? 0 : O_NONBLOCK);
|
||||
#endif
|
||||
@@ -810,54 +858,53 @@ void PISerial::setTimeouts() {
|
||||
//! \~\sa \a readData(), \a readString()
|
||||
ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) {
|
||||
#ifdef WINDOWS
|
||||
if (!canRead()) return -1;
|
||||
if (sending) return -1;
|
||||
//piCoutObj << "read ..." << PRIVATE->hCom;
|
||||
memset(&(PRIVATE->overlap), 0, sizeof(PRIVATE->overlap));
|
||||
PRIVATE->overlap.hEvent = PRIVATE->event.getEvent();
|
||||
ReadFile(PRIVATE->hCom, read_to, max_size, NULL, &(PRIVATE->overlap));
|
||||
PRIVATE->readed = 0;
|
||||
if (PRIVATE->event.wait()) {
|
||||
GetOverlappedResult(PRIVATE->hCom, &(PRIVATE->overlap), &(PRIVATE->readed), FALSE);
|
||||
} else
|
||||
return -1;
|
||||
//piCoutObj << "read done" << PRIVATE->readed;
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_TIMEOUT && PRIVATE->readed == 0)
|
||||
return 0;
|
||||
if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) {
|
||||
piCoutObj << "read error" << (PRIVATE->readed) << errorString();
|
||||
stop();
|
||||
if (!canRead()) return -1;
|
||||
if (sending) return -1;
|
||||
// piCoutObj << "read ..." << PRIVATE->hCom;
|
||||
memset(&(PRIVATE->overlap), 0, sizeof(PRIVATE->overlap));
|
||||
PRIVATE->overlap.hEvent = PRIVATE->event.getEvent();
|
||||
ReadFile(PRIVATE->hCom, read_to, max_size, NULL, &(PRIVATE->overlap));
|
||||
PRIVATE->readed = 0;
|
||||
if (PRIVATE->event.wait()) {
|
||||
GetOverlappedResult(PRIVATE->hCom, &(PRIVATE->overlap), &(PRIVATE->readed), FALSE);
|
||||
} else
|
||||
return -1;
|
||||
// piCoutObj << "read done" << PRIVATE->readed;
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_TIMEOUT && PRIVATE->readed == 0) return 0;
|
||||
if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) {
|
||||
piCoutObj << "read error" << (PRIVATE->readed) << errorString();
|
||||
stop();
|
||||
close();
|
||||
return 0;
|
||||
}
|
||||
// piCoutObj << "read" << (PRIVATE->readed) << errorString();
|
||||
return PRIVATE->readed;
|
||||
#else
|
||||
if (!canRead()) return -1;
|
||||
if (!PRIVATE->event.wait(fd)) return -1;
|
||||
ssize_t ret = ::read(fd, read_to, max_size);
|
||||
if (ret < 0) {
|
||||
int err = errno;
|
||||
if (err == EBADF || err == EFAULT || err == EINVAL || err == EIO) {
|
||||
stopThreadedRead();
|
||||
close();
|
||||
return 0;
|
||||
}
|
||||
//piCoutObj << "read" << (PRIVATE->readed) << errorString();
|
||||
return PRIVATE->readed;
|
||||
#else
|
||||
if (!canRead()) return -1;
|
||||
if (!PRIVATE->event.wait(fd)) return -1;
|
||||
ssize_t ret = ::read(fd, read_to, max_size);
|
||||
if (ret < 0) {
|
||||
int err = errno;
|
||||
if (err == EBADF || err == EFAULT || err == EINVAL || err == EIO) {
|
||||
stopThreadedRead();
|
||||
close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t PISerial::writeDevice(const void * data, ssize_t max_size) {
|
||||
if (fd == -1 || !canWrite()) {
|
||||
//piCoutObj << "Can`t write to uninitialized COM";
|
||||
// piCoutObj << "Can`t write to uninitialized COM";
|
||||
return -1;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
DWORD wrote(0);
|
||||
//piCoutObj << "send ..." << max_size;// << ": " << PIString((char*)data, max_size);
|
||||
// piCoutObj << "send ..." << max_size;// << ": " << PIString((char*)data, max_size);
|
||||
sending = true;
|
||||
memset(&(PRIVATE->overlap_write), 0, sizeof(PRIVATE->overlap_write));
|
||||
PRIVATE->overlap_write.hEvent = PRIVATE->event_write.getEvent();
|
||||
@@ -866,20 +913,20 @@ ssize_t PISerial::writeDevice(const void * data, ssize_t max_size) {
|
||||
GetOverlappedResult(PRIVATE->hCom, &(PRIVATE->overlap_write), &wrote, FALSE);
|
||||
}
|
||||
sending = false;
|
||||
//piCoutObj << "send ok" << wrote;// << " bytes in " << path();
|
||||
// piCoutObj << "send ok" << wrote;// << " bytes in " << path();
|
||||
#else
|
||||
ssize_t wrote;
|
||||
wrote = ::write(fd, data, max_size);
|
||||
if (isOptionSet(BlockingWrite)) tcdrain(fd);
|
||||
#endif
|
||||
return (ssize_t)wrote;
|
||||
//piCoutObj << "Error while sending";
|
||||
// piCoutObj << "Error while sending";
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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));
|
||||
@@ -894,11 +941,16 @@ PIString PISerial::constructFullPathDevice() const {
|
||||
PIString ret;
|
||||
ret += path() + ":" + PIString::fromNumber(int(inSpeed())) + ":" + PIString::fromNumber(dataBitsCount());
|
||||
if (parameters()[ParityControl]) {
|
||||
if (parameters()[ParityOdd]) ret += ":O";
|
||||
else ret += ":E";
|
||||
} else ret += ":N";
|
||||
if (parameters()[TwoStopBits]) ret += ":2";
|
||||
else ret += ":1";
|
||||
if (parameters()[ParityOdd])
|
||||
ret += ":O";
|
||||
else
|
||||
ret += ":E";
|
||||
} else
|
||||
ret += ":N";
|
||||
if (parameters()[TwoStopBits])
|
||||
ret += ":2";
|
||||
else
|
||||
ret += ":1";
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -916,14 +968,19 @@ void PISerial::configureFromFullPathDevice(const PIString & full_path) {
|
||||
PIString p(pl[i]);
|
||||
switch (i) {
|
||||
case 0: setProperty("path", p); break;
|
||||
case 1: setProperty("outSpeed", p.toInt()); setProperty("inSpeed", p.toInt()); break;
|
||||
case 1:
|
||||
setProperty("outSpeed", p.toInt());
|
||||
setProperty("inSpeed", p.toInt());
|
||||
break;
|
||||
case 2: setProperty("dataBitsCount", p.toInt()); break;
|
||||
case 3:
|
||||
p = p.left(1).toLowerCase();
|
||||
if (p != "n") setParameter(ParityControl);
|
||||
if (p == "o") setParameter(ParityOdd);
|
||||
break;
|
||||
case 4: if (p.toInt() == 2) setParameter(TwoStopBits); break;
|
||||
case 4:
|
||||
if (p.toInt() == 2) setParameter(TwoStopBits);
|
||||
break;
|
||||
}
|
||||
}
|
||||
applySettings();
|
||||
@@ -936,17 +993,23 @@ PIPropertyStorage PISerial::constructVariantDevice() const {
|
||||
PIVariantTypes::Enum e;
|
||||
|
||||
PIVector<int> as = availableSpeeds();
|
||||
piForeachC (int s, as) {e << PIVariantTypes::Enumerator(s, PIString::fromNumber(s));}
|
||||
piForeachC(int s, as) {
|
||||
e << PIVariantTypes::Enumerator(s, PIString::fromNumber(s));
|
||||
}
|
||||
e.selectValue((int)inSpeed());
|
||||
ret.addProperty("speed", e);
|
||||
|
||||
e = PIVariantTypes::Enum();
|
||||
for (int i = 5; i <= 8; ++i) {e << PIVariantTypes::Enumerator(i, PIString::fromNumber(i));}
|
||||
for (int i = 5; i <= 8; ++i) {
|
||||
e << PIVariantTypes::Enumerator(i, PIString::fromNumber(i));
|
||||
}
|
||||
e.selectValue(dataBitsCount());
|
||||
ret.addProperty("dataBits", e);
|
||||
|
||||
e = PIVariantTypes::Enum();
|
||||
e << "None" << "Odd" << "Even";
|
||||
e << "None"
|
||||
<< "Odd"
|
||||
<< "Even";
|
||||
if (parameters()[ParityControl]) {
|
||||
if (parameters()[ParityOdd])
|
||||
e.selectValue(1);
|
||||
@@ -957,7 +1020,9 @@ PIPropertyStorage PISerial::constructVariantDevice() const {
|
||||
ret.addProperty("parity", e);
|
||||
|
||||
e = PIVariantTypes::Enum();
|
||||
for (int i = 1; i <= 2; ++i) {e << PIVariantTypes::Enumerator(i, PIString::fromNumber(i));}
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
e << PIVariantTypes::Enumerator(i, PIString::fromNumber(i));
|
||||
}
|
||||
e.selectValue(parameters()[TwoStopBits] ? 2 : 1);
|
||||
ret.addProperty("stopBits", e);
|
||||
return ret;
|
||||
@@ -970,21 +1035,19 @@ void PISerial::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
setDataBitsCount(d.propertyValueByName("dataBits").toEnum().selectedValue());
|
||||
PIVariantTypes::Enum e = d.propertyValueByName("parity").toEnum();
|
||||
setParameter(ParityControl, e.selectedValue() > 0);
|
||||
setParameter(ParityOdd , e.selectedValue() == 1);
|
||||
setParameter(TwoStopBits , d.propertyValueByName("stopBits").toEnum().selectedValue() == 2);
|
||||
setParameter(ParityOdd, e.selectedValue() == 1);
|
||||
setParameter(TwoStopBits, d.propertyValueByName("stopBits").toEnum().selectedValue() == 2);
|
||||
}
|
||||
|
||||
|
||||
PIVector<int> PISerial::availableSpeeds() {
|
||||
PIVector<int> spds;
|
||||
spds << 50 << 75 << 110 << 300 << 600 << 1200 << 2400 << 4800 <<
|
||||
9600 <<
|
||||
spds << 50 << 75 << 110 << 300 << 600 << 1200 << 2400 << 4800 << 9600 <<
|
||||
#ifdef WINDOWS
|
||||
14400 <<
|
||||
14400 <<
|
||||
#endif
|
||||
19200 << 38400 << 57600 << 115200 << 230400 <<
|
||||
460800 << 500000 << 576000 << 921600 << 1000000 << 1152000 <<
|
||||
1500000 << 2000000 << 2500000 << 3000000 << 3500000 << 4000000;
|
||||
19200 << 38400 << 57600 << 115200 << 230400 << 460800 << 500000 << 576000 << 921600 << 1000000 << 1152000 << 1500000 << 2000000
|
||||
<< 2500000 << 3000000 << 3500000 << 4000000;
|
||||
return spds;
|
||||
}
|
||||
|
||||
@@ -992,7 +1055,7 @@ PIVector<int> PISerial::availableSpeeds() {
|
||||
PIStringList PISerial::availableDevices(bool test) {
|
||||
PIVector<DeviceInfo> devs = availableDevicesInfo(test);
|
||||
PIStringList ret;
|
||||
piForeachC (DeviceInfo & d, devs)
|
||||
piForeachC(DeviceInfo & d, devs)
|
||||
ret << d.path;
|
||||
return ret;
|
||||
}
|
||||
@@ -1002,15 +1065,11 @@ PIStringList PISerial::availableDevices(bool test) {
|
||||
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]);
|
||||
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 dataType = 0;
|
||||
DWORD bytesRequired = MAX_PATH;
|
||||
PIVector<wchar_t> outputBuffer(MAX_PATH + 1);
|
||||
for (;;) {
|
||||
@@ -1026,8 +1085,7 @@ PIString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData)
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!ret.isEmpty())
|
||||
break;
|
||||
if (!ret.isEmpty()) break;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
return ret;
|
||||
@@ -1035,14 +1093,19 @@ PIString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData)
|
||||
|
||||
|
||||
PIString deviceRegistryProperty(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, DWORD property) {
|
||||
DWORD dataType = 0;
|
||||
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))
|
||||
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();
|
||||
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());
|
||||
@@ -1073,20 +1136,20 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
||||
PIVector<DeviceInfo> ret;
|
||||
DeviceInfo di;
|
||||
#ifdef WINDOWS
|
||||
static const GUID guids[] = {GUID_DEVINTERFACE_MODEM, GUID_DEVINTERFACE_COMPORT};
|
||||
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);
|
||||
did.cbSize = sizeof(did);
|
||||
DWORD index = 0;
|
||||
while (SetupDiEnumDeviceInfo(dis, index++, &did)) {
|
||||
di = DeviceInfo();
|
||||
di = DeviceInfo();
|
||||
di.path = devicePortName(dis, &did);
|
||||
if (!di.path.startsWith("COM")) continue;
|
||||
di.description = deviceRegistryProperty(dis, &did, SPDRP_DEVICEDESC);
|
||||
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)) {
|
||||
@@ -1097,25 +1160,34 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
||||
}
|
||||
}
|
||||
ret << di;
|
||||
//piCout << "dev" << did.DevInst << di;
|
||||
// piCout << "dev" << did.DevInst << di;
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(dis);
|
||||
}
|
||||
#else
|
||||
# ifndef ANDROID
|
||||
PIStringList prefixes;
|
||||
# ifdef QNX
|
||||
# ifdef QNX
|
||||
prefixes << "ser";
|
||||
# else
|
||||
prefixes << "ttyS" << "ttyO" << "ttyUSB" << "ttyACM" << "ttyGS"
|
||||
<< "ttyMI" << "ttymxc" << "ttyAMA" << "rfcomm" << "ircomm";
|
||||
# ifdef FREE_BSD
|
||||
# else
|
||||
prefixes << "ttyS"
|
||||
<< "ttyO"
|
||||
<< "ttyUSB"
|
||||
<< "ttyACM"
|
||||
<< "ttyGS"
|
||||
<< "ttyMI"
|
||||
<< "ttymxc"
|
||||
<< "ttyAMA"
|
||||
<< "rfcomm"
|
||||
<< "ircomm";
|
||||
# ifdef FREE_BSD
|
||||
prefixes << "cu";
|
||||
# endif
|
||||
# ifdef MAC_OS
|
||||
# endif
|
||||
# ifdef MAC_OS
|
||||
prefixes.clear();
|
||||
prefixes << "cu." << "tty.";
|
||||
# endif
|
||||
prefixes << "cu."
|
||||
<< "tty.";
|
||||
# endif
|
||||
PIFile file_prefixes("/proc/tty/drivers", PIIODevice::ReadOnly);
|
||||
if (file_prefixes.open()) {
|
||||
PIString fc = file_prefixes.readAll(true), line, cpref;
|
||||
@@ -1129,45 +1201,40 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
||||
words << line.takeWord();
|
||||
if (words.size_s() < 2) break;
|
||||
if (words.back() != "serial") continue;
|
||||
cpref = words[1];
|
||||
cpref = words[1];
|
||||
int li = cpref.findLast("/");
|
||||
if (li > 0) cpref.cutLeft(li + 1);
|
||||
prefixes << cpref;
|
||||
}
|
||||
prefixes.removeDuplicates();
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
PIDir dir("/dev");
|
||||
PIVector<PIFile::FileInfo> de = dir.entries();
|
||||
# ifdef LINUX
|
||||
# ifdef LINUX
|
||||
char linkbuf[1024];
|
||||
# endif
|
||||
piForeachC (PIFile::FileInfo & e, de) { // TODO changes in FileInfo
|
||||
piForeachC (PIString & p, prefixes) {
|
||||
# endif
|
||||
piForeachC(PIFile::FileInfo & e, de) { // TODO changes in FileInfo
|
||||
piForeachC(PIString & p, prefixes) {
|
||||
if (e.name().startsWith(p)) {
|
||||
di = DeviceInfo();
|
||||
di.path = e.path;
|
||||
# ifdef LINUX
|
||||
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;
|
||||
// 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
|
||||
# endif
|
||||
ret << di;
|
||||
}
|
||||
}
|
||||
@@ -1177,7 +1244,13 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
||||
if (test) {
|
||||
for (int i = 0; i < ret.size_s(); ++i) {
|
||||
#ifdef WINDOWS
|
||||
void * hComm = CreateFileA(ret[i].path.dataAscii(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
|
||||
void * hComm = CreateFileA(ret[i].path.dataAscii(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
||||
0);
|
||||
if (hComm == INVALID_HANDLE_VALUE) {
|
||||
#else
|
||||
int fd = ::open(ret[i].path.dataAscii(), O_NOCTTY | O_RDONLY);
|
||||
@@ -1191,9 +1264,8 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
||||
#ifndef WINDOWS
|
||||
int void_ = 0;
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
if (::read(fd, &void_, 1) == -1)
|
||||
rok = errno != EIO;
|
||||
|
||||
if (::read(fd, &void_, 1) == -1) rok = errno != EIO;
|
||||
|
||||
#endif
|
||||
if (!rok) {
|
||||
ret.remove(i);
|
||||
@@ -1221,9 +1293,9 @@ void PISerial::threadedReadBufferSizeChanged() {
|
||||
#if defined(LINUX)
|
||||
serial_struct ss;
|
||||
ioctl(fd, TIOCGSERIAL, &ss);
|
||||
//piCoutObj << "b" << ss.xmit_fifo_size;
|
||||
// piCoutObj << "b" << ss.xmit_fifo_size;
|
||||
ss.xmit_fifo_size = piMaxi(threadedReadBufferSize(), 4096);
|
||||
ioctl(fd, TIOCSSERIAL, &ss);
|
||||
//piCoutObj << "a" << ss.xmit_fifo_size;
|
||||
// piCoutObj << "a" << ss.xmit_fifo_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Последовательный порт
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
COM
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
COM
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISERIAL_H
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "pisharedmemory.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#if defined(LINUX) || defined(MAC_OS)
|
||||
# define SHM_POSIX
|
||||
@@ -30,13 +31,13 @@
|
||||
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
//# include <fcntl.h>
|
||||
// # include <fcntl.h>
|
||||
|
||||
#endif
|
||||
#ifdef SHM_POSIX
|
||||
# include <fcntl.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/mman.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -83,8 +84,7 @@ PISharedMemory::PISharedMemory(): PIIODevice() {
|
||||
PISharedMemory::PISharedMemory(const PIString & shm_name, int size, PIIODevice::DeviceMode mode): PIIODevice(shm_name, mode) {
|
||||
initPrivate();
|
||||
dsize = size;
|
||||
if (!shm_name.isEmpty())
|
||||
open();
|
||||
if (!shm_name.isEmpty()) open();
|
||||
}
|
||||
|
||||
|
||||
@@ -96,16 +96,16 @@ PISharedMemory::~PISharedMemory() {
|
||||
|
||||
bool PISharedMemory::openDevice() {
|
||||
close();
|
||||
//piCoutObj << "try open" << path() << dsize;
|
||||
// piCoutObj << "try open" << path() << dsize;
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->name = ("PIP_SHM_" + path()).toByteArray();
|
||||
PRIVATE->name.push_back(0);
|
||||
const char * nm = (const char *)PRIVATE->name.data();
|
||||
PRIVATE->map = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, nm);
|
||||
//piCoutObj << "open map =" << ullong(PRIVATE->map);
|
||||
PRIVATE->map = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, nm);
|
||||
// piCoutObj << "open map =" << ullong(PRIVATE->map);
|
||||
if (!PRIVATE->map) {
|
||||
PRIVATE->map = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)dsize, nm);
|
||||
//piCoutObj << "create map =" << ullong(PRIVATE->map);
|
||||
// piCoutObj << "create map =" << ullong(PRIVATE->map);
|
||||
if (!PRIVATE->map) {
|
||||
piCoutObj << "CreateFileMapping error," << errorString();
|
||||
return false;
|
||||
@@ -117,33 +117,32 @@ bool PISharedMemory::openDevice() {
|
||||
piCoutObj << "MapViewOfFile error," << errorString();
|
||||
return false;
|
||||
}
|
||||
//piCout << PRIVATE->map << PRIVATE->data;
|
||||
// piCout << PRIVATE->map << PRIVATE->data;
|
||||
#endif
|
||||
#ifdef SHM_POSIX
|
||||
PRIVATE->name = ("/pip_shm_" + path()).toByteArray();
|
||||
PRIVATE->name.push_back(0);
|
||||
int fd = shm_open((const char *)PRIVATE->name.data(), O_RDWR, 0777);
|
||||
//piCoutObj << "try open" << PICoutManipulators::Hex << fd;
|
||||
// piCoutObj << "try open" << PICoutManipulators::Hex << fd;
|
||||
if (fd < 0) {
|
||||
//piCoutObj << "shm_open error," << errorString();
|
||||
// piCoutObj << "shm_open error," << errorString();
|
||||
fd = shm_open((const char *)PRIVATE->name.data(), O_RDWR | O_CREAT, 0777);
|
||||
//piCoutObj << "try create" << PICoutManipulators::Hex << (m | O_CREAT) << fd;
|
||||
// piCoutObj << "try create" << PICoutManipulators::Hex << (m | O_CREAT) << fd;
|
||||
if (fd < 0) {
|
||||
piCoutObj << "shm_open error," << errorString();
|
||||
return false;
|
||||
}
|
||||
PRIVATE->owner = true;
|
||||
//piCoutObj << "created" << fd;
|
||||
// piCoutObj << "created" << fd;
|
||||
}
|
||||
if (fd >= 0)
|
||||
ftruncate(fd, dsize);
|
||||
if (fd >= 0) ftruncate(fd, dsize);
|
||||
PRIVATE->data = mmap(0, dsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
::close(fd);
|
||||
if (PRIVATE->data == MAP_FAILED) {
|
||||
piCoutObj << "mmap error," << errorString();
|
||||
return false;
|
||||
}
|
||||
//piCoutObj << "opened" << PRIVATE->data;
|
||||
// piCoutObj << "opened" << PRIVATE->data;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -155,13 +154,13 @@ bool PISharedMemory::closeDevice() {
|
||||
if (PRIVATE->map) CloseHandle(PRIVATE->map);
|
||||
#endif
|
||||
#ifdef SHM_POSIX
|
||||
//piCoutObj << "close" << PIString(PRIVATE->name) << PRIVATE->data;
|
||||
// piCoutObj << "close" << PIString(PRIVATE->name) << PRIVATE->data;
|
||||
if (PRIVATE->data) munmap(PRIVATE->data, dsize);
|
||||
if (PRIVATE->owner) {
|
||||
//piCout << "unlink" << PIString(PRIVATE->name);
|
||||
// piCout << "unlink" << PIString(PRIVATE->name);
|
||||
shm_unlink((const char *)PRIVATE->name.data());
|
||||
}
|
||||
//if (fd > 0)
|
||||
// if (fd > 0)
|
||||
#endif
|
||||
initPrivate();
|
||||
return true;
|
||||
@@ -204,11 +203,11 @@ void PISharedMemory::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
|
||||
void PISharedMemory::initPrivate() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->map = 0;
|
||||
PRIVATE->map = 0;
|
||||
PRIVATE->data = 0;
|
||||
#endif
|
||||
#ifdef SHM_POSIX
|
||||
PRIVATE->data = 0;
|
||||
PRIVATE->data = 0;
|
||||
PRIVATE->owner = false;
|
||||
#endif
|
||||
}
|
||||
@@ -250,12 +249,12 @@ int PISharedMemory::read(void * read_to, int max_size) {
|
||||
int PISharedMemory::read(void * read_to, int max_size, int offset) {
|
||||
#ifdef WINDOWS
|
||||
if (!PRIVATE->data) return -1;
|
||||
CopyMemory(read_to, &(((char*)(PRIVATE->data))[offset]), max_size);
|
||||
CopyMemory(read_to, &(((char *)(PRIVATE->data))[offset]), max_size);
|
||||
return max_size;
|
||||
#endif
|
||||
#ifdef SHM_POSIX
|
||||
if (!PRIVATE->data) return -1;
|
||||
memcpy(read_to, &(((char*)(PRIVATE->data))[offset]), max_size);
|
||||
memcpy(read_to, &(((char *)(PRIVATE->data))[offset]), max_size);
|
||||
return max_size;
|
||||
#endif
|
||||
return -1;
|
||||
@@ -270,12 +269,12 @@ int PISharedMemory::write(const void * data, int max_size) {
|
||||
int PISharedMemory::write(const void * data, int max_size, int offset) {
|
||||
#ifdef WINDOWS
|
||||
if (!PRIVATE->data) return -1;
|
||||
CopyMemory(&(((char*)(PRIVATE->data))[offset]), data, max_size);
|
||||
CopyMemory(&(((char *)(PRIVATE->data))[offset]), data, max_size);
|
||||
return max_size;
|
||||
#endif
|
||||
#ifdef SHM_POSIX
|
||||
if (!PRIVATE->data) return -1;
|
||||
memcpy(&(((char*)(PRIVATE->data))[offset]), data, max_size);
|
||||
memcpy(&(((char *)(PRIVATE->data))[offset]), data, max_size);
|
||||
return max_size;
|
||||
#endif
|
||||
return -1;
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Разделяемая память
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Shared Memory
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Shared Memory
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISHAREDMEMORY_H
|
||||
@@ -33,26 +33,25 @@
|
||||
//! \~\brief
|
||||
//! \~english Shared memory.
|
||||
//! \~russian Разделяемая память.
|
||||
class PIP_EXPORT PISharedMemory: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PISharedMemory: public PIIODevice {
|
||||
PIIODEVICE(PISharedMemory, "shm");
|
||||
|
||||
public:
|
||||
|
||||
//! \~english Constructs empty %PISharedMemory
|
||||
//! \~russian Создает пустой %PISharedMemory
|
||||
explicit PISharedMemory();
|
||||
|
||||
|
||||
//! \~english Constructs a shared memory object with name "shm_name", size "size" and open mode "mode"
|
||||
//! \~russian Создает объект разделяемой памяти с именем "shm_name", размером "size" и режимом открытия "mode"
|
||||
explicit PISharedMemory(const PIString & shm_name, int size, DeviceMode mode = ReadWrite);
|
||||
|
||||
|
||||
virtual ~PISharedMemory();
|
||||
|
||||
|
||||
|
||||
//! \~english Read all shared memory content and return it as byte array
|
||||
//! \~russian Читает всю разделяемую память и возвращает её как байтовый массив
|
||||
PIByteArray readAll();
|
||||
|
||||
|
||||
//! \~english Returns shared memory size
|
||||
//! \~russian Возвращает размер разделяемой памяти
|
||||
llong size() const;
|
||||
@@ -60,11 +59,11 @@ public:
|
||||
//! \~english Set shared memory size
|
||||
//! \~russian Устанавливает размер разделяемой памяти
|
||||
void setSize(llong s);
|
||||
|
||||
|
||||
//! \~english Returns if shared memory object is empty (by size)
|
||||
//! \~russian Возвращает пустой ли объект разделяемой памяти (по размеру)
|
||||
bool isEmpty() const {return (size() <= 0);}
|
||||
|
||||
bool isEmpty() const { return (size() <= 0); }
|
||||
|
||||
//! \~english Read from shared memory to "read_to" no more than "max_size" and return readed bytes count
|
||||
//! \~russian Читает из разделяемой памяти в "read_to" не более "max_size" и возвращает количество прочитанных байт
|
||||
int read(void * read_to, int max_size);
|
||||
@@ -72,7 +71,7 @@ public:
|
||||
//! \~english Read from shared memory started from "offset" to "read_to" no more than "max_size" and return readed bytes count
|
||||
//! \~russian Читает из разделяемой памяти с начала "offset" в "read_to" не более "max_size" и возвращает количество прочитанных байт
|
||||
int read(void * read_to, int max_size, int offset);
|
||||
|
||||
|
||||
//! \~english Write to shared memory "data" with size "max_size" and return written bytes count
|
||||
//! \~russian Пишет в разделяемую память "data" размером "max_size" и возвращает количество записанных байт
|
||||
int write(const void * data, int max_size);
|
||||
@@ -83,12 +82,12 @@ public:
|
||||
|
||||
//! \~english Write "data" to shared memory
|
||||
//! \~russian Пишет в разделяемую память "data"
|
||||
int write(const PIByteArray & data) {return write(data.data(), data.size_s());}
|
||||
int write(const PIByteArray & data) { return write(data.data(), data.size_s()); }
|
||||
|
||||
//! \~english Write "data" to shared memory
|
||||
//! \~russian Пишет в разделяемую память "data"
|
||||
int write(const PIByteArray & data, int offset) {return write(data.data(), data.size_s(), offset);}
|
||||
|
||||
int write(const PIByteArray & data, int offset) { return write(data.data(), data.size_s(), offset); }
|
||||
|
||||
|
||||
protected:
|
||||
bool openDevice() override;
|
||||
@@ -97,16 +96,15 @@ protected:
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override {return read(read_to, max_size, 0);}
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override {return write(data, max_size, 0);}
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override { return read(read_to, max_size, 0); }
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override { return write(data, max_size, 0); }
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
private:
|
||||
void initPrivate();
|
||||
|
||||
int dsize;
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
SPI
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
SPI
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pispi.h"
|
||||
#include "pipropertystorage.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#ifdef LINUX
|
||||
# define PIP_SPI
|
||||
#endif
|
||||
#ifdef PIP_SPI
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <linux/spi/spidev.h>
|
||||
# include <fcntl.h>
|
||||
# include <linux/spi/spidev.h>
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PISPI)
|
||||
#ifdef PIP_SPI
|
||||
int fd;
|
||||
spi_ioc_transfer spi_ioc_tr;
|
||||
int fd;
|
||||
spi_ioc_transfer spi_ioc_tr;
|
||||
#endif
|
||||
PRIVATE_DEFINITION_END(PISPI)
|
||||
|
||||
@@ -41,7 +42,7 @@ PRIVATE_DEFINITION_END(PISPI)
|
||||
REGISTER_DEVICE(PISPI)
|
||||
|
||||
|
||||
PISPI::PISPI(const PIString & path, uint speed, PIIODevice::DeviceMode mode) : PIIODevice(path, mode) {
|
||||
PISPI::PISPI(const PIString & path, uint speed, PIIODevice::DeviceMode mode): PIIODevice(path, mode) {
|
||||
#ifdef MICRO_PIP
|
||||
setThreadedReadBufferSize(512);
|
||||
#else
|
||||
@@ -51,8 +52,7 @@ PISPI::PISPI(const PIString & path, uint speed, PIIODevice::DeviceMode mode) : P
|
||||
setSpeed(speed);
|
||||
setBits(8);
|
||||
spi_mode = 0;
|
||||
if (mode == ReadOnly)
|
||||
piCoutObj << "error, SPI can't work in ReadOnly mode";
|
||||
if (mode == ReadOnly) piCoutObj << "error, SPI can't work in ReadOnly mode";
|
||||
#ifdef PIP_SPI
|
||||
PRIVATE->fd = 0;
|
||||
#endif
|
||||
@@ -95,22 +95,35 @@ ssize_t PISPI::bytesAvailable() const {
|
||||
|
||||
bool PISPI::openDevice() {
|
||||
#ifdef PIP_SPI
|
||||
int ret = 0;
|
||||
//piCoutObj << "open device" << path();
|
||||
int ret = 0;
|
||||
// piCoutObj << "open device" << path();
|
||||
PRIVATE->fd = ::open(path().dataAscii(), O_RDWR);
|
||||
if (PRIVATE->fd < 0) {piCoutObj << "can't open device";return false;}
|
||||
//piCoutObj << "set mode" << spi_mode;
|
||||
if (PRIVATE->fd < 0) {
|
||||
piCoutObj << "can't open device";
|
||||
return false;
|
||||
}
|
||||
// piCoutObj << "set mode" << spi_mode;
|
||||
ret = ioctl(PRIVATE->fd, SPI_IOC_WR_MODE, &spi_mode);
|
||||
if (ret == -1) {piCoutObj << "can't set spi write mode";return false;}
|
||||
//piCoutObj << "set bits" << spi_bits;
|
||||
if (ret == -1) {
|
||||
piCoutObj << "can't set spi write mode";
|
||||
return false;
|
||||
}
|
||||
// piCoutObj << "set bits" << spi_bits;
|
||||
ret = ioctl(PRIVATE->fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits);
|
||||
if (ret == -1) {piCoutObj << "can't set bits per word";return false;}
|
||||
//piCoutObj << "set speed" << spi_speed;
|
||||
if (ret == -1) {
|
||||
piCoutObj << "can't set bits per word";
|
||||
return false;
|
||||
}
|
||||
// piCoutObj << "set speed" << spi_speed;
|
||||
ret = ioctl(PRIVATE->fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
|
||||
if (ret == -1) {piCoutObj << "can't set max write speed hz";return false;}
|
||||
piCoutObj << "SPI open" << path() << "speed:" << spi_speed/1000 << "KHz" << "mode" << spi_mode << "bits" << spi_bits;
|
||||
PRIVATE->spi_ioc_tr.delay_usecs = 0;
|
||||
PRIVATE->spi_ioc_tr.speed_hz = 0;
|
||||
if (ret == -1) {
|
||||
piCoutObj << "can't set max write speed hz";
|
||||
return false;
|
||||
}
|
||||
piCoutObj << "SPI open" << path() << "speed:" << spi_speed / 1000 << "KHz"
|
||||
<< "mode" << spi_mode << "bits" << spi_bits;
|
||||
PRIVATE->spi_ioc_tr.delay_usecs = 0;
|
||||
PRIVATE->spi_ioc_tr.speed_hz = 0;
|
||||
PRIVATE->spi_ioc_tr.bits_per_word = spi_bits;
|
||||
return true;
|
||||
#else
|
||||
@@ -144,13 +157,16 @@ ssize_t PISPI::writeDevice(const void * data, ssize_t max_size) {
|
||||
rx_buf.resize(max_size);
|
||||
PRIVATE->spi_ioc_tr.tx_buf = (ulong)(tx_buf.data());
|
||||
PRIVATE->spi_ioc_tr.rx_buf = (ulong)(rx_buf.data());
|
||||
PRIVATE->spi_ioc_tr.len = max_size;
|
||||
PRIVATE->spi_ioc_tr.len = max_size;
|
||||
}
|
||||
memcpy(tx_buf.data(), data, max_size);
|
||||
int ret;
|
||||
//piCoutObj << "write" << max_size << tx_buf.size();
|
||||
// piCoutObj << "write" << max_size << tx_buf.size();
|
||||
ret = ioctl(PRIVATE->fd, SPI_IOC_MESSAGE(1), &PRIVATE->spi_ioc_tr);
|
||||
if (ret < 1) {piCoutObj << "can't send spi message" << ret; return -1;}
|
||||
if (ret < 1) {
|
||||
piCoutObj << "can't send spi message" << ret;
|
||||
return -1;
|
||||
}
|
||||
if (canRead()) recv_buf.append(rx_buf);
|
||||
if (recv_buf.size_s() > threadedReadBufferSize()) recv_buf.resize(threadedReadBufferSize());
|
||||
return max_size;
|
||||
@@ -162,7 +178,8 @@ ssize_t PISPI::writeDevice(const void * data, ssize_t max_size) {
|
||||
|
||||
PIString PISPI::constructFullPathDevice() const {
|
||||
PIString ret;
|
||||
ret += path() + ":" + PIString::fromNumber((int)speed()) + ":" + PIString::fromNumber((int)bits()) + ":" + PIString::fromNumber((int)parameters());
|
||||
ret += path() + ":" + PIString::fromNumber((int)speed()) + ":" + PIString::fromNumber((int)bits()) + ":" +
|
||||
PIString::fromNumber((int)parameters());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Устройство SPI
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
SPI
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
SPI
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISPI_H
|
||||
@@ -29,27 +29,27 @@
|
||||
#include "piiodevice.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PISPI: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PISPI: public PIIODevice {
|
||||
PIIODEVICE(PISPI, "spi");
|
||||
|
||||
public:
|
||||
explicit PISPI(const PIString & path = PIString(), uint speed_hz = 1000000, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
virtual ~PISPI();
|
||||
|
||||
//! \brief Parameters of PISPI
|
||||
enum Parameters {
|
||||
ClockInverse /*! SPI clk polarity control*/ = 0x1,
|
||||
ClockInverse /*! SPI clk polarity control*/ = 0x1,
|
||||
ClockPhaseShift /*! SPI clk phase control */ = 0x2,
|
||||
};
|
||||
|
||||
void setSpeed(uint speed_hz);
|
||||
uint speed() const {return spi_speed;}
|
||||
uint speed() const { return spi_speed; }
|
||||
|
||||
void setBits(uchar bits = 8);
|
||||
uchar bits() const {return spi_bits;}
|
||||
uchar bits() const { return spi_bits; }
|
||||
|
||||
//! Set parameters to "parameters_"
|
||||
void setParameters(PIFlags<PISPI::Parameters> parameters_) {spi_mode = (int)parameters_;}
|
||||
void setParameters(PIFlags<PISPI::Parameters> parameters_) { spi_mode = (int)parameters_; }
|
||||
|
||||
//! Set parameter "parameter" to "on" state
|
||||
void setParameter(PISPI::Parameters parameter, bool on = true);
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
bool isParameterSet(PISPI::Parameters parameter) const;
|
||||
|
||||
//! Returns parameters
|
||||
PIFlags<PISPI::Parameters> parameters() const {return spi_mode;}
|
||||
PIFlags<PISPI::Parameters> parameters() const { return spi_mode; }
|
||||
|
||||
ssize_t bytesAvailable() const override;
|
||||
|
||||
@@ -72,7 +72,7 @@ protected:
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Sequential;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Sequential; }
|
||||
|
||||
private:
|
||||
uint spi_speed;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice that pass write to read
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice that pass write to read
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitransparentdevice.h"
|
||||
@@ -39,8 +39,7 @@
|
||||
REGISTER_DEVICE(PITransparentDevice)
|
||||
|
||||
|
||||
PITransparentDevice::PITransparentDevice() {
|
||||
}
|
||||
PITransparentDevice::PITransparentDevice() {}
|
||||
|
||||
|
||||
PITransparentDevice::~PITransparentDevice() {
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian PIIODevice который транслирует запись на чтение
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice that pass write to read
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
PIIODevice that pass write to read
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PITRANSPARENTDEVICE_H
|
||||
@@ -33,17 +33,16 @@
|
||||
//! \~\brief
|
||||
//! \~english PIIODevice that pass write to read.
|
||||
//! \~russian PIIODevice который транслирует запись на чтение.
|
||||
class PIP_EXPORT PITransparentDevice: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PITransparentDevice: public PIIODevice {
|
||||
PIIODEVICE(PITransparentDevice, "tr");
|
||||
|
||||
public:
|
||||
|
||||
//! \~english Contructs empty %PITransparentDevice
|
||||
//! \~russian Создает пустой %PITransparentDevice
|
||||
explicit PITransparentDevice();
|
||||
|
||||
|
||||
virtual ~PITransparentDevice();
|
||||
|
||||
|
||||
ssize_t bytesAvailable() const override;
|
||||
|
||||
protected:
|
||||
@@ -51,11 +50,10 @@ protected:
|
||||
bool closeDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
mutable PIMutex que_mutex;
|
||||
PIQueue<PIByteArray> que;
|
||||
|
||||
};
|
||||
|
||||
#endif // PITRANSPARENTDEVICE_H
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Устройство USB
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
USB, based on libusb
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
USB, based on libusb
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//! \defgroup USB USB
|
||||
//! \~\brief
|
||||
@@ -61,23 +61,45 @@
|
||||
|
||||
struct usb_dev_handle;
|
||||
|
||||
class PIP_EXPORT PIUSB: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIUSB: public PIIODevice {
|
||||
PIIODEVICE(PIUSB, "usb");
|
||||
|
||||
public:
|
||||
explicit PIUSB(ushort vid = 0, ushort pid = 0);
|
||||
virtual ~PIUSB();
|
||||
|
||||
struct PIP_EXPORT Endpoint {
|
||||
Endpoint(uchar a = 0, uchar at = 0, ushort mps = 0) {address = a; attributes = at; max_packet_size = mps; parse();}
|
||||
Endpoint(uchar a = 0, uchar at = 0, ushort mps = 0) {
|
||||
address = a;
|
||||
attributes = at;
|
||||
max_packet_size = mps;
|
||||
parse();
|
||||
}
|
||||
|
||||
enum Direction {Write = 0, Read = 1};
|
||||
enum TransferType {Control = 0, Isochronous = 1, Bulk = 2, Interrupt = 3};
|
||||
enum SynchronisationType {NoSynchonisation= 0, Asynchronous = 2, Adaptive = 1, Synchronous = 3};
|
||||
enum UsageType {DataEndpoint = 0, FeedbackEndpoint = 2, ExplicitFeedbackDataEndpoint = 1};
|
||||
enum Direction {
|
||||
Write = 0,
|
||||
Read = 1
|
||||
};
|
||||
enum TransferType {
|
||||
Control = 0,
|
||||
Isochronous = 1,
|
||||
Bulk = 2,
|
||||
Interrupt = 3
|
||||
};
|
||||
enum SynchronisationType {
|
||||
NoSynchonisation = 0,
|
||||
Asynchronous = 2,
|
||||
Adaptive = 1,
|
||||
Synchronous = 3
|
||||
};
|
||||
enum UsageType {
|
||||
DataEndpoint = 0,
|
||||
FeedbackEndpoint = 2,
|
||||
ExplicitFeedbackDataEndpoint = 1
|
||||
};
|
||||
|
||||
void parse();
|
||||
bool isNull() const {return address == 0;}
|
||||
bool isNull() const { return address == 0; }
|
||||
|
||||
uchar address;
|
||||
uchar attributes;
|
||||
@@ -89,7 +111,7 @@ public:
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Interface {
|
||||
Interface() {index = value_to_select = class_code = subclass_code = protocol_code = 0;}
|
||||
Interface() { index = value_to_select = class_code = subclass_code = protocol_code = 0; }
|
||||
uchar index;
|
||||
uchar value_to_select;
|
||||
ushort class_code;
|
||||
@@ -99,7 +121,10 @@ public:
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Configuration {
|
||||
Configuration() {index = value_to_select = attributes = max_power = 0; self_powered = remote_wakeup = false;}
|
||||
Configuration() {
|
||||
index = value_to_select = attributes = max_power = 0;
|
||||
self_powered = remote_wakeup = false;
|
||||
}
|
||||
uchar index;
|
||||
uchar value_to_select;
|
||||
uchar attributes;
|
||||
@@ -110,7 +135,12 @@ public:
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Descriptor {
|
||||
Descriptor() {usb_spec_number = 0; device_class = device_subclass = device_protocol = max_packet_size = 0; id_vendor = id_product = id_device_release = 0; index_manufacturer = index_product = index_serial = 0;}
|
||||
Descriptor() {
|
||||
usb_spec_number = 0;
|
||||
device_class = device_subclass = device_protocol = max_packet_size = 0;
|
||||
id_vendor = id_product = id_device_release = 0;
|
||||
index_manufacturer = index_product = index_serial = 0;
|
||||
}
|
||||
ushort usb_spec_number;
|
||||
uchar device_class;
|
||||
uchar device_subclass;
|
||||
@@ -125,35 +155,41 @@ public:
|
||||
PIVector<PIUSB::Configuration> configurations;
|
||||
};
|
||||
|
||||
const PIUSB::Descriptor & currentDescriptor() const {return desc_;}
|
||||
const PIUSB::Configuration & currentConfiguration() const {return conf_;}
|
||||
const PIUSB::Interface & currentInterface() const {return iface_;}
|
||||
const PIUSB::Descriptor & currentDescriptor() const { return desc_; }
|
||||
const PIUSB::Configuration & currentConfiguration() const { return conf_; }
|
||||
const PIUSB::Interface & currentInterface() const { return iface_; }
|
||||
|
||||
ushort vendorID() const {return vid_;}
|
||||
ushort productID() const {return pid_;}
|
||||
ushort vendorID() const { return vid_; }
|
||||
ushort productID() const { return pid_; }
|
||||
|
||||
int deviceNumber() const {return property("deviceNumber").toInt();}
|
||||
int timeoutRead() const {return property("timeoutRead").toInt();}
|
||||
int timeoutWrite() const {return property("timeoutWrite").toInt();}
|
||||
const PIUSB::Endpoint & endpointRead() const {return ep_read;}
|
||||
const PIUSB::Endpoint & endpointWrite() const {return ep_write;}
|
||||
int deviceNumber() const { return property("deviceNumber").toInt(); }
|
||||
int timeoutRead() const { return property("timeoutRead").toInt(); }
|
||||
int timeoutWrite() const { return property("timeoutWrite").toInt(); }
|
||||
const PIUSB::Endpoint & endpointRead() const { return ep_read; }
|
||||
const PIUSB::Endpoint & endpointWrite() const { return ep_write; }
|
||||
|
||||
const PIVector<PIUSB::Endpoint> & endpoints() const {return eps;}
|
||||
const PIVector<PIUSB::Endpoint> & endpoints() const { return eps; }
|
||||
PIVector<PIUSB::Endpoint> endpointsRead();
|
||||
PIVector<PIUSB::Endpoint> endpointsWrite();
|
||||
PIUSB::Endpoint getEndpointByAddress(uchar address);
|
||||
|
||||
void setVendorID(ushort vid) {vid_ = vid; setPath(PIString::fromNumber(vid_, 16).expandLeftTo(4, "0") + ":" + PIString::fromNumber(pid_, 16).expandLeftTo(4, "0"));}
|
||||
void setProductID(ushort pid) {pid_ = pid; setPath(PIString::fromNumber(vid_, 16).expandLeftTo(4, "0") + ":" + PIString::fromNumber(pid_, 16).expandLeftTo(4, "0"));}
|
||||
void setVendorID(ushort vid) {
|
||||
vid_ = vid;
|
||||
setPath(PIString::fromNumber(vid_, 16).expandLeftTo(4, "0") + ":" + PIString::fromNumber(pid_, 16).expandLeftTo(4, "0"));
|
||||
}
|
||||
void setProductID(ushort pid) {
|
||||
pid_ = pid;
|
||||
setPath(PIString::fromNumber(vid_, 16).expandLeftTo(4, "0") + ":" + PIString::fromNumber(pid_, 16).expandLeftTo(4, "0"));
|
||||
}
|
||||
|
||||
bool setConfiguration(uchar value);
|
||||
bool setInterface(uchar value);
|
||||
|
||||
void setEndpointRead(const PIUSB::Endpoint & ep) {ep_read = ep;}
|
||||
void setEndpointWrite(const PIUSB::Endpoint & ep) {ep_write = ep;}
|
||||
void setDeviceNumber(int dn) {setProperty("deviceNumber", dn);}
|
||||
void setTimeoutRead(int t) {setProperty("timeoutRead", t);}
|
||||
void setTimeoutWrite(int t) {setProperty("timeoutWrite", t);}
|
||||
void setEndpointRead(const PIUSB::Endpoint & ep) { ep_read = ep; }
|
||||
void setEndpointWrite(const PIUSB::Endpoint & ep) { ep_write = ep; }
|
||||
void setDeviceNumber(int dn) { setProperty("deviceNumber", dn); }
|
||||
void setTimeoutRead(int t) { setProperty("timeoutRead", t); }
|
||||
void setTimeoutWrite(int t) { setProperty("timeoutWrite", t); }
|
||||
|
||||
int controlWrite(const void * data, int max_size);
|
||||
|
||||
@@ -167,7 +203,7 @@ protected:
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
|
||||
|
||||
PIVector<PIUSB::Endpoint> eps;
|
||||
ushort vid_, pid_;
|
||||
@@ -178,9 +214,8 @@ protected:
|
||||
Configuration conf_;
|
||||
Interface iface_;
|
||||
usb_dev_handle * hdev;
|
||||
|
||||
};
|
||||
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PIUSB::Endpoint & v);
|
||||
PIP_EXPORT PICout operator<<(PICout s, const PIUSB::Endpoint & v);
|
||||
|
||||
#endif // PIUSB_H
|
||||
|
||||
Reference in New Issue
Block a user