code format
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Base class for reliable send and receive data in fixed packets with error correction, pause and resume
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Base class for reliable send and receive data in fixed packets with error correction, pause and resume
|
||||
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 "pibasetransfer.h"
|
||||
@@ -22,17 +22,17 @@
|
||||
const uint PIBaseTransfer::signature = 0x54424950;
|
||||
|
||||
PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
||||
header.sig = signature;
|
||||
crc_enabled = true;
|
||||
header.session_id = 0;
|
||||
header.sig = signature;
|
||||
crc_enabled = true;
|
||||
header.session_id = 0;
|
||||
packet_header_size = sizeof(PacketHeader) + customHeader().size();
|
||||
part_header_size = sizeof(Part) + sizeof(int);
|
||||
part_header_size = sizeof(Part) + sizeof(int);
|
||||
is_sending = is_receiving = is_pause = false;
|
||||
break_ = true;
|
||||
break_ = true;
|
||||
bytes_all = bytes_cur = 0;
|
||||
send_queue = 0;
|
||||
send_up = 0;
|
||||
timeout_ = 10.;
|
||||
send_queue = 0;
|
||||
send_up = 0;
|
||||
timeout_ = 10.;
|
||||
diag.setDisconnectTimeout(timeout_ / 10);
|
||||
diag.setName("PIBaseTransfer");
|
||||
diag.start(50);
|
||||
@@ -61,7 +61,7 @@ void PIBaseTransfer::stopSend() {
|
||||
void PIBaseTransfer::stopReceive() {
|
||||
if (!is_receiving) return;
|
||||
break_ = true;
|
||||
//piCoutObj << "stopReceive()";
|
||||
// piCoutObj << "stopReceive()";
|
||||
finish_receive(false);
|
||||
}
|
||||
|
||||
@@ -70,8 +70,10 @@ void PIBaseTransfer::setPause(bool pause_) {
|
||||
if (is_pause == pause_) return;
|
||||
pause_tm.reset();
|
||||
is_pause = pause_;
|
||||
if (pause_) paused();
|
||||
else resumed();
|
||||
if (pause_)
|
||||
paused();
|
||||
else
|
||||
resumed();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,184 +90,187 @@ void PIBaseTransfer::received(PIByteArray data) {
|
||||
piCoutObj << "invalid packet signature";
|
||||
diag.received(data.size(), false);
|
||||
return;
|
||||
} else diag.received(data.size(), true);
|
||||
//piCoutObj << "receive" << h.session_id << h.type << h.id;
|
||||
} else
|
||||
diag.received(data.size(), true);
|
||||
// piCoutObj << "receive" << h.session_id << h.type << h.id;
|
||||
switch (pt) {
|
||||
case pt_Unknown: break;
|
||||
case pt_Data:
|
||||
mutex_header.lock();
|
||||
if (h.session_id != header.session_id || !is_receiving) {
|
||||
sendBreak(h.session_id);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
} else {
|
||||
uint rcrc = h.crc;
|
||||
uint ccrc;
|
||||
if (crc_enabled) ccrc = crc.calculate(data.data(), data.size_s());
|
||||
else ccrc = 0;
|
||||
if (rcrc != ccrc) {
|
||||
header.id = h.id;
|
||||
piCoutObj << "invalid CRC";
|
||||
sendReply(pt_ReplyInvalid);
|
||||
} else {
|
||||
mutex_session.lock();
|
||||
processData(h.id, data);
|
||||
mutex_session.unlock();
|
||||
}
|
||||
if (is_pause) sendReply(pt_Pause);
|
||||
}
|
||||
case pt_Unknown: break;
|
||||
case pt_Data:
|
||||
mutex_header.lock();
|
||||
if (h.session_id != header.session_id || !is_receiving) {
|
||||
sendBreak(h.session_id);
|
||||
mutex_header.unlock();
|
||||
break;
|
||||
case pt_ReplySuccess:
|
||||
case pt_ReplyInvalid:
|
||||
mutex_header.lock();
|
||||
if (h.session_id != header.session_id) {
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
return;
|
||||
} else {
|
||||
uint rcrc = h.crc;
|
||||
uint ccrc;
|
||||
if (crc_enabled)
|
||||
ccrc = crc.calculate(data.data(), data.size_s());
|
||||
else
|
||||
ccrc = 0;
|
||||
if (rcrc != ccrc) {
|
||||
header.id = h.id;
|
||||
piCoutObj << "invalid CRC";
|
||||
sendReply(pt_ReplyInvalid);
|
||||
} else {
|
||||
mutex_session.lock();
|
||||
processData(h.id, data);
|
||||
mutex_session.unlock();
|
||||
}
|
||||
if (is_pause) sendReply(pt_Pause);
|
||||
}
|
||||
mutex_header.unlock();
|
||||
break;
|
||||
case pt_ReplySuccess:
|
||||
case pt_ReplyInvalid:
|
||||
mutex_header.lock();
|
||||
if (h.session_id != header.session_id) {
|
||||
mutex_header.unlock();
|
||||
if (pt == pt_ReplySuccess) {
|
||||
mutex_send.lock();
|
||||
send_queue--;
|
||||
if (send_queue < 0) send_queue = 0;
|
||||
send_tm.reset();
|
||||
mutex_send.unlock();
|
||||
}
|
||||
if (is_sending) {
|
||||
mutex_session.lock();
|
||||
if (h.id < replies.size()) {
|
||||
replies[h.id] = pt;
|
||||
pm_string[h.id] = pt == pt_ReplySuccess ? '#' : '-';
|
||||
int s = pm_string.find('+'), s1 = send_queue;
|
||||
while (s <= (int)h.id && s > 0) {
|
||||
send_queue--;
|
||||
if (s >= 0) {
|
||||
pm_string[s] = '-';
|
||||
bytes_cur -= packet_size;
|
||||
}
|
||||
send_up = 0;
|
||||
if (send_queue < 0) {
|
||||
send_queue = 0;
|
||||
break;
|
||||
}
|
||||
s = pm_string.find('+');
|
||||
return;
|
||||
}
|
||||
if (is_pause) sendReply(pt_Pause);
|
||||
mutex_header.unlock();
|
||||
if (pt == pt_ReplySuccess) {
|
||||
mutex_send.lock();
|
||||
send_queue--;
|
||||
if (send_queue < 0) send_queue = 0;
|
||||
send_tm.reset();
|
||||
mutex_send.unlock();
|
||||
}
|
||||
if (is_sending) {
|
||||
mutex_session.lock();
|
||||
if (h.id < replies.size()) {
|
||||
replies[h.id] = pt;
|
||||
pm_string[h.id] = pt == pt_ReplySuccess ? '#' : '-';
|
||||
int s = pm_string.find('+'), s1 = send_queue;
|
||||
while (s <= (int)h.id && s > 0) {
|
||||
send_queue--;
|
||||
if (s >= 0) {
|
||||
pm_string[s] = '-';
|
||||
bytes_cur -= packet_size;
|
||||
}
|
||||
if (s1-send_queue > 1 && packets_count > 2) packets_count-= piMaxi(packets_count/10,1);
|
||||
if (s1 == send_queue && s1 < piMaxi(packets_count/2, 2) && packets_count < 100) send_up++;
|
||||
if (send_up > 20 && send_up > packets_count*2) packets_count+= piMaxi(packets_count/10,1);
|
||||
//piCoutObj << packets_count;
|
||||
} else
|
||||
piCoutObj << "invalid reply id";
|
||||
mutex_session.unlock();
|
||||
// piCoutObj << "Done Packet" << h.id;
|
||||
}
|
||||
if (is_receiving && h.id == 0) {
|
||||
if (pt == pt_ReplySuccess) {
|
||||
mutex_session.lock();
|
||||
int cs = checkSession();
|
||||
mutex_session.unlock();
|
||||
//piCoutObj << "Success receive";
|
||||
if (cs == 0) finish_receive(true);
|
||||
send_up = 0;
|
||||
if (send_queue < 0) {
|
||||
send_queue = 0;
|
||||
break;
|
||||
}
|
||||
s = pm_string.find('+');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_Break:
|
||||
break_ = true;
|
||||
//piCoutObj << "BREAK";
|
||||
if (is_receiving) {
|
||||
stopReceive();
|
||||
return;
|
||||
}
|
||||
if (is_sending) {
|
||||
stopSend();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case pt_Start:
|
||||
mutex_header.lock();
|
||||
if (is_pause && (is_sending || is_receiving)) {
|
||||
if (header.session_id == h.session_id) {
|
||||
is_pause = false;
|
||||
mutex_header.unlock();
|
||||
resumed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (is_sending && header.session_id != h.session_id) {
|
||||
sendBreak(h.session_id);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
}
|
||||
if (is_receiving) {
|
||||
if (header.session_id != h.session_id) {
|
||||
piCoutObj << "restart receive";
|
||||
mutex_header.unlock();
|
||||
finish_receive(false, true);
|
||||
} else {
|
||||
header.id = 0;
|
||||
sendReply(pt_ReplySuccess);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
mutex_header.unlock();
|
||||
if (data.size() == sizeof(StartRequest)) {
|
||||
StartRequest sr;
|
||||
data >> sr;
|
||||
if (s1 - send_queue > 1 && packets_count > 2) packets_count -= piMaxi(packets_count / 10, 1);
|
||||
if (s1 == send_queue && s1 < piMaxi(packets_count / 2, 2) && packets_count < 100) send_up++;
|
||||
if (send_up > 20 && send_up > packets_count * 2) packets_count += piMaxi(packets_count / 10, 1);
|
||||
// piCoutObj << packets_count;
|
||||
} else
|
||||
piCoutObj << "invalid reply id";
|
||||
mutex_session.unlock();
|
||||
// piCoutObj << "Done Packet" << h.id;
|
||||
}
|
||||
if (is_receiving && h.id == 0) {
|
||||
if (pt == pt_ReplySuccess) {
|
||||
mutex_session.lock();
|
||||
mutex_header.lock();
|
||||
bytes_cur = 0;
|
||||
state_string = "start request";
|
||||
bytes_all = sr.size;
|
||||
header.session_id = h.session_id;
|
||||
header.id = 0;
|
||||
packets_count = 10;
|
||||
session.clear();
|
||||
replies.clear();
|
||||
session.resize(sr.packets);
|
||||
replies.resize(sr.packets + 1);
|
||||
replies.fill(pt_Unknown);
|
||||
pm_string.resize(replies.size(), '-');
|
||||
diag.reset();
|
||||
//piCoutObj << "receiveStarted()";
|
||||
is_receiving = true;
|
||||
break_ = false;
|
||||
mutex_send.lock();
|
||||
send_queue = 0;
|
||||
mutex_send.unlock();
|
||||
beginReceive();
|
||||
receiveStarted();
|
||||
state_string = "receiving";
|
||||
replies[0] = pt_ReplySuccess;
|
||||
pm_string[0] = '#';
|
||||
int cs = checkSession();
|
||||
mutex_session.unlock();
|
||||
// piCoutObj << "Success receive";
|
||||
if (cs == 0) finish_receive(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_Break:
|
||||
break_ = true;
|
||||
// piCoutObj << "BREAK";
|
||||
if (is_receiving) {
|
||||
stopReceive();
|
||||
return;
|
||||
}
|
||||
if (is_sending) {
|
||||
stopSend();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case pt_Start:
|
||||
mutex_header.lock();
|
||||
if (is_pause && (is_sending || is_receiving)) {
|
||||
if (header.session_id == h.session_id) {
|
||||
is_pause = false;
|
||||
mutex_header.unlock();
|
||||
resumed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (is_sending && header.session_id != h.session_id) {
|
||||
sendBreak(h.session_id);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
}
|
||||
if (is_receiving) {
|
||||
if (header.session_id != h.session_id) {
|
||||
piCoutObj << "restart receive";
|
||||
mutex_header.unlock();
|
||||
finish_receive(false, true);
|
||||
} else {
|
||||
header.id = 0;
|
||||
sendReply(pt_ReplySuccess);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case pt_Pause:
|
||||
}
|
||||
mutex_header.unlock();
|
||||
if (data.size() == sizeof(StartRequest)) {
|
||||
StartRequest sr;
|
||||
data >> sr;
|
||||
mutex_session.lock();
|
||||
mutex_header.lock();
|
||||
if (header.session_id == h.session_id) {
|
||||
//piCout << "receive pause";
|
||||
if (!is_pause && pause_tm.elapsed_s() < timeout_/10) {
|
||||
//piCout << "resume";
|
||||
sendReply(pt_Start);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
}
|
||||
if (!is_pause) paused();
|
||||
is_pause = true;
|
||||
if (is_receiving && pause_tm.elapsed_m() > 40) {
|
||||
//piCout << "send pause";
|
||||
sendReply(pt_Pause);
|
||||
}
|
||||
if (is_sending) send_tm.reset();
|
||||
pause_tm.reset();
|
||||
}
|
||||
bytes_cur = 0;
|
||||
state_string = "start request";
|
||||
bytes_all = sr.size;
|
||||
header.session_id = h.session_id;
|
||||
header.id = 0;
|
||||
packets_count = 10;
|
||||
session.clear();
|
||||
replies.clear();
|
||||
session.resize(sr.packets);
|
||||
replies.resize(sr.packets + 1);
|
||||
replies.fill(pt_Unknown);
|
||||
pm_string.resize(replies.size(), '-');
|
||||
diag.reset();
|
||||
// piCoutObj << "receiveStarted()";
|
||||
is_receiving = true;
|
||||
break_ = false;
|
||||
mutex_send.lock();
|
||||
send_queue = 0;
|
||||
mutex_send.unlock();
|
||||
beginReceive();
|
||||
receiveStarted();
|
||||
state_string = "receiving";
|
||||
replies[0] = pt_ReplySuccess;
|
||||
pm_string[0] = '#';
|
||||
mutex_session.unlock();
|
||||
sendReply(pt_ReplySuccess);
|
||||
mutex_header.unlock();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case pt_Pause:
|
||||
mutex_header.lock();
|
||||
if (header.session_id == h.session_id) {
|
||||
// piCout << "receive pause";
|
||||
if (!is_pause && pause_tm.elapsed_s() < timeout_ / 10) {
|
||||
// piCout << "resume";
|
||||
sendReply(pt_Start);
|
||||
mutex_header.unlock();
|
||||
return;
|
||||
}
|
||||
if (!is_pause) paused();
|
||||
is_pause = true;
|
||||
if (is_receiving && pause_tm.elapsed_m() > 40) {
|
||||
// piCout << "send pause";
|
||||
sendReply(pt_Pause);
|
||||
}
|
||||
if (is_sending) send_tm.reset();
|
||||
pause_tm.reset();
|
||||
}
|
||||
mutex_header.unlock();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,10 +278,10 @@ void PIBaseTransfer::received(PIByteArray data) {
|
||||
bool PIBaseTransfer::send_process() {
|
||||
mutex_session.lock();
|
||||
packet_header_size = sizeof(PacketHeader) + customHeader().size();
|
||||
break_ = false;
|
||||
break_ = false;
|
||||
diag.reset();
|
||||
sendStarted();
|
||||
is_sending = true;
|
||||
is_sending = true;
|
||||
int session_size = session.size();
|
||||
replies.resize(session_size + 1);
|
||||
replies.fill(pt_Unknown);
|
||||
@@ -288,7 +293,7 @@ bool PIBaseTransfer::send_process() {
|
||||
PITimeMeasurer stm;
|
||||
mutex_send.lock();
|
||||
send_queue = 0;
|
||||
send_up = 0;
|
||||
send_up = 0;
|
||||
send_tm.reset();
|
||||
mutex_send.unlock();
|
||||
for (int i = 0; i < session_size; i++) {
|
||||
@@ -299,7 +304,7 @@ bool PIBaseTransfer::send_process() {
|
||||
--i;
|
||||
if (is_pause) {
|
||||
piMSleep(40);
|
||||
//piCout << "send pause";
|
||||
// piCout << "send pause";
|
||||
mutex_header.lock();
|
||||
sendReply(pt_Pause);
|
||||
mutex_header.unlock();
|
||||
@@ -313,7 +318,7 @@ bool PIBaseTransfer::send_process() {
|
||||
return finish_send(false);
|
||||
}
|
||||
if (stm.elapsed_s() > timeout_ / 2.) {
|
||||
send_up = 0;
|
||||
send_up = 0;
|
||||
send_queue = 0;
|
||||
pm_string.replaceAll("+", "-");
|
||||
}
|
||||
@@ -324,13 +329,13 @@ bool PIBaseTransfer::send_process() {
|
||||
ba = build_packet(i);
|
||||
diag.sended(ba.size_s());
|
||||
sendRequest(ba);
|
||||
pm_string[i+1] = '+';
|
||||
pm_string[i + 1] = '+';
|
||||
mutex_send.lock();
|
||||
send_queue++;
|
||||
mutex_send.unlock();
|
||||
if (break_) return finish_send(false);
|
||||
}
|
||||
// piCoutObj << "send done, checking";
|
||||
// piCoutObj << "send done, checking";
|
||||
PITimeMeasurer rtm;
|
||||
int prev_chk = 0;
|
||||
mutex_send.lock();
|
||||
@@ -339,35 +344,38 @@ bool PIBaseTransfer::send_process() {
|
||||
piMSleep(10);
|
||||
state_string = "sending more";
|
||||
while (rtm.elapsed_s() < timeout_) {
|
||||
//piCoutObj << "recovering...";
|
||||
// piCoutObj << "recovering...";
|
||||
mutex_session.lock();
|
||||
int chk = checkSession();
|
||||
mutex_session.unlock();
|
||||
if (chk == 0) return finish_send(true);
|
||||
if (chk != prev_chk) rtm.reset();
|
||||
if (chk != prev_chk)
|
||||
rtm.reset();
|
||||
else if (rtm.elapsed_m() < 100) {
|
||||
piMinSleep();
|
||||
continue;
|
||||
}
|
||||
if (is_pause) {
|
||||
piMSleep(40);
|
||||
//piCout << "send pause";
|
||||
// piCout << "send pause";
|
||||
mutex_header.lock();
|
||||
sendReply(pt_Pause);
|
||||
mutex_header.unlock();
|
||||
if (pause_tm.elapsed_s() > timeout())return finish_send(false);
|
||||
else continue;
|
||||
if (pause_tm.elapsed_s() > timeout())
|
||||
return finish_send(false);
|
||||
else
|
||||
continue;
|
||||
}
|
||||
prev_chk = chk;
|
||||
if (chk > 0) {
|
||||
//piCoutObj << "recovery packet" << chk;
|
||||
// piCoutObj << "recovery packet" << chk;
|
||||
mutex_send.lock();
|
||||
int sq = send_queue;
|
||||
mutex_send.unlock();
|
||||
if (sq >= packets_count) {
|
||||
piMSleep(10);
|
||||
send_queue = 0;
|
||||
send_up = 0;
|
||||
send_up = 0;
|
||||
pm_string.replaceAll("+", "-");
|
||||
continue;
|
||||
}
|
||||
@@ -393,12 +401,13 @@ int PIBaseTransfer::checkSession() {
|
||||
if (replies[i] == pt_ReplyInvalid) return i;
|
||||
}
|
||||
for (int i = 1; i < replies.size_s(); i++) {
|
||||
if (replies[i] != pt_ReplySuccess) return i;
|
||||
if (replies[i] != pt_ReplySuccess) return i;
|
||||
}
|
||||
if (miss > 0) {
|
||||
//piCoutObj << "missing" << miss << "packets";
|
||||
// piCoutObj << "missing" << miss << "packets";
|
||||
return -miss;
|
||||
} else return 0;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -408,7 +417,7 @@ void PIBaseTransfer::buildSession(PIVector<Part> parts) {
|
||||
state_string = "calculating parts ... ";
|
||||
session.clear();
|
||||
header.session_id = randomi();
|
||||
bytes_all = 0;
|
||||
bytes_all = 0;
|
||||
Part fi;
|
||||
int fi_index, fi_prts;
|
||||
PIVector<Part> lfi;
|
||||
@@ -416,21 +425,21 @@ void PIBaseTransfer::buildSession(PIVector<Part> parts) {
|
||||
int cur_size = min_size;
|
||||
for (int i = 0; i < parts.size_s(); i++) {
|
||||
state_string = "calculating parts ... " + PIString::fromNumber(i) + " of " + PIString::fromNumber(parts.size());
|
||||
fi.id = parts[i].id;
|
||||
//piCout << fi.id << state_string;
|
||||
fi.id = parts[i].id;
|
||||
// piCout << fi.id << state_string;
|
||||
bytes_all += parts[i].size;
|
||||
fi.start = 0;
|
||||
fi.start = 0;
|
||||
llong rest = parts[i].size - (packet_size - cur_size);
|
||||
//piCout << i << fi.size << rest << bytes_all;
|
||||
// piCout << i << fi.size << rest << bytes_all;
|
||||
if (rest <= 0) {
|
||||
fi.size = parts[i].size;
|
||||
lfi << fi;
|
||||
cur_size += fi.size + part_header_size;
|
||||
} else {
|
||||
fi.size = parts[i].size - rest;
|
||||
fi.size = parts[i].size - rest;
|
||||
fi_index = 1;
|
||||
fi_prts = 1 + 1 + piMaxi(1, rest / (packet_size - min_size));
|
||||
//piCout << fi_prts;
|
||||
fi_prts = 1 + 1 + piMaxi(1, rest / (packet_size - min_size));
|
||||
// piCout << fi_prts;
|
||||
lfi << fi;
|
||||
session << lfi;
|
||||
lfi.clear();
|
||||
@@ -439,7 +448,7 @@ void PIBaseTransfer::buildSession(PIVector<Part> parts) {
|
||||
for (int j = 1; j < fi_prts; j++) {
|
||||
fi_index++;
|
||||
fi.start = fs;
|
||||
fi.size = piMin<ullong>(parts[i].size - fs, packet_size - min_size);
|
||||
fi.size = piMin<ullong>(parts[i].size - fs, packet_size - min_size);
|
||||
lfi << fi;
|
||||
cur_size += fi.size + part_header_size;
|
||||
if (fi_index != fi_prts) {
|
||||
@@ -463,8 +472,8 @@ void PIBaseTransfer::buildSession(PIVector<Part> parts) {
|
||||
|
||||
|
||||
void PIBaseTransfer::sendBreak(int session_id) {
|
||||
//piCoutObj << "sendBreak";
|
||||
uint psid = header.session_id;
|
||||
// piCoutObj << "sendBreak";
|
||||
uint psid = header.session_id;
|
||||
header.session_id = session_id;
|
||||
sendReply(pt_Break);
|
||||
header.session_id = psid;
|
||||
@@ -472,7 +481,7 @@ void PIBaseTransfer::sendBreak(int session_id) {
|
||||
|
||||
|
||||
void PIBaseTransfer::sendReply(PacketType reply) {
|
||||
//piCoutObj << "sendReply" << reply;
|
||||
// piCoutObj << "sendReply" << reply;
|
||||
header.type = reply;
|
||||
PIByteArray ba;
|
||||
ba << header;
|
||||
@@ -484,11 +493,11 @@ void PIBaseTransfer::sendReply(PacketType reply) {
|
||||
bool PIBaseTransfer::getStartRequest() {
|
||||
mutex_header.lock();
|
||||
header.type = pt_Start;
|
||||
header.id = 0;
|
||||
header.id = 0;
|
||||
PIByteArray ba;
|
||||
StartRequest st;
|
||||
st.packets = (uint)session.size();
|
||||
st.size = bytes_all;
|
||||
st.size = bytes_all;
|
||||
ba << header;
|
||||
mutex_header.unlock();
|
||||
ba << st;
|
||||
@@ -498,11 +507,11 @@ bool PIBaseTransfer::getStartRequest() {
|
||||
diag.sended(ba.size_s());
|
||||
sendRequest(ba);
|
||||
if (break_) return false;
|
||||
// piCoutObj << replies[0];
|
||||
// piCoutObj << replies[0];
|
||||
mutex_session.lock();
|
||||
if (replies[0] == pt_ReplySuccess) {
|
||||
state_string = "send permited!";
|
||||
//piCoutObj << "ping " << tm.elapsed_m();
|
||||
// piCoutObj << "ping " << tm.elapsed_m();
|
||||
mutex_session.unlock();
|
||||
return true;
|
||||
}
|
||||
@@ -514,14 +523,14 @@ bool PIBaseTransfer::getStartRequest() {
|
||||
|
||||
|
||||
void PIBaseTransfer::processData(int id, PIByteArray & data) {
|
||||
// piCoutObj << "received packet" << id << ", size" << data.size();
|
||||
// piCoutObj << "received packet" << id << ", size" << data.size();
|
||||
if (id < 1 || id > replies.size_s()) return;
|
||||
if (!session[id - 1].isEmpty()) {
|
||||
header.id = id;
|
||||
replies[id] = pt_ReplySuccess;
|
||||
header.id = id;
|
||||
replies[id] = pt_ReplySuccess;
|
||||
pm_string[id] = '#';
|
||||
sendReply(pt_ReplySuccess);
|
||||
if (replies[replies.size()-1] == pt_ReplySuccess)
|
||||
if (replies[replies.size() - 1] == pt_ReplySuccess)
|
||||
if (checkSession() == 0) state_string = "receive ok";
|
||||
return;
|
||||
}
|
||||
@@ -537,13 +546,13 @@ void PIBaseTransfer::processData(int id, PIByteArray & data) {
|
||||
data >> fi;
|
||||
data >> ba;
|
||||
bytes_cur += fi.size;
|
||||
//piCoutObj << "recv" << fi;
|
||||
// piCoutObj << "recv" << fi;
|
||||
session[id - 1] << fi;
|
||||
state_string = "receiving...";
|
||||
receivePart(fi, ba, pheader);
|
||||
}
|
||||
header.id = id;
|
||||
replies[id] = pt_ReplySuccess;
|
||||
header.id = id;
|
||||
replies[id] = pt_ReplySuccess;
|
||||
pm_string[id] = '#';
|
||||
sendReply(pt_ReplySuccess);
|
||||
if (checkSession() == 0) state_string = "receive ok";
|
||||
@@ -553,13 +562,13 @@ void PIBaseTransfer::processData(int id, PIByteArray & data) {
|
||||
PIByteArray PIBaseTransfer::build_packet(int id) {
|
||||
PIByteArray ret;
|
||||
PIByteArray ba;
|
||||
//piCoutObj << "session id" << header.session_id;
|
||||
// piCoutObj << "session id" << header.session_id;
|
||||
ret.append(customHeader());
|
||||
mutex_session.lock();
|
||||
for (int i = 0; i < session[id].size_s(); i++) {
|
||||
Part fi = session[id][i];
|
||||
ret << fi;
|
||||
//piCout << "build" << fi;
|
||||
// piCout << "build" << fi;
|
||||
ba = buildPacket(fi);
|
||||
bytes_cur += ba.size();
|
||||
if (ba.size() != fi.size) piCoutObj << "***error while build packet, wrong part size";
|
||||
@@ -568,28 +577,34 @@ PIByteArray PIBaseTransfer::build_packet(int id) {
|
||||
mutex_session.unlock();
|
||||
PIByteArray hdr;
|
||||
mutex_header.lock();
|
||||
header.id = id + 1;
|
||||
header.id = id + 1;
|
||||
header.type = pt_Data;
|
||||
if (crc_enabled) header.crc = crc.calculate(ret);
|
||||
else header.crc = 0;
|
||||
if (crc_enabled)
|
||||
header.crc = crc.calculate(ret);
|
||||
else
|
||||
header.crc = 0;
|
||||
hdr << header;
|
||||
mutex_header.unlock();
|
||||
ret.insert(0, hdr);
|
||||
// piCoutObj << "Send Packet" << header.id << ret.size();
|
||||
// piCoutObj << "Send Packet" << header.id << ret.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIBaseTransfer::finish_send(bool ok) {
|
||||
is_sending = false;
|
||||
if (ok) state_string = "send done";
|
||||
else state_string = "send failed";
|
||||
if (ok)
|
||||
state_string = "send done";
|
||||
else
|
||||
state_string = "send failed";
|
||||
mutex_header.lock();
|
||||
header.id = 0;
|
||||
if (!ok) sendBreak(header.session_id);
|
||||
else sendReply(pt_ReplySuccess);
|
||||
if (!ok)
|
||||
sendBreak(header.session_id);
|
||||
else
|
||||
sendReply(pt_ReplySuccess);
|
||||
mutex_header.unlock();
|
||||
//piCoutObj << state_string << PIString::readableSize(bytes_all);
|
||||
// piCoutObj << state_string << PIString::readableSize(bytes_all);
|
||||
sendFinished(ok);
|
||||
bytes_all = bytes_cur = 0;
|
||||
return ok;
|
||||
@@ -598,15 +613,16 @@ bool PIBaseTransfer::finish_send(bool ok) {
|
||||
|
||||
void PIBaseTransfer::finish_receive(bool ok, bool quet) {
|
||||
is_receiving = false;
|
||||
if (ok) state_string = "receive done";
|
||||
else state_string = "receive failed";
|
||||
if (ok)
|
||||
state_string = "receive done";
|
||||
else
|
||||
state_string = "receive failed";
|
||||
if (!ok && !quet) {
|
||||
mutex_header.lock();
|
||||
sendBreak(header.session_id);
|
||||
mutex_header.unlock();
|
||||
}
|
||||
//piCoutObj << state_string << PIString::readableSize(bytes_all);
|
||||
// piCoutObj << state_string << PIString::readableSize(bytes_all);
|
||||
receiveFinished(ok);
|
||||
bytes_all = bytes_cur = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Базовый класс для надежного обмена данными с помощью фиксированных пакетов с коррекцией ошибок и паузой
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Base class for reliable send and receive data in fixed packets with error correction, pause and resume
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Base class for reliable send and receive data in fixed packets with error correction, pause and resume
|
||||
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 PIBASETRANSFER_H
|
||||
@@ -29,61 +29,67 @@
|
||||
#include "picrc.h"
|
||||
#include "pidiagnostics.h"
|
||||
|
||||
class PIP_EXPORT PIBaseTransfer: public PIObject
|
||||
{
|
||||
class PIP_EXPORT PIBaseTransfer: public PIObject {
|
||||
PIOBJECT_SUBCLASS(PIBaseTransfer, PIObject);
|
||||
|
||||
public:
|
||||
PIBaseTransfer();
|
||||
~PIBaseTransfer();
|
||||
|
||||
# pragma pack(push,1)
|
||||
#pragma pack(push, 1)
|
||||
struct PIP_EXPORT PacketHeader {
|
||||
uint sig;
|
||||
int type; // PacketType
|
||||
int session_id;
|
||||
uint id;
|
||||
uint crc;
|
||||
bool check_sig() {return (sig == signature);}
|
||||
bool check_sig() { return (sig == signature); }
|
||||
};
|
||||
|
||||
|
||||
struct PIP_EXPORT Part {
|
||||
Part(uint id_ = 0, ullong size_ = 0, ullong start_ = 0) : id(id_), size(size_), start(start_) {}
|
||||
Part(uint id_ = 0, ullong size_ = 0, ullong start_ = 0): id(id_), size(size_), start(start_) {}
|
||||
uint id;
|
||||
ullong size;
|
||||
ullong start;
|
||||
};
|
||||
# pragma pack(pop)
|
||||
#pragma pack(pop)
|
||||
|
||||
void stopSend();
|
||||
void stopReceive();
|
||||
|
||||
bool isSending() const {return is_sending;}
|
||||
bool isReceiving() const {return is_receiving;}
|
||||
bool isPause() const {return is_pause;}
|
||||
bool isSending() const { return is_sending; }
|
||||
bool isReceiving() const { return is_receiving; }
|
||||
bool isPause() const { return is_pause; }
|
||||
void setPause(bool pause_);
|
||||
|
||||
void setPacketSize(int size) {packet_size = size;}
|
||||
int packetSize() const {return packet_size;}
|
||||
void setPacketSize(int size) { packet_size = size; }
|
||||
int packetSize() const { return packet_size; }
|
||||
|
||||
void setTimeout(double sec) {timeout_ = sec; diag.setDisconnectTimeout(sec);}
|
||||
double timeout() const {return timeout_;}
|
||||
void setTimeout(double sec) {
|
||||
timeout_ = sec;
|
||||
diag.setDisconnectTimeout(sec);
|
||||
}
|
||||
double timeout() const { return timeout_; }
|
||||
|
||||
void setCRCEnabled(bool en = true) {crc_enabled = en;}
|
||||
bool isCRCEnabled() const {return crc_enabled;}
|
||||
void setCRCEnabled(bool en = true) { crc_enabled = en; }
|
||||
bool isCRCEnabled() const { return crc_enabled; }
|
||||
|
||||
PIString stateString() const {return state_string;}
|
||||
PIString packetMap() const {return pm_string;}
|
||||
llong bytesAll() const {return bytes_all;}
|
||||
llong bytesCur() const {return bytes_cur;}
|
||||
const PIDiagnostics &diagnostic() {return diag;}
|
||||
PIString stateString() const { return state_string; }
|
||||
PIString packetMap() const { return pm_string; }
|
||||
llong bytesAll() const { return bytes_all; }
|
||||
llong bytesCur() const { return bytes_cur; }
|
||||
const PIDiagnostics & diagnostic() { return diag; }
|
||||
|
||||
static uint packetSignature() {return signature;}
|
||||
static uint packetSignature() { return signature; }
|
||||
|
||||
EVENT_HANDLER1(void, received, PIByteArray, data);
|
||||
EVENT_HANDLER(void, stop) {stopSend(); stopReceive();}
|
||||
EVENT_HANDLER(void, pause) {setPause(true);}
|
||||
EVENT_HANDLER(void, resume) {setPause(false);}
|
||||
|
||||
EVENT_HANDLER(void, stop) {
|
||||
stopSend();
|
||||
stopReceive();
|
||||
}
|
||||
EVENT_HANDLER(void, pause) { setPause(true); }
|
||||
EVENT_HANDLER(void, resume) { setPause(false); }
|
||||
|
||||
EVENT(receiveStarted);
|
||||
EVENT(paused);
|
||||
EVENT(resumed);
|
||||
@@ -94,30 +100,38 @@ public:
|
||||
|
||||
protected:
|
||||
void buildSession(PIVector<Part> parts);
|
||||
virtual PIByteArray buildPacket(Part fi) = 0;
|
||||
virtual PIByteArray buildPacket(Part fi) = 0;
|
||||
virtual void receivePart(Part fi, PIByteArray ba, PIByteArray pheader) = 0;
|
||||
virtual void beginReceive() {;}
|
||||
virtual PIByteArray customHeader() {return PIByteArray();}
|
||||
virtual void beginReceive() { ; }
|
||||
virtual PIByteArray customHeader() { return PIByteArray(); }
|
||||
bool send_process();
|
||||
|
||||
|
||||
uint packet_header_size, part_header_size;
|
||||
bool break_, is_sending, is_receiving, is_pause;
|
||||
PIString state_string;
|
||||
llong bytes_all, bytes_cur;
|
||||
|
||||
private:
|
||||
enum PacketType {pt_Unknown, pt_Data, pt_ReplySuccess, pt_ReplyInvalid, pt_Break, pt_Start, pt_Pause};
|
||||
enum PacketType {
|
||||
pt_Unknown,
|
||||
pt_Data,
|
||||
pt_ReplySuccess,
|
||||
pt_ReplyInvalid,
|
||||
pt_Break,
|
||||
pt_Start,
|
||||
pt_Pause
|
||||
};
|
||||
|
||||
# pragma pack(push,1)
|
||||
#pragma pack(push, 1)
|
||||
struct PIP_EXPORT StartRequest {
|
||||
uint packets;
|
||||
ullong size;
|
||||
};
|
||||
# pragma pack(pop)
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
BINARY_STREAM_FRIEND(PIBaseTransfer::StartRequest);
|
||||
|
||||
void processData(int id, PIByteArray &data);
|
||||
void processData(int id, PIByteArray & data);
|
||||
PIByteArray build_packet(int id);
|
||||
int checkSession();
|
||||
void sendBreak(int session_id);
|
||||
@@ -129,7 +143,7 @@ private:
|
||||
static const uint signature;
|
||||
int packet_size, packets_count;
|
||||
double timeout_;
|
||||
PIVector<PIVector<Part> > session;
|
||||
PIVector<PIVector<Part>> session;
|
||||
PIVector<PacketType> replies;
|
||||
PITimeMeasurer send_tm, pause_tm;
|
||||
PacketHeader header;
|
||||
@@ -145,16 +159,39 @@ private:
|
||||
};
|
||||
|
||||
|
||||
BINARY_STREAM_WRITE(PIBaseTransfer::PacketHeader) {s << v.sig << v.type << v.session_id << v.id << v.crc; return s;}
|
||||
BINARY_STREAM_READ (PIBaseTransfer::PacketHeader) {s >> v.sig >> v.type >> v.session_id >> v.id >> v.crc; return s;}
|
||||
BINARY_STREAM_WRITE(PIBaseTransfer::PacketHeader) {
|
||||
s << v.sig << v.type << v.session_id << v.id << v.crc;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIBaseTransfer::PacketHeader) {
|
||||
s >> v.sig >> v.type >> v.session_id >> v.id >> v.crc;
|
||||
return s;
|
||||
}
|
||||
|
||||
BINARY_STREAM_WRITE(PIBaseTransfer::Part) {s << v.id << v.size << v.start; return s;}
|
||||
BINARY_STREAM_READ (PIBaseTransfer::Part) {s >> v.id >> v.size >> v.start; return s;}
|
||||
BINARY_STREAM_WRITE(PIBaseTransfer::Part) {
|
||||
s << v.id << v.size << v.start;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIBaseTransfer::Part) {
|
||||
s >> v.id >> v.size >> v.start;
|
||||
return s;
|
||||
}
|
||||
|
||||
BINARY_STREAM_WRITE(PIBaseTransfer::StartRequest) {s << v.packets << v.size; return s;}
|
||||
BINARY_STREAM_READ (PIBaseTransfer::StartRequest) {s >> v.packets >> v.size; return s;}
|
||||
BINARY_STREAM_WRITE(PIBaseTransfer::StartRequest) {
|
||||
s << v.packets << v.size;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIBaseTransfer::StartRequest) {
|
||||
s >> v.packets >> v.size;
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PIBaseTransfer::Part & v) {s.saveAndSetControls(0); s << "Part(\"" << v.id << "\", " << PIString::readableSize(v.start) << " b | " << PIString::readableSize(v.size) << " b)"; s.restoreControls(); return s;}
|
||||
inline PICout operator<<(PICout s, const PIBaseTransfer::Part & v) {
|
||||
s.saveAndSetControls(0);
|
||||
s << "Part(\"" << v.id << "\", " << PIString::readableSize(v.start) << " b | " << PIString::readableSize(v.size) << " b)";
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIBASETRANSFER_H
|
||||
|
||||
@@ -5,42 +5,44 @@
|
||||
* \~russian Широкое вещание на все интерфейсы, включая loopback
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Broadcast for all interfaces, including loopback
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Broadcast for all interfaces, including loopback
|
||||
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 PIBROADCAST_H
|
||||
#define PIBROADCAST_H
|
||||
|
||||
#include "pip_io_utils_export.h"
|
||||
#include "piethutilbase.h"
|
||||
#include "piethernet.h"
|
||||
#include "piethutilbase.h"
|
||||
#include "pip_io_utils_export.h"
|
||||
|
||||
|
||||
class PIP_IO_UTILS_EXPORT PIBroadcast: public PIThread, public PIEthUtilBase {
|
||||
class PIP_IO_UTILS_EXPORT PIBroadcast
|
||||
: public PIThread
|
||||
, public PIEthUtilBase {
|
||||
PIOBJECT_SUBCLASS(PIBroadcast, PIThread);
|
||||
public:
|
||||
|
||||
public:
|
||||
//! %PIBroadcast channels, can be used independently
|
||||
enum Channel {
|
||||
Multicast /** Use multicast addresses */ = 0x01,
|
||||
Broadcast /** Use broadcast addresses */ = 0x02,
|
||||
Loopback /** Use loopback addresses */ = 0x04,
|
||||
All /** Use all channels */ = 0xFFFF,
|
||||
Loopback /** Use loopback addresses */ = 0x04,
|
||||
All /** Use all channels */ = 0xFFFF,
|
||||
};
|
||||
|
||||
typedef PIFlags<Channel> Channels;
|
||||
@@ -56,49 +58,49 @@ public:
|
||||
void setChannels(Channels ch);
|
||||
|
||||
//! Returns channels
|
||||
Channels channels() const {return _channels;}
|
||||
Channels channels() const { return _channels; }
|
||||
|
||||
//! Returns if is send_only
|
||||
bool isSendOnly() const {return _send_only;}
|
||||
bool isSendOnly() const { return _send_only; }
|
||||
|
||||
|
||||
//! Set multicast IP to \"mg\" and queue to reinit
|
||||
void setMulticastGroup(const PIString & mg);
|
||||
|
||||
//! Returns multicast IP
|
||||
PIString multicastGroup() const {return mcast_address.ipString();}
|
||||
PIString multicastGroup() const { return mcast_address.ipString(); }
|
||||
|
||||
//! Set multicast port to \"port\" and queue to reinit
|
||||
void setMulticastPort(ushort port);
|
||||
|
||||
//! Returns multicast port
|
||||
ushort multicastPort() const {return mcast_address.port();}
|
||||
ushort multicastPort() const { return mcast_address.port(); }
|
||||
|
||||
//! Set multicast address to \"addr\" and queue to reinit
|
||||
void setMulticastAddress(const PIEthernet::Address & addr);
|
||||
|
||||
//! Returns multicast address
|
||||
PIEthernet::Address multicastAddress() const {return mcast_address;}
|
||||
PIEthernet::Address multicastAddress() const { return mcast_address; }
|
||||
|
||||
|
||||
//! Set broadcast port to \"port\" and queue to reinit
|
||||
void setBroadcastPort(ushort port);
|
||||
|
||||
//! Returns broadcast port
|
||||
ushort broadcastPort() {return bcast_port;}
|
||||
ushort broadcastPort() { return bcast_port; }
|
||||
|
||||
|
||||
//! Set loopback start port to \"port\" and queue to reinit
|
||||
void setLoopbackPort(ushort port);
|
||||
|
||||
//! Returns loopback start port
|
||||
ushort loopbackPort() {return lo_port;}
|
||||
ushort loopbackPort() { return lo_port; }
|
||||
|
||||
//! Set loopback ports count to \"count\" and queue to reinit
|
||||
void setLoopbackPortsCount(int count);
|
||||
|
||||
//! Returns loopback ports count
|
||||
int loopbackPortsCount() const {return lo_pcnt;}
|
||||
int loopbackPortsCount() const { return lo_pcnt; }
|
||||
|
||||
|
||||
//! If not send_only starts all threaded reads
|
||||
@@ -119,13 +121,12 @@ public:
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void receiveEvent(PIByteArray data)
|
||||
//! \brief Raise on packet received
|
||||
//! \fn void receiveEvent(PIByteArray data)
|
||||
//! \brief Raise on packet received
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
//! Called when packet received
|
||||
virtual void received(PIByteArray data) {}
|
||||
|
||||
@@ -133,7 +134,7 @@ protected:
|
||||
virtual void addressesChanged() {}
|
||||
|
||||
private:
|
||||
EVENT_HANDLER2(void, mcastRead, const uchar * , data, ssize_t, size);
|
||||
EVENT_HANDLER2(void, mcastRead, const uchar *, data, ssize_t, size);
|
||||
void destroyAll();
|
||||
void initAll(PIVector<PIEthernet::Address> al);
|
||||
void run() override;
|
||||
@@ -141,13 +142,12 @@ private:
|
||||
Channels _channels;
|
||||
PIEthernet::Address mcast_address;
|
||||
PIMutex mcast_mutex;
|
||||
PIVector<PIEthernet*> eth_mcast;
|
||||
PIVector<PIEthernet *> eth_mcast;
|
||||
PIEthernet * eth_lo;
|
||||
PIVector<PIEthernet::Address> prev_al;
|
||||
ushort lo_port, bcast_port;
|
||||
int lo_pcnt;
|
||||
bool _started, _send_only, _reinit;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIBROADCAST_H
|
||||
|
||||
@@ -1,43 +1,44 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
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 "piconnection.h"
|
||||
|
||||
#include "piconfig.h"
|
||||
#include "piiostream.h"
|
||||
|
||||
/** \class PIConnection
|
||||
* \brief Complex Input/Output point
|
||||
*
|
||||
*
|
||||
* \section PIConnection_synopsis Synopsis
|
||||
* %PIConnection provides abstract layer over physical devices,
|
||||
* filtering and connecting data streams. Each %PIConnection
|
||||
* works through Device Pool, so several %PIConnections can
|
||||
* read from single physical device. General scheme:
|
||||
* \image html piconnection.png
|
||||
*
|
||||
*
|
||||
* \section PIConnection_pool Device pool concept
|
||||
* Device pool is static object, single for each application, which
|
||||
* contains unique devices. Each %PIConnection works with real devices
|
||||
* through Device pool. Each device has assosiated thread for read
|
||||
* and it can be started or stopped with %PIConnection functions
|
||||
* \a startThreadedRead() and \a stopThreadedRead().
|
||||
*
|
||||
*
|
||||
* \section PIConnection_filters Filters
|
||||
* %PIConnection filter is a PIPacketExtractor and assosiated
|
||||
* array of devices or other filters. When read thread is successfully read
|
||||
@@ -48,11 +49,11 @@
|
||||
* One filter can receive data from several sources, and can be bounded to
|
||||
* several filters.
|
||||
* \image html piconnection_filters.png
|
||||
*
|
||||
*
|
||||
* \section PIConnection_diag Diagnostics
|
||||
* %PIConnection create PIDiagnostics for each device or filter. You can
|
||||
* access to these objects with functions \a diagnostic().
|
||||
*
|
||||
*
|
||||
* \section PIConnection_sender Senders
|
||||
* %PIConnection can send data to devices with named timers ("senders").
|
||||
* You can create sender or add device to sender with function \a addSender().
|
||||
@@ -61,7 +62,7 @@
|
||||
* You can assign fixed send data to sender with function \a setSenderFixedData().
|
||||
* In this case sender will NOT execute \a senderData(), but send assigned data.
|
||||
* \image html piconnection_senders.png
|
||||
*
|
||||
*
|
||||
* \section PIConnection_config Configuration
|
||||
* You can create %PIConnection from config file section or configure
|
||||
* it later with function \a configureFromConfig(). Devices describes
|
||||
@@ -70,11 +71,11 @@
|
||||
* Also %PIConnection can create PIString with its configuration with
|
||||
* function \a makeConfig(). This string can be directly inserted into the
|
||||
* config file.
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
PIVector<PIConnection * > PIConnection::_connections;
|
||||
PIVector<PIConnection *> PIConnection::_connections;
|
||||
|
||||
|
||||
PIConnection::PIConnection(const PIString & name): PIObject(name) {
|
||||
@@ -123,20 +124,20 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
setName(name_);
|
||||
if (name_.isEmpty()) piCoutObj << "Warning, can't configure connection with empty name";
|
||||
PIConfig::Entry ce(conf.getValue(name_));
|
||||
PIConfig::Branch db(ce.getValue("device").children()), fb(ce.getValue("filter").children()),
|
||||
cb(ce.getValue("channel").children()), sb(ce.getValue("sender").children());
|
||||
PIConfig::Branch db(ce.getValue("device").children()), fb(ce.getValue("filter").children()), cb(ce.getValue("channel").children()),
|
||||
sb(ce.getValue("sender").children());
|
||||
PIStringList dev_list(ce.getValue("device").toString());
|
||||
PIStringList name_list(ce.getValue("device").name());
|
||||
PIStringList flt_list(ce.getValue("filter").toString());
|
||||
for (const PIConfig::Entry * e : db) {
|
||||
for (const PIConfig::Entry * e: db) {
|
||||
dev_list << e->value();
|
||||
name_list << e->name();
|
||||
}
|
||||
for (const PIConfig::Entry * e : fb) {
|
||||
for (const PIConfig::Entry * e: fb) {
|
||||
flt_list << e->name();
|
||||
}
|
||||
PISet<PIString> chk_set = (PISet<PIString>(name_list) & PISet<PIString>(flt_list));
|
||||
//piCout << name_list << flt_list << chk_set;
|
||||
// piCout << name_list << flt_list << chk_set;
|
||||
chk_set.remove("");
|
||||
if (!chk_set.isEmpty()) {
|
||||
piCoutObj << "Error," << chk_set.toVector() << "names assigned to both devices and filters!";
|
||||
@@ -149,8 +150,8 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
PIString & n(name_list[i]);
|
||||
PIIODevice::DeviceMode dm = PIIODevice::ReadWrite;
|
||||
PIIODevice::splitFullPath(fn, &fn, &dm);
|
||||
//piCout << fn;
|
||||
//piCoutObj << "add" << fn << n;
|
||||
// piCout << fn;
|
||||
// piCoutObj << "add" << fn << n;
|
||||
PIIODevice * dev = addDevice(fn, dm);
|
||||
if (!dev) continue;
|
||||
dev_aliases[n] = fn;
|
||||
@@ -167,13 +168,14 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
PIStringList filter_fails;
|
||||
while (added != padded && tries < 100) {
|
||||
padded = added;
|
||||
added = 0;
|
||||
added = 0;
|
||||
++tries;
|
||||
for (const PIConfig::Entry * e : fb) {
|
||||
for (const PIConfig::Entry * e: fb) {
|
||||
PIPacketExtractor::SplitMode sm = PIPacketExtractor::None;
|
||||
PIString sms(e->getValue("splitMode").value());
|
||||
int smi = sms.toInt();
|
||||
if (smi >= 1 && smi <= 5) sm = (PIPacketExtractor::SplitMode)smi;
|
||||
if (smi >= 1 && smi <= 5)
|
||||
sm = (PIPacketExtractor::SplitMode)smi;
|
||||
else {
|
||||
sms = sms.trim().toLowerCase();
|
||||
if (sms.find("header") >= 0 && sms.find("footer") >= 0)
|
||||
@@ -188,8 +190,7 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
if (sms.find("time") >= 0)
|
||||
sm = PIPacketExtractor::Timeout;
|
||||
else {
|
||||
if (sms.find("size") >= 0)
|
||||
sm = PIPacketExtractor::Size;
|
||||
if (sms.find("size") >= 0) sm = PIPacketExtractor::Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,12 +199,12 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
PIStringList devs(e->value());
|
||||
PIConfig::Branch db(e->getValue("device").children());
|
||||
devs << e->getValue("device", "").value();
|
||||
for (const PIConfig::Entry * e2 : db) {
|
||||
for (const PIConfig::Entry * e2: db) {
|
||||
devs << e2->value();
|
||||
}
|
||||
devs.removeStrings("");
|
||||
if (devs.isEmpty()) continue;
|
||||
PIString dname = dev_aliases.value(devs.front(), devs.front());
|
||||
PIString dname = dev_aliases.value(devs.front(), devs.front());
|
||||
PIPacketExtractor * pe = addFilter(e->name(), dname, sm);
|
||||
if (!pe) {
|
||||
if (!filter_fails.contains(dname)) filter_fails << dname;
|
||||
@@ -218,8 +219,7 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
filter_fails.removeAll(dname);
|
||||
++added;
|
||||
} else {
|
||||
if (!filter_fails.contains(dname))
|
||||
filter_fails << dname;
|
||||
if (!filter_fails.contains(dname)) filter_fails << dname;
|
||||
}
|
||||
}
|
||||
PIDiagnostics * diag = diags_.value(pe, nullptr);
|
||||
@@ -231,24 +231,24 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
}
|
||||
}
|
||||
setDebug(pdebug);
|
||||
for (const PIString & f : filter_fails) {
|
||||
for (const PIString & f: filter_fails) {
|
||||
piCoutObj << "\"addFilter\" error: no such device \"" << f << "\"!";
|
||||
}
|
||||
for (const PIConfig::Entry * e : cb) {
|
||||
for (const PIConfig::Entry * e: cb) {
|
||||
PIString f(e->getValue("from").value()), t(e->getValue("to").value());
|
||||
addChannel(dev_aliases.value(f, f), dev_aliases.value(t, t));
|
||||
}
|
||||
for (const PIConfig::Entry * e : sb) {
|
||||
for (const PIConfig::Entry * e: sb) {
|
||||
PIStringList devs(e->value());
|
||||
PIConfig::Branch db(e->getValue("device").children());
|
||||
devs << e->getValue("device", "").value();
|
||||
for (const PIConfig::Entry * e2 : db) {
|
||||
for (const PIConfig::Entry * e2: db) {
|
||||
devs << e2->value();
|
||||
}
|
||||
devs.removeStrings("");
|
||||
if (devs.isEmpty()) continue;
|
||||
float freq = e->getValue("frequency").toFloat();
|
||||
for (const PIString & d : devs) {
|
||||
for (const PIString & d: devs) {
|
||||
addSender(e->name(), dev_aliases.value(d, d), freq);
|
||||
}
|
||||
PIByteArray fd(PIByteArray::fromUserInput(e->getValue("fixedData").toString()));
|
||||
@@ -262,15 +262,15 @@ PIString PIConnection::makeConfig() const {
|
||||
PIString ret;
|
||||
PIIOTextStream ts(&ret);
|
||||
ts << "[" << name() << "]\n";
|
||||
PIVector<PIIODevice * > devs(boundedDevices());
|
||||
PIVector<PIIODevice *> devs(boundedDevices());
|
||||
int dn(-1);
|
||||
for (const PIIODevice * d : devs) {
|
||||
for (const PIIODevice * d: devs) {
|
||||
PIStringList dnl(deviceNames(d));
|
||||
if (dnl.isEmpty()) dnl << PIString::fromNumber(++dn);
|
||||
for (const PIString & dname : dnl) {
|
||||
for (const PIString & dname: dnl) {
|
||||
ts << "device." << dname << " = " << d->constructFullPath() << " #s\n";
|
||||
ts << "device." << dname << ".bufferSize = " << d->threadedReadBufferSize() << " #n\n";
|
||||
PIDiagnostics * diag = diags_.value(const_cast<PIIODevice * >(d), nullptr);
|
||||
PIDiagnostics * diag = diags_.value(const_cast<PIIODevice *>(d), nullptr);
|
||||
if (diag) ts << "device." << dname << ".disconnectTimeout = " << diag->disconnectTimeout() << " #f\n";
|
||||
}
|
||||
}
|
||||
@@ -301,11 +301,12 @@ PIString PIConnection::makeConfig() const {
|
||||
ts << prefix << ".header = " << ite.value()->extractor->header().toString() << " #s\n";
|
||||
ts << prefix << ".footer = " << ite.value()->extractor->footer().toString() << " #s\n";
|
||||
}
|
||||
dn = 0;
|
||||
dn = 0;
|
||||
auto itc = channels_.makeIterator();
|
||||
while (itc.next()) {
|
||||
for (const PIIODevice * d : itc.value()) {
|
||||
PIString prefix = "channel." + PIString::fromNumber(dn); ++dn;
|
||||
for (const PIIODevice * d: itc.value()) {
|
||||
PIString prefix = "channel." + PIString::fromNumber(dn);
|
||||
++dn;
|
||||
PIString dname = device_names.key(itc.key());
|
||||
if (dname.isEmpty()) dname = devPath(itc.key());
|
||||
ts << prefix << ".from = " << dname << " #s\n";
|
||||
@@ -324,10 +325,8 @@ PIString PIConnection::makeConfig() const {
|
||||
ts << prefix << ".device." << i << " = " << dname << " #s\n";
|
||||
}
|
||||
double int_ = its.value()->int_;
|
||||
if (int_ > 0.)
|
||||
ts << prefix << ".frequency = " << (1000. / int_) << " #f\n";
|
||||
if (!its.value()->sdata.isEmpty())
|
||||
ts << prefix << ".fixedData = " << its.value()->sdata.toString() << " #s\n";
|
||||
if (int_ > 0.) ts << prefix << ".frequency = " << (1000. / int_) << " #f\n";
|
||||
if (!its.value()->sdata.isEmpty()) ts << prefix << ".fixedData = " << its.value()->sdata.toString() << " #s\n";
|
||||
}
|
||||
ts << "[]\n";
|
||||
return ret;
|
||||
@@ -363,7 +362,7 @@ void PIConnection::setDeviceName(PIIODevice * dev, const PIString & name) {
|
||||
PIStringList PIConnection::deviceNames(const PIIODevice * dev) const {
|
||||
PIStringList ret;
|
||||
auto it = device_names.makeIterator();
|
||||
while(it.next()) {
|
||||
while (it.next()) {
|
||||
if (it.value() == dev) ret << it.key();
|
||||
}
|
||||
return ret;
|
||||
@@ -375,7 +374,7 @@ bool PIConnection::removeDevice(const PIString & full_path) {
|
||||
PIIODevice * dev = __device_pool__->device(fp);
|
||||
if (!dev) return false;
|
||||
PIStringList dntd(deviceNames(dev));
|
||||
for (const PIString & n : dntd) {
|
||||
for (const PIString & n: dntd) {
|
||||
device_names.remove(n);
|
||||
}
|
||||
for (auto s = senders.begin(); s != senders.end(); s++) {
|
||||
@@ -406,9 +405,9 @@ bool PIConnection::removeDevice(const PIString & full_path) {
|
||||
|
||||
void PIConnection::removeAllDevices() {
|
||||
device_names.clear();
|
||||
PIVector<PIIODevice * > bdevs(__device_pool__->boundedDevices(this));
|
||||
PIVector<PIIODevice *> bdevs(__device_pool__->boundedDevices(this));
|
||||
__device_pool__->lock();
|
||||
for (PIIODevice * d : bdevs) {
|
||||
for (PIIODevice * d: bdevs) {
|
||||
for (auto s = senders.begin(); s != senders.end(); s++) {
|
||||
if (!s.value()) continue;
|
||||
s.value()->lock();
|
||||
@@ -440,7 +439,7 @@ PIIODevice * PIConnection::deviceByFullPath(const PIString & full_path) const {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(fp, nullptr);
|
||||
if (!dd) return nullptr;
|
||||
if (!dd->dev) return nullptr;
|
||||
if (!dd->listeners.contains(const_cast<PIConnection * >(this))) return nullptr;
|
||||
if (!dd->listeners.contains(const_cast<PIConnection *>(this))) return nullptr;
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
@@ -450,16 +449,16 @@ PIIODevice * PIConnection::deviceByName(const PIString & name) const {
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::boundedDevices() const {
|
||||
PIVector<PIIODevice *> PIConnection::boundedDevices() const {
|
||||
return __device_pool__->boundedDevices(this);
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIString & full_path, PIPacketExtractor::SplitMode mode) {
|
||||
PIString fname_ = name_.trimmed();
|
||||
Extractor * e = extractors.value(fname_, nullptr);
|
||||
Extractor * e = extractors.value(fname_, nullptr);
|
||||
if (full_path.isEmpty()) return (e ? e->extractor : nullptr);
|
||||
PIIODevice * dev = devByString(full_path);
|
||||
PIIODevice * dev = devByString(full_path);
|
||||
PIPacketExtractor * pe = nullptr;
|
||||
if (extractors.value(full_path, nullptr)) pe = extractors.value(full_path, nullptr)->extractor;
|
||||
if (pe) dev = pe;
|
||||
@@ -468,7 +467,7 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
|
||||
return nullptr;
|
||||
}
|
||||
if (!e) {
|
||||
e = new Extractor();
|
||||
e = new Extractor();
|
||||
extractors[fname_] = e;
|
||||
}
|
||||
if (!e->extractor) {
|
||||
@@ -482,11 +481,11 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
|
||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||
}
|
||||
__device_pool__->unlock();
|
||||
CONNECT2(void, const uchar * , int, e->extractor, packetReceived, this, packetExtractorReceived)
|
||||
CONNECT2(void, const uchar *, int, e->extractor, packetReceived, this, packetExtractorReceived)
|
||||
}
|
||||
if (!e->devices.contains(dev)) {
|
||||
bounded_extractors[dev] << e->extractor;
|
||||
//if (PIString(dev->className()) == "PIPacketExtractor") dev->setThreadSafe(false);
|
||||
// if (PIString(dev->className()) == "PIPacketExtractor") dev->setThreadSafe(false);
|
||||
e->devices << dev;
|
||||
}
|
||||
return e->extractor;
|
||||
@@ -496,9 +495,9 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
|
||||
PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PIString & full_path) {
|
||||
Extractor * e = nullptr;
|
||||
if (full_path.isEmpty()) return nullptr;
|
||||
PIIODevice * dev = devByString(full_path);
|
||||
PIIODevice * dev = devByString(full_path);
|
||||
PIPacketExtractor * pe = nullptr;
|
||||
e = extractors.value(full_path, nullptr);
|
||||
e = extractors.value(full_path, nullptr);
|
||||
if (e) pe = e->extractor;
|
||||
if (pe) {
|
||||
dev = pe;
|
||||
@@ -507,7 +506,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI
|
||||
return nullptr;
|
||||
}
|
||||
if (!e) {
|
||||
e = new Extractor();
|
||||
e = new Extractor();
|
||||
extractors[filter->name()] = e;
|
||||
}
|
||||
if (!e->extractor) {
|
||||
@@ -520,7 +519,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI
|
||||
CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged);
|
||||
}
|
||||
__device_pool__->unlock();
|
||||
CONNECT2(void, const uchar * , int, e->extractor, packetReceived, this, packetExtractorReceived)
|
||||
CONNECT2(void, const uchar *, int, e->extractor, packetReceived, this, packetExtractorReceived)
|
||||
}
|
||||
if (!e->devices.contains(dev)) {
|
||||
bounded_extractors[dev] << e->extractor;
|
||||
@@ -586,8 +585,8 @@ void PIConnection::removeAllFilters() {
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIPacketExtractor * > PIConnection::filters() const {
|
||||
PIVector<PIPacketExtractor * > ret;
|
||||
PIVector<PIPacketExtractor *> PIConnection::filters() const {
|
||||
PIVector<PIPacketExtractor *> ret;
|
||||
for (auto i = extractors.begin(); i != extractors.end(); i++) {
|
||||
if (i.value()) {
|
||||
if (i.value()->extractor) ret << i.value()->extractor;
|
||||
@@ -618,8 +617,8 @@ PIPacketExtractor * PIConnection::filter(const PIString & name_) const {
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::filterBoundedDevices(const PIString & name_) const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
PIVector<PIIODevice *> PIConnection::filterBoundedDevices(const PIString & name_) const {
|
||||
PIVector<PIIODevice *> ret;
|
||||
Extractor * p = extractors.value(name_.trimmed());
|
||||
if (!p) return ret;
|
||||
return p->devices;
|
||||
@@ -627,12 +626,12 @@ PIVector<PIIODevice * > PIConnection::filterBoundedDevices(const PIString & name
|
||||
|
||||
|
||||
bool PIConnection::addChannel(const PIString & name0, const PIString & name1) {
|
||||
//piCout << "addChannel" << name0 << name1;
|
||||
// piCout << "addChannel" << name0 << name1;
|
||||
if (name0.isEmpty() || name1.isEmpty()) return false;
|
||||
PIIODevice * dev0 = devByString(name0);
|
||||
PIIODevice * dev1 = devByString(name1);
|
||||
Extractor * p0 = extractors.value(name0, nullptr);
|
||||
Extractor * p1 = extractors.value(name1, nullptr);
|
||||
PIIODevice * dev0 = devByString(name0);
|
||||
PIIODevice * dev1 = devByString(name1);
|
||||
Extractor * p0 = extractors.value(name0, nullptr);
|
||||
Extractor * p1 = extractors.value(name1, nullptr);
|
||||
PIPacketExtractor * pe0 = nullptr;
|
||||
PIPacketExtractor * pe1 = nullptr;
|
||||
if (p0) pe0 = p0->extractor;
|
||||
@@ -644,17 +643,16 @@ bool PIConnection::addChannel(const PIString & name0, const PIString & name1) {
|
||||
if (!dev1) piCoutObj << "\"addChannel\" error: no such device \"" << name1 << "\"!";
|
||||
return false;
|
||||
}
|
||||
if (!channels_[dev0].contains(dev1))
|
||||
channels_[dev0] << dev1;
|
||||
if (!channels_[dev0].contains(dev1)) channels_[dev0] << dev1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeChannel(const PIString & name0, const PIString & name1) {
|
||||
PIIODevice * dev0 = devByString(name0);
|
||||
PIIODevice * dev1 = devByString(name1);
|
||||
Extractor * p0 = extractors.value(name0, nullptr);
|
||||
Extractor * p1 = extractors.value(name1, nullptr);
|
||||
PIIODevice * dev0 = devByString(name0);
|
||||
PIIODevice * dev1 = devByString(name1);
|
||||
Extractor * p0 = extractors.value(name0, nullptr);
|
||||
Extractor * p1 = extractors.value(name1, nullptr);
|
||||
PIPacketExtractor * pe0 = nullptr;
|
||||
PIPacketExtractor * pe1 = nullptr;
|
||||
if (p0) pe0 = p0->extractor;
|
||||
@@ -668,8 +666,8 @@ bool PIConnection::removeChannel(const PIString & name0, const PIString & name1)
|
||||
|
||||
|
||||
bool PIConnection::removeChannel(const PIString & name0) {
|
||||
PIIODevice * dev0 = devByString(name0);
|
||||
Extractor * p0 = extractors.value(name0, nullptr);
|
||||
PIIODevice * dev0 = devByString(name0);
|
||||
Extractor * p0 = extractors.value(name0, nullptr);
|
||||
PIPacketExtractor * pe0 = nullptr;
|
||||
if (p0) pe0 = p0->extractor;
|
||||
if (pe0) dev0 = pe0;
|
||||
@@ -710,12 +708,12 @@ PIIODevice * PIConnection::devByString(const PIString & s) const {
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIPair<PIString, PIString > > PIConnection::channels() const {
|
||||
PIVector<PIPair<PIString, PIString > > ret;
|
||||
PIVector<PIPair<PIString, PIString>> PIConnection::channels() const {
|
||||
PIVector<PIPair<PIString, PIString>> ret;
|
||||
auto it = channels_.makeIterator();
|
||||
while (it.next()) {
|
||||
PIString fp0(devFPath(it.key()));
|
||||
for (const PIIODevice * d : it.value()) {
|
||||
for (const PIIODevice * d: it.value()) {
|
||||
ret << PIPair<PIString, PIString>(fp0, devFPath(d));
|
||||
}
|
||||
}
|
||||
@@ -730,7 +728,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_
|
||||
if (!s) {
|
||||
s = new Sender(this);
|
||||
s->setName(fname_);
|
||||
s->int_ = 1000. / frequency;
|
||||
s->int_ = 1000. / frequency;
|
||||
senders[fname_] = s;
|
||||
}
|
||||
PIIODevice * dev = devByString(full_path_name);
|
||||
@@ -739,7 +737,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_
|
||||
return;
|
||||
}
|
||||
if (!s->isRunning() && start_) {
|
||||
//piCoutObj << name_ << "start" << 1000. / frequency;
|
||||
// piCoutObj << name_ << "start" << 1000. / frequency;
|
||||
if (!__device_pool__->fake) s->start(s->int_);
|
||||
}
|
||||
s->lock();
|
||||
@@ -749,7 +747,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_
|
||||
|
||||
|
||||
bool PIConnection::removeSender(const PIString & name, const PIString & full_path_name) {
|
||||
Sender * s = senders.value(name, nullptr);
|
||||
Sender * s = senders.value(name, nullptr);
|
||||
PIIODevice * d = devByString(full_path_name);
|
||||
if (!s || !d) return false;
|
||||
s->lock();
|
||||
@@ -880,8 +878,8 @@ void PIConnection::stopAllSenders() {
|
||||
|
||||
|
||||
PIDiagnostics * PIConnection::diagnostic(const PIString & full_path_name) const {
|
||||
PIIODevice * dev = devByString(full_path_name);
|
||||
Extractor * e = extractors.value(full_path_name, nullptr);
|
||||
PIIODevice * dev = devByString(full_path_name);
|
||||
Extractor * e = extractors.value(full_path_name, nullptr);
|
||||
PIPacketExtractor * pe = nullptr;
|
||||
if (e) pe = e->extractor;
|
||||
if (pe) dev = pe;
|
||||
@@ -891,9 +889,9 @@ PIDiagnostics * PIConnection::diagnostic(const PIString & full_path_name) const
|
||||
|
||||
|
||||
int PIConnection::writeByFullPath(const PIString & full_path, const PIByteArray & data) {
|
||||
PIString fp = PIIODevice::normalizeFullPath(full_path);
|
||||
PIString fp = PIIODevice::normalizeFullPath(full_path);
|
||||
PIIODevice * dev = __device_pool__->device(fp);
|
||||
//piCout << "SEND" << full_path << fp;
|
||||
// piCout << "SEND" << full_path << fp;
|
||||
if (!dev) {
|
||||
piCoutObj << "No such full path \"" << full_path << "\"!";
|
||||
return -1;
|
||||
@@ -922,25 +920,25 @@ int PIConnection::write(PIIODevice * dev, const PIByteArray & data) {
|
||||
piCoutObj << "Device \"" << dev->constructFullPath() << "\" can`t write!";
|
||||
return -1;
|
||||
}
|
||||
int ret = dev->write(data);
|
||||
int ret = dev->write(data);
|
||||
PIDiagnostics * diag = diags_.value(dev, nullptr);
|
||||
if (diag && ret > 0) diag->sended(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIConnection * > PIConnection::allConnections() {
|
||||
PIVector<PIConnection *> PIConnection::allConnections() {
|
||||
return _connections;
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIIODevice * > PIConnection::allDevices() {
|
||||
PIVector<PIIODevice *> PIConnection::allDevices() {
|
||||
return __device_pool__->boundedDevices();
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::setFakeMode(bool yes) {
|
||||
bool ret = isFakeMode();
|
||||
bool ret = isFakeMode();
|
||||
__device_pool__->fake = yes;
|
||||
return ret;
|
||||
}
|
||||
@@ -951,8 +949,6 @@ bool PIConnection::isFakeMode() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIConnection::DevicePool::DevicePool(): PIThread(false, 10) {
|
||||
setName("PIConnection::DevicePool");
|
||||
needLockRun(true);
|
||||
@@ -960,8 +956,7 @@ PIConnection::DevicePool::DevicePool(): PIThread(false, 10) {
|
||||
}
|
||||
|
||||
|
||||
PIConnection::DevicePool::~DevicePool() {
|
||||
}
|
||||
PIConnection::DevicePool::~DevicePool() {}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::init() {
|
||||
@@ -971,14 +966,14 @@ void PIConnection::DevicePool::init() {
|
||||
|
||||
PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode, bool start) {
|
||||
DeviceData * dd = devices[fp];
|
||||
int pmode = 0;
|
||||
int pmode = 0;
|
||||
bool need_start = false;
|
||||
if (!dd) {
|
||||
dd = new DeviceData();
|
||||
dd = new DeviceData();
|
||||
devices[fp] = dd;
|
||||
}
|
||||
if (!dd->dev) {
|
||||
//piCout << "new device" << fp;
|
||||
// piCout << "new device" << fp;
|
||||
dd->dev = PIIODevice::createFromFullPath(fp);
|
||||
if (!dd->dev) {
|
||||
piCoutObj << "Error: can`t create device \"" << fp << "\"!"; //:" << errorString();
|
||||
@@ -1040,7 +1035,7 @@ void PIConnection::DevicePool::unboundConnection(PIConnection * parent) {
|
||||
i.value()->listeners.removeAll(parent);
|
||||
if (i.value()->listeners.isEmpty()) rem << i.key();
|
||||
}
|
||||
for (const PIString & i : rem) {
|
||||
for (const PIString & i: rem) {
|
||||
DeviceData * dd = devices.value(i, nullptr);
|
||||
if (!dd) continue;
|
||||
delete dd;
|
||||
@@ -1067,8 +1062,8 @@ PIConnection::DevicePool::DeviceData * PIConnection::DevicePool::deviceData(PIIO
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIConnection * > PIConnection::DevicePool::boundedConnections() const {
|
||||
PIVector<PIConnection * > ret;
|
||||
PIVector<PIConnection *> PIConnection::DevicePool::boundedConnections() const {
|
||||
PIVector<PIConnection *> ret;
|
||||
auto it = devices.makeIterator();
|
||||
while (it.next()) {
|
||||
if (!it.value()) continue;
|
||||
@@ -1086,8 +1081,8 @@ PIVector<PIConnection * > PIConnection::DevicePool::boundedConnections() const {
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIIODevice * > PIConnection::DevicePool::boundedDevices() const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
PIVector<PIIODevice *> PIConnection::DevicePool::boundedDevices() const {
|
||||
PIVector<PIIODevice *> ret;
|
||||
auto it = devices.makeIterator();
|
||||
while (it.next()) {
|
||||
if (!it.value()) continue;
|
||||
@@ -1098,13 +1093,13 @@ PIVector< PIIODevice * > PIConnection::DevicePool::boundedDevices() const {
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::DevicePool::boundedDevices(const PIConnection * parent) const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
PIVector<PIIODevice *> PIConnection::DevicePool::boundedDevices(const PIConnection * parent) const {
|
||||
PIVector<PIIODevice *> ret;
|
||||
auto it = devices.makeIterator();
|
||||
while (it.next()) {
|
||||
if (!it.value()) continue;
|
||||
if (!it.value()->dev) continue;
|
||||
if (it.value()->listeners.contains(const_cast<PIConnection*>(parent))) {
|
||||
if (it.value()->listeners.contains(const_cast<PIConnection *>(parent))) {
|
||||
ret << it.value()->dev;
|
||||
}
|
||||
}
|
||||
@@ -1116,8 +1111,7 @@ PIConnection::DevicePool::DeviceData::~DeviceData() {
|
||||
if (rthread) {
|
||||
rthread->stop();
|
||||
if (dev) dev->interrupt();
|
||||
if (!rthread->waitForFinish(1000))
|
||||
rthread->terminate();
|
||||
if (!rthread->waitForFinish(1000)) rthread->terminate();
|
||||
delete rthread;
|
||||
rthread = nullptr;
|
||||
}
|
||||
@@ -1130,8 +1124,8 @@ PIConnection::DevicePool::DeviceData::~DeviceData() {
|
||||
|
||||
|
||||
void PIConnection::DevicePool::run() {
|
||||
PIVector<PIConnection * > conns(PIConnection::allConnections());
|
||||
for (PIConnection * c : conns) {
|
||||
PIVector<PIConnection *> conns(PIConnection::allConnections());
|
||||
for (PIConnection * c: conns) {
|
||||
for (auto d = c->diags_.begin(); d != c->diags_.end(); d++) {
|
||||
if (!d.value()) continue;
|
||||
d.value()->tick(0, 1);
|
||||
@@ -1141,7 +1135,7 @@ void PIConnection::DevicePool::run() {
|
||||
|
||||
|
||||
void __DevicePool_threadReadDP(void * ddp) {
|
||||
PIConnection::DevicePool::DeviceData * dd((PIConnection::DevicePool::DeviceData * )ddp);
|
||||
PIConnection::DevicePool::DeviceData * dd((PIConnection::DevicePool::DeviceData *)ddp);
|
||||
PIIODevice * dev = dd->dev;
|
||||
if (!dev) {
|
||||
piMSleep(100);
|
||||
@@ -1152,8 +1146,7 @@ void __DevicePool_threadReadDP(void * ddp) {
|
||||
PITimeMeasurer tm;
|
||||
int timeout = dev->reopenTimeout();
|
||||
while (tm.elapsed_m() < timeout) {
|
||||
if (dd->rthread->isStopping())
|
||||
return;
|
||||
if (dd->rthread->isStopping()) return;
|
||||
piMSleep(50);
|
||||
}
|
||||
}
|
||||
@@ -1166,14 +1159,14 @@ void __DevicePool_threadReadDP(void * ddp) {
|
||||
}
|
||||
dev->threadedRead(ba.data(), ba.size_s());
|
||||
dev->threadedReadEvent(ba.data(), ba.size_s());
|
||||
//piCout << "Readed from" << dd->dev->path() << Hex << ba;
|
||||
// piCout << "Readed from" << dd->dev->path() << Hex << ba;
|
||||
__device_pool__->deviceReaded(dd, ba);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::deviceReaded(PIConnection::DevicePool::DeviceData * dd, const PIByteArray & data) {
|
||||
PIString from = dd->dev->property("__fullPath__").toString();
|
||||
for (PIConnection * ld : dd->listeners) {
|
||||
for (PIConnection * ld: dd->listeners) {
|
||||
ld->rawReceived(dd->dev, from, data);
|
||||
}
|
||||
}
|
||||
@@ -1182,14 +1175,14 @@ void PIConnection::DevicePool::deviceReaded(PIConnection::DevicePool::DeviceData
|
||||
void PIConnection::rawReceived(PIIODevice * dev, const PIString & from, const PIByteArray & data) {
|
||||
dataReceived(from, data);
|
||||
dataReceivedEvent(from, data);
|
||||
PIVector<PIPacketExtractor * > be(bounded_extractors.value(dev));
|
||||
//piCout << be;
|
||||
for (PIPacketExtractor * i : be) {
|
||||
PIVector<PIPacketExtractor *> be(bounded_extractors.value(dev));
|
||||
// piCout << be;
|
||||
for (PIPacketExtractor * i: be) {
|
||||
i->threadedRead(data.data(), data.size_s());
|
||||
}
|
||||
PIVector<PIIODevice * > chd(channels_.value(dev));
|
||||
for (PIIODevice * d : chd) {
|
||||
int ret = d->write(data);
|
||||
PIVector<PIIODevice *> chd(channels_.value(dev));
|
||||
for (PIIODevice * d: chd) {
|
||||
int ret = d->write(data);
|
||||
PIDiagnostics * diag = diags_.value(d, nullptr);
|
||||
if (diag && ret > 0) diag->sended(ret);
|
||||
}
|
||||
@@ -1198,7 +1191,6 @@ void PIConnection::rawReceived(PIIODevice * dev, const PIString & from, const PI
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIByteArray PIConnection::senderData(const PIString & sender_name) {
|
||||
return PIByteArray();
|
||||
}
|
||||
@@ -1212,31 +1204,29 @@ PIConnection::Extractor::~Extractor() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_), int_(0.f) {
|
||||
setName("__S__.PIConnection.Sender");
|
||||
needLockRun(true);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::Sender::tick(void * , int) {
|
||||
void PIConnection::Sender::tick(void *, int) {
|
||||
if (!parent) return;
|
||||
PIByteArray data;
|
||||
if (!sdata.isEmpty()) data = sdata;
|
||||
else data = parent->senderData(name());
|
||||
if (!sdata.isEmpty())
|
||||
data = sdata;
|
||||
else
|
||||
data = parent->senderData(name());
|
||||
if (data.isEmpty()) return;
|
||||
//piCoutObj << "write"<<data.size()<<"bytes to"<<devices.size()<<"devices";
|
||||
for (PIIODevice * d : devices) {
|
||||
int ret = d->write(data);
|
||||
// piCoutObj << "write"<<data.size()<<"bytes to"<<devices.size()<<"devices";
|
||||
for (PIIODevice * d: devices) {
|
||||
int ret = d->write(data);
|
||||
PIDiagnostics * diag = parent->diags_.value(d, nullptr);
|
||||
if (diag && ret > 0) diag->sended(ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
|
||||
if (!pe) return;
|
||||
channels_.remove(pe);
|
||||
@@ -1245,9 +1235,9 @@ void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
|
||||
it.value().removeAll(pe);
|
||||
}
|
||||
bounded_extractors.remove(pe);
|
||||
PIVector<PIIODevice * > k = bounded_extractors.keys();
|
||||
for (PIIODevice * i : k) {
|
||||
PIVector<PIPacketExtractor * > & be(bounded_extractors[i]);
|
||||
PIVector<PIIODevice *> k = bounded_extractors.keys();
|
||||
for (PIIODevice * i: k) {
|
||||
PIVector<PIPacketExtractor *> & be(bounded_extractors[i]);
|
||||
be.removeAll(pe);
|
||||
if (be.isEmpty()) bounded_extractors.remove(i);
|
||||
}
|
||||
@@ -1260,18 +1250,18 @@ void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
|
||||
|
||||
|
||||
void PIConnection::packetExtractorReceived(const uchar * data, int size) {
|
||||
PIString from(emitter()? emitter()->name() : PIString());
|
||||
PIIODevice * cd = (PIIODevice * )emitter();
|
||||
// piCout << "packetExtractorReceived" << from << cd;
|
||||
PIString from(emitter() ? emitter()->name() : PIString());
|
||||
PIIODevice * cd = (PIIODevice *)emitter();
|
||||
// piCout << "packetExtractorReceived" << from << cd;
|
||||
if (cd) {
|
||||
PIVector<PIPacketExtractor * > be(bounded_extractors.value(cd));
|
||||
//piCout << be << (void*)data << size;
|
||||
for (PIPacketExtractor * i : be) {
|
||||
PIVector<PIPacketExtractor *> be(bounded_extractors.value(cd));
|
||||
// piCout << be << (void*)data << size;
|
||||
for (PIPacketExtractor * i: be) {
|
||||
i->threadedRead(data, size);
|
||||
}
|
||||
PIVector<PIIODevice * > chd(channels_.value(cd));
|
||||
for (PIIODevice * d : chd) {
|
||||
int ret = d->write(data, size);
|
||||
PIVector<PIIODevice *> chd(channels_.value(cd));
|
||||
for (PIIODevice * d: chd) {
|
||||
int ret = d->write(data, size);
|
||||
PIDiagnostics * diag = diags_.value(d);
|
||||
if (diag) diag->sended(ret);
|
||||
}
|
||||
@@ -1284,17 +1274,16 @@ void PIConnection::packetExtractorReceived(const uchar * data, int size) {
|
||||
|
||||
|
||||
void PIConnection::diagQualityChanged(PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality) {
|
||||
qualityChanged(diags_.key((PIDiagnostics*)emitter()), new_quality, old_quality);
|
||||
qualityChanged(diags_.key((PIDiagnostics *)emitter()), new_quality, old_quality);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIConnection::DevicePool * __device_pool__;
|
||||
|
||||
bool __DevicePoolContainer__::inited_(false);
|
||||
|
||||
__DevicePoolContainer__::__DevicePoolContainer__() {
|
||||
if (inited_) return;
|
||||
inited_ = true;
|
||||
inited_ = true;
|
||||
__device_pool__ = new PIConnection::DevicePool();
|
||||
}
|
||||
|
||||
@@ -6,171 +6,177 @@
|
||||
* \~russian Составное устройство ввода/вывода
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
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 PICONNECTION_H
|
||||
#define PICONNECTION_H
|
||||
|
||||
#include "pipacketextractor.h"
|
||||
#include "pidiagnostics.h"
|
||||
#include "pipacketextractor.h"
|
||||
|
||||
class PIConfig;
|
||||
|
||||
class PIP_EXPORT PIConnection: public PIObject
|
||||
{
|
||||
class PIP_EXPORT PIConnection: public PIObject {
|
||||
PIOBJECT_SUBCLASS(PIConnection, PIObject);
|
||||
|
||||
public:
|
||||
//! Constructs connection with name "name", or with default name = "connection"
|
||||
PIConnection(const PIString & name = PIStringAscii("connection"));
|
||||
|
||||
|
||||
//! Constructs connection and configure it from config file "config" from section "name"
|
||||
PIConnection(const PIString & config, const PIString & name);
|
||||
|
||||
|
||||
//! Constructs connection and configure it from config content "string" from section "name"
|
||||
PIConnection(PIString * string, const PIString & name);
|
||||
|
||||
~PIConnection();
|
||||
|
||||
|
||||
/*! \brief Configure connection from config file "config" from section "name". Returns if configuration was successful
|
||||
* \details \b Warning: all devices, filters and channels removed before configure! */
|
||||
bool configureFromConfig(const PIString & config, const PIString & name = PIStringAscii("connection"));
|
||||
|
||||
|
||||
/*! \brief Configure connection from config content "string" from section "name". Returns if configuration was successful
|
||||
* \details \b Warning: all devices, filters and channels removed before configure! */
|
||||
bool configureFromString(PIString * string, const PIString & name = PIStringAscii("connection"));
|
||||
|
||||
|
||||
//! Returns config file section of current connection configuration
|
||||
PIString makeConfig() const;
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief Add device with full path "full_path", open mode "mode" to Device pool and connection
|
||||
* \details Returns pointer to device or null if device can not be created. If "start" is true,
|
||||
* read thread is started immediately. Else, you can start read thread with functions \a startThreadedRead()
|
||||
* or \a startAllThreadedReads(). By default, read thread doesn`t start */
|
||||
PIIODevice * addDevice(const PIString & full_path, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = false);
|
||||
|
||||
|
||||
void setDeviceName(PIIODevice * dev, const PIString & name);
|
||||
|
||||
|
||||
PIStringList deviceNames(const PIIODevice * dev) const;
|
||||
|
||||
|
||||
/*! \brief Remove device with full path "full_path" from connection
|
||||
* \details Returns if device was removed. If there is no connection bounded to this device,
|
||||
* it will be removed from Device pool */
|
||||
bool removeDevice(const PIString & full_path);
|
||||
|
||||
|
||||
/*! \brief Remove all device from connection
|
||||
* \details If there is no connection bounded to there devices, they removed from Device pool */
|
||||
void removeAllDevices();
|
||||
|
||||
|
||||
//! Returns device with full path "full_path" or null if there is no such device
|
||||
PIIODevice * deviceByFullPath(const PIString & full_path) const;
|
||||
|
||||
|
||||
//! Returns device with name "name" or null if there is no such device
|
||||
PIIODevice * deviceByName(const PIString & name) const;
|
||||
|
||||
|
||||
//! Returns all devices bounded to this connection
|
||||
PIVector<PIIODevice * > boundedDevices() const;
|
||||
|
||||
PIVector<PIIODevice *> boundedDevices() const;
|
||||
|
||||
/*! \brief Add filter with name "name" to device with full path "full_path_name" or filter "full_path_name"
|
||||
* \details If there is no filter with name "name", connection create new with split mode "mode" and bound
|
||||
* to it device "full_path_name" or filter "full_path_name". If filter with name "name" already exists,
|
||||
* device "full_path_name" or filter "full_path_name" add to this filter.
|
||||
* This function returns PIPacketExtractor * assosiated with this filter
|
||||
* \n \b Attention! "mode" is altual olny if new filter was created! */
|
||||
PIPacketExtractor * addFilter(const PIString & name, const PIString & full_path_name, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None);
|
||||
|
||||
PIPacketExtractor *
|
||||
addFilter(const PIString & name, const PIString & full_path_name, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None);
|
||||
|
||||
//! Add filter with name "name" to device "dev"
|
||||
PIPacketExtractor * addFilter(const PIString & name, const PIIODevice * dev, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None) {return addFilter(name, devFPath(dev), mode);}
|
||||
PIPacketExtractor *
|
||||
addFilter(const PIString & name, const PIIODevice * dev, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None) {
|
||||
return addFilter(name, devFPath(dev), mode);
|
||||
}
|
||||
|
||||
//! Add filter with "filter" to device "dev"
|
||||
PIPacketExtractor * addFilter(PIPacketExtractor * filter, const PIString & full_path_name);
|
||||
|
||||
//! Add filter with "filter" to device "dev"
|
||||
PIPacketExtractor * addFilter(PIPacketExtractor * filter, const PIIODevice * dev) {return addFilter(filter, devFPath(dev));}
|
||||
|
||||
PIPacketExtractor * addFilter(PIPacketExtractor * filter, const PIIODevice * dev) { return addFilter(filter, devFPath(dev)); }
|
||||
|
||||
/*! \brief Remove from filter with name "name" device with full path "full_path_name" or filter "full_path_name"
|
||||
* \details If there is no devices bounded to this filter, it will be removed. Returns if device was removed */
|
||||
bool removeFilter(const PIString & name, const PIString & full_path_name);
|
||||
|
||||
|
||||
//! Remove from filter with name "name" device or filter "dev"
|
||||
bool removeFilter(const PIString & name, const PIIODevice * dev);
|
||||
|
||||
|
||||
//! Remove filter with name "name". Returns if filter was removed
|
||||
bool removeFilter(const PIString & name);
|
||||
|
||||
|
||||
//! Remove all filters from connection
|
||||
void removeAllFilters();
|
||||
|
||||
|
||||
//! Returns all filters of connection
|
||||
PIVector<PIPacketExtractor * > filters() const;
|
||||
|
||||
PIVector<PIPacketExtractor *> filters() const;
|
||||
|
||||
//! Returns all filter names of connection
|
||||
PIStringList filterNames() const;
|
||||
|
||||
|
||||
//! Returns PIPacketExtractor * assosiated with filter "name" or null if there is no such filter
|
||||
PIPacketExtractor * filter(const PIString & name) const;
|
||||
|
||||
|
||||
//! Returns all devices bounded to filter "name"
|
||||
PIVector<PIIODevice * > filterBoundedDevices(const PIString & name) const;
|
||||
|
||||
PIVector<PIIODevice *> filterBoundedDevices(const PIString & name) const;
|
||||
|
||||
/*! \brief Add to connection channel from "name_from" to "name_to"
|
||||
* \details "name_from" and "name_to" can be full pathes of devices or device names or filter names.
|
||||
* Returns \b false if there if no such device or filter, else create channel and returns \b true */
|
||||
bool addChannel(const PIString & name_from, const PIString & name_to);
|
||||
|
||||
|
||||
//! Add to connection channel from "name_from" to "dev_to"
|
||||
bool addChannel(const PIString & name_from, const PIIODevice * dev_to) {return addChannel(name_from, devFPath(dev_to));}
|
||||
|
||||
bool addChannel(const PIString & name_from, const PIIODevice * dev_to) { return addChannel(name_from, devFPath(dev_to)); }
|
||||
|
||||
//! Add to connection channel from "dev_from" to "name_to"
|
||||
bool addChannel(const PIIODevice * dev_from, const PIString & name_to) {return addChannel(devFPath(dev_from), name_to);}
|
||||
|
||||
bool addChannel(const PIIODevice * dev_from, const PIString & name_to) { return addChannel(devFPath(dev_from), name_to); }
|
||||
|
||||
//! Add to connection channel from "dev_from" to "dev_to"
|
||||
bool addChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) {return addChannel(devFPath(dev_from), devFPath(dev_to));}
|
||||
|
||||
bool addChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) { return addChannel(devFPath(dev_from), devFPath(dev_to)); }
|
||||
|
||||
/*! \brief Remove from connection channel from "name_from" to "name_to"
|
||||
* \details "name_from" and "name_to" can be full pathes of devices or filter names.
|
||||
* Returns \b false if there if no such device or filter, else remove channel and returns \b true */
|
||||
bool removeChannel(const PIString & name_from, const PIString & name_to);
|
||||
|
||||
|
||||
//! Remove from connection channel from "name_from" to "dev_to"
|
||||
bool removeChannel(const PIString & name_from, const PIIODevice * dev_to) {return removeChannel(name_from, devFPath(dev_to));}
|
||||
|
||||
bool removeChannel(const PIString & name_from, const PIIODevice * dev_to) { return removeChannel(name_from, devFPath(dev_to)); }
|
||||
|
||||
//! Remove from connection channel from "dev_from" to "name_to"
|
||||
bool removeChannel(const PIIODevice * dev_from, const PIString & name_to) {return removeChannel(devFPath(dev_from), name_to);}
|
||||
|
||||
bool removeChannel(const PIIODevice * dev_from, const PIString & name_to) { return removeChannel(devFPath(dev_from), name_to); }
|
||||
|
||||
//! Remove from connection channel from "dev_from" to "dev_to"
|
||||
bool removeChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) {return removeChannel(devFPath(dev_from), devFPath(dev_to));}
|
||||
|
||||
bool removeChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) {
|
||||
return removeChannel(devFPath(dev_from), devFPath(dev_to));
|
||||
}
|
||||
|
||||
/*! \brief Remove from connection all channels from "name_from"
|
||||
* \details "name_from" can be full path of device or filter name.
|
||||
* Returns \b false if there if no such device or filter, else remove channels and returns \b true */
|
||||
bool removeChannel(const PIString & name_from);
|
||||
|
||||
|
||||
//! Remove from connection all channels from "dev_from"
|
||||
bool removeChannel(const PIIODevice * dev_from) {return removeChannel(devFPath(dev_from));}
|
||||
|
||||
bool removeChannel(const PIIODevice * dev_from) { return removeChannel(devFPath(dev_from)); }
|
||||
|
||||
//! Remove from connection all channels
|
||||
void removeAllChannels();
|
||||
|
||||
|
||||
//! Returns all channels of this connection as full pathes or filter names pair array (from, to)
|
||||
PIVector<PIPair<PIString, PIString> > channels() const;
|
||||
|
||||
PIVector<PIPair<PIString, PIString>> channels() const;
|
||||
|
||||
/*! \brief Add to connection sender with name "name" device with full path "full_path"
|
||||
* \details If there is no sender with name "name", connection create new, bound
|
||||
* to it device "full_path_name" and start sender timer with frequency "frequency".
|
||||
@@ -179,125 +185,139 @@ public:
|
||||
* functions \a startSender()
|
||||
* \n \b Attention! "frequency" is actual olny if new sender was created! */
|
||||
void addSender(const PIString & name, const PIString & full_path_name, float frequency, bool start = false);
|
||||
|
||||
|
||||
//! Add to connection sender with name "name" device "dev"
|
||||
void addSender(const PIString & name, const PIIODevice * dev, float frequency, bool start = false) {addSender(name, devFPath(dev), frequency, start);}
|
||||
|
||||
void addSender(const PIString & name, const PIIODevice * dev, float frequency, bool start = false) {
|
||||
addSender(name, devFPath(dev), frequency, start);
|
||||
}
|
||||
|
||||
/*! \brief Remove from sender with name "name" device with full path "full_path_name"
|
||||
* \details If there is no devices bounded to this sender, it will be removed. Returns if sender was removed */
|
||||
bool removeSender(const PIString & name, const PIString & full_path_name);
|
||||
|
||||
|
||||
//! Remove from sender with name "name" device "dev"
|
||||
bool removeSender(const PIString & name, const PIIODevice * dev) {return removeSender(name, devFPath(dev));}
|
||||
|
||||
bool removeSender(const PIString & name, const PIIODevice * dev) { return removeSender(name, devFPath(dev)); }
|
||||
|
||||
//! Remove sender with name "name", returns if sender was removed
|
||||
bool removeSender(const PIString & name);
|
||||
|
||||
|
||||
//! Set sender "name" fixed send data "data", returns if sender exists
|
||||
bool setSenderFixedData(const PIString & name, const PIByteArray & data);
|
||||
|
||||
|
||||
//! Remove sender "name" fixed send data, returns if sender exists
|
||||
bool clearSenderFixedData(const PIString & name);
|
||||
|
||||
|
||||
//! Returns sender "name" fixed send data
|
||||
PIByteArray senderFixedData(const PIString & name) const;
|
||||
|
||||
|
||||
//! Returns sender "name" timer frequency, -1 if there is no such sender, or 0 if sender is not started yet
|
||||
float senderFrequency(const PIString & name) const;
|
||||
|
||||
|
||||
//! Remove from connection all senders
|
||||
void removeAllSenders();
|
||||
|
||||
|
||||
//! Start read thread of device with full path "full_path"
|
||||
void startThreadedRead(const PIString & full_path_name);
|
||||
|
||||
|
||||
//! Start read thread of device "dev"
|
||||
void startThreadedRead(const PIIODevice * dev) {startThreadedRead(devFPath(dev));}
|
||||
|
||||
void startThreadedRead(const PIIODevice * dev) { startThreadedRead(devFPath(dev)); }
|
||||
|
||||
//! Start read threads of all Device pool device
|
||||
void startAllThreadedReads();
|
||||
|
||||
|
||||
//! Start sender "name" timer
|
||||
void startSender(const PIString & name);
|
||||
|
||||
|
||||
//! Start all senders timers
|
||||
void startAllSenders();
|
||||
|
||||
|
||||
//! Start all read threads and senders
|
||||
void start() {startAllThreadedReads(); startAllSenders();}
|
||||
|
||||
void start() {
|
||||
startAllThreadedReads();
|
||||
startAllSenders();
|
||||
}
|
||||
|
||||
//! Stop read thread of device with full path "full_path"
|
||||
void stopThreadedRead(const PIString & full_path_name);
|
||||
|
||||
|
||||
//! Stop read thread of device "dev"
|
||||
void stopThreadedRead(const PIIODevice * dev) {stopThreadedRead(devFPath(dev));}
|
||||
|
||||
void stopThreadedRead(const PIIODevice * dev) { stopThreadedRead(devFPath(dev)); }
|
||||
|
||||
//! Stop read threads of all Device pool device
|
||||
void stopAllThreadedReads();
|
||||
|
||||
|
||||
//! Stop sender "name" timer
|
||||
void stopSender(const PIString & name);
|
||||
|
||||
|
||||
//! Stop all senders timers
|
||||
void stopAllSenders();
|
||||
|
||||
|
||||
//! Stop all read threads and senders
|
||||
void stop() {stopAllThreadedReads(); stopAllSenders();}
|
||||
|
||||
void stop() {
|
||||
stopAllThreadedReads();
|
||||
stopAllSenders();
|
||||
}
|
||||
|
||||
//! Stop connection and remove all devices
|
||||
void destroy() {stop(); removeAllDevices();}
|
||||
|
||||
void destroy() {
|
||||
stop();
|
||||
removeAllDevices();
|
||||
}
|
||||
|
||||
//! Returns if there are no devices in this connection
|
||||
bool isEmpty() const {return device_modes.isEmpty();}
|
||||
|
||||
|
||||
bool isEmpty() const { return device_modes.isEmpty(); }
|
||||
|
||||
|
||||
//! Returns PIDiagnostics * assosiated with device with full path "full_path_name", name "full_path_name" or filter "full_path_name"
|
||||
PIDiagnostics * diagnostic(const PIString & full_path_name) const;
|
||||
|
||||
|
||||
//! Returns PIDiagnostics * assosiated with device or filter "dev"
|
||||
PIDiagnostics * diagnostic(const PIIODevice * dev) const {return diags_.value(const_cast<PIIODevice * >(dev), 0);}
|
||||
|
||||
PIDiagnostics * diagnostic(const PIIODevice * dev) const { return diags_.value(const_cast<PIIODevice *>(dev), 0); }
|
||||
|
||||
//! Write data "data" to device with full path "full_path" and returns result of \a write() function of device
|
||||
int writeByFullPath(const PIString & full_path, const PIByteArray & data);
|
||||
|
||||
|
||||
//! Write data "data" to device with name "name" and returns result of \a write() function of device
|
||||
int writeByName(const PIString & name, const PIByteArray & data);
|
||||
|
||||
|
||||
//! Write data "data" to device "dev" and returns result of \a write() function of device
|
||||
int write(PIIODevice * dev, const PIByteArray & data);
|
||||
|
||||
|
||||
//! Returns all connections in application
|
||||
static PIVector<PIConnection * > allConnections();
|
||||
|
||||
static PIVector<PIConnection *> allConnections();
|
||||
|
||||
//! Returns all devices in Device pool
|
||||
static PIVector<PIIODevice * > allDevices();
|
||||
|
||||
static PIVector<PIIODevice *> allDevices();
|
||||
|
||||
//! Set Device pool fake mode to \"yes\" and returns previous mode
|
||||
static bool setFakeMode(bool yes);
|
||||
|
||||
|
||||
//! Returns if Device pool works in fake mode
|
||||
static bool isFakeMode();
|
||||
|
||||
|
||||
class PIP_EXPORT DevicePool: public PIThread {
|
||||
PIOBJECT_SUBCLASS(DevicePool, PIThread);
|
||||
friend void __DevicePool_threadReadDP(void * ddp);
|
||||
friend class PIConnection;
|
||||
|
||||
protected:
|
||||
struct DeviceData;
|
||||
|
||||
public:
|
||||
DevicePool();
|
||||
~DevicePool();
|
||||
|
||||
|
||||
void init();
|
||||
PIIODevice * addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = true);
|
||||
PIIODevice *
|
||||
addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = true);
|
||||
bool removeDevice(PIConnection * parent, const PIString & fp);
|
||||
void unboundConnection(PIConnection * parent);
|
||||
PIIODevice * device(const PIString & fp) const;
|
||||
DeviceData * deviceData(PIIODevice * d) const;
|
||||
PIVector<PIConnection * > boundedConnections() const;
|
||||
PIVector<PIIODevice * > boundedDevices() const;
|
||||
PIVector<PIIODevice * > boundedDevices(const PIConnection * parent) const;
|
||||
|
||||
PIVector<PIConnection *> boundedConnections() const;
|
||||
PIVector<PIIODevice *> boundedDevices() const;
|
||||
PIVector<PIIODevice *> boundedDevices(const PIConnection * parent) const;
|
||||
|
||||
protected:
|
||||
struct PIP_EXPORT DeviceData {
|
||||
DeviceData(): dev(0), rthread(0), started(false) {}
|
||||
@@ -305,85 +325,85 @@ public:
|
||||
PIIODevice * dev;
|
||||
PIThread * rthread;
|
||||
bool started;
|
||||
PIVector<PIConnection * > listeners;
|
||||
PIVector<PIConnection *> listeners;
|
||||
};
|
||||
|
||||
|
||||
void run() override;
|
||||
|
||||
|
||||
void deviceReaded(DeviceData * dd, const PIByteArray & data);
|
||||
|
||||
PIMap<PIString, DeviceData * > devices;
|
||||
|
||||
PIMap<PIString, DeviceData *> devices;
|
||||
bool fake;
|
||||
};
|
||||
|
||||
|
||||
EVENT2(dataReceivedEvent, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT2(packetReceivedEvent, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT3(qualityChanged, const PIIODevice * , dev, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality);
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
EVENT3(qualityChanged, const PIIODevice *, dev, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality);
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void dataReceivedEvent(const PIString & from, const PIByteArray & data)
|
||||
//! \brief Raise on data received from device with full path "from"
|
||||
|
||||
|
||||
//! \fn void packetReceivedEvent(const PIString & from, const PIByteArray & data)
|
||||
//! \brief Raise on packet received from filter with name "from"
|
||||
|
||||
|
||||
//! \fn void qualityChanged(const PIIODevice * device, PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality)
|
||||
//! \brief Raise on diagnostic quality of device "device" changed from "old_quality" to "new_quality"
|
||||
|
||||
//! \}
|
||||
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
//! Executes on data received from device with full path "from"
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data) {}
|
||||
|
||||
|
||||
//! Executes on packet received from filter with name "from"
|
||||
virtual void packetReceived(const PIString & from, const PIByteArray & data) {}
|
||||
|
||||
|
||||
//! You should returns data for sender "sender_name"
|
||||
virtual PIByteArray senderData(const PIString & sender_name);
|
||||
|
||||
|
||||
private:
|
||||
bool configure(PIConfig & conf, const PIString & name_);
|
||||
void rawReceived(PIIODevice * dev, const PIString & from, const PIByteArray & data);
|
||||
void unboundExtractor(PIPacketExtractor * pe);
|
||||
EVENT_HANDLER2(void, packetExtractorReceived, const uchar * , data, int, size);
|
||||
EVENT_HANDLER2(void, packetExtractorReceived, const uchar *, data, int, size);
|
||||
EVENT_HANDLER2(void, diagQualityChanged, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality);
|
||||
|
||||
|
||||
PIString devPath(const PIIODevice * d) const;
|
||||
PIString devFPath(const PIIODevice * d) const;
|
||||
PIIODevice * devByString(const PIString & s) const;
|
||||
|
||||
|
||||
struct PIP_EXPORT Extractor {
|
||||
Extractor(): extractor(0) {}
|
||||
~Extractor();
|
||||
PIPacketExtractor * extractor;
|
||||
PIVector<PIIODevice * > devices;
|
||||
PIVector<PIIODevice *> devices;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT Sender: public PITimer {
|
||||
PIOBJECT_SUBCLASS(Sender, PIObject);
|
||||
|
||||
public:
|
||||
Sender(PIConnection * parent_ = 0);
|
||||
~Sender() {stop();}
|
||||
~Sender() { stop(); }
|
||||
PIConnection * parent;
|
||||
PIVector<PIIODevice * > devices;
|
||||
PIVector<PIIODevice *> devices;
|
||||
PIByteArray sdata;
|
||||
float int_;
|
||||
void tick(void * , int) override;
|
||||
void tick(void *, int) override;
|
||||
};
|
||||
|
||||
PIMap<PIString, Extractor * > extractors;
|
||||
PIMap<PIString, Sender * > senders;
|
||||
PIMap<PIString, PIIODevice * > device_names;
|
||||
PIMap<PIIODevice * , PIIODevice::DeviceMode> device_modes;
|
||||
PIMap<PIIODevice * , PIVector<PIPacketExtractor * > > bounded_extractors;
|
||||
PIMap<PIIODevice * , PIVector<PIIODevice * > > channels_;
|
||||
PIMap<PIIODevice * , PIDiagnostics * > diags_;
|
||||
|
||||
static PIVector<PIConnection * > _connections;
|
||||
|
||||
PIMap<PIString, Extractor *> extractors;
|
||||
PIMap<PIString, Sender *> senders;
|
||||
PIMap<PIString, PIIODevice *> device_names;
|
||||
PIMap<PIIODevice *, PIIODevice::DeviceMode> device_modes;
|
||||
PIMap<PIIODevice *, PIVector<PIPacketExtractor *>> bounded_extractors;
|
||||
PIMap<PIIODevice *, PIVector<PIIODevice *>> channels_;
|
||||
PIMap<PIIODevice *, PIDiagnostics *> diags_;
|
||||
|
||||
static PIVector<PIConnection *> _connections;
|
||||
};
|
||||
|
||||
void __DevicePool_threadReadDP(void * ddp);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive PIByteArray via PIBaseTransfer
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive PIByteArray via PIBaseTransfer
|
||||
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 "pidatatransfer.h"
|
||||
@@ -39,10 +39,8 @@ void PIDataTransfer::beginReceive() {
|
||||
}
|
||||
|
||||
|
||||
bool PIDataTransfer::send(const PIByteArray& ba) {
|
||||
bool PIDataTransfer::send(const PIByteArray & ba) {
|
||||
data_ = ba;
|
||||
buildSession(PIVector<Part>() << Part(0, data_.size()));
|
||||
return send_process();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Класс для отправки и приема PIByteArray с помощью \a PIBaseTransfer
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive PIByteArray via PIBaseTransfer
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive PIByteArray via PIBaseTransfer
|
||||
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 PIDATATRANSFER_H
|
||||
@@ -29,16 +29,16 @@
|
||||
#include "pibasetransfer.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIDataTransfer: public PIBaseTransfer
|
||||
{
|
||||
class PIP_EXPORT PIDataTransfer: public PIBaseTransfer {
|
||||
PIOBJECT_SUBCLASS(PIDataTransfer, PIBaseTransfer);
|
||||
|
||||
public:
|
||||
PIDataTransfer() {;}
|
||||
~PIDataTransfer() {;}
|
||||
|
||||
bool send(const PIByteArray &ba);
|
||||
const PIByteArray & data() {return data_;}
|
||||
|
||||
PIDataTransfer() { ; }
|
||||
~PIDataTransfer() { ; }
|
||||
|
||||
bool send(const PIByteArray & ba);
|
||||
const PIByteArray & data() { return data_; }
|
||||
|
||||
private:
|
||||
PIByteArray buildPacket(Part p) override;
|
||||
void receivePart(PIBaseTransfer::Part fi, PIByteArray ba, PIByteArray pheader) override;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Speed and quality in/out diagnostics
|
||||
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Speed and quality in/out diagnostics
|
||||
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 "pidiagnostics.h"
|
||||
@@ -39,38 +39,36 @@
|
||||
|
||||
PIDiagnostics::State::State() {
|
||||
immediate_freq = integral_freq = 0.f;
|
||||
received_packets_per_sec = 0ull;
|
||||
received_packets = 0ull;
|
||||
received_packets_wrong = 0ull;
|
||||
received_bytes_per_sec = 0ull;
|
||||
received_bytes = 0ull;
|
||||
received_bytes_wrong = 0ull;
|
||||
sended_packets_per_sec = 0ull;
|
||||
sended_packets = 0ull;
|
||||
sended_bytes_per_sec = 0ull;
|
||||
sended_bytes = 0ull;
|
||||
received_packets_per_sec = 0ull;
|
||||
received_packets = 0ull;
|
||||
received_packets_wrong = 0ull;
|
||||
received_bytes_per_sec = 0ull;
|
||||
received_bytes = 0ull;
|
||||
received_bytes_wrong = 0ull;
|
||||
sended_packets_per_sec = 0ull;
|
||||
sended_packets = 0ull;
|
||||
sended_bytes_per_sec = 0ull;
|
||||
sended_bytes = 0ull;
|
||||
receive_speed = send_speed = PIString::readableSize(0) + "/s";
|
||||
quality = PIDiagnostics::Unknown;
|
||||
quality = PIDiagnostics::Unknown;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIDiagnostics::PIDiagnostics(bool start_): PITimer(/*PITimer::Pool*/) {
|
||||
disconn_ = 0.;
|
||||
//piCout << "PIDiagnostics construct";
|
||||
// piCout << "PIDiagnostics construct";
|
||||
setInterval(100);
|
||||
reset();
|
||||
setDisconnectTimeout(3.);
|
||||
changeDisconnectTimeout(3.);
|
||||
if (start_) PITimer::start(100);
|
||||
//piCout << "PIDiagnostics construct done";
|
||||
// piCout << "PIDiagnostics construct done";
|
||||
}
|
||||
|
||||
PIDiagnostics::~PIDiagnostics() {
|
||||
PITimer::stop();
|
||||
//piCout << "~PIDiagnostics start...";
|
||||
//piCout << "~PIDiagnostics done!";
|
||||
// piCout << "~PIDiagnostics start...";
|
||||
// piCout << "~PIDiagnostics done!";
|
||||
}
|
||||
|
||||
|
||||
@@ -151,49 +149,52 @@ void PIDiagnostics::sended(int size) {
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::tick(void * , int ) {
|
||||
void PIDiagnostics::tick(void *, int) {
|
||||
mutex_state.lock();
|
||||
//piCoutObj << "lock";
|
||||
// piCoutObj << "lock";
|
||||
int tcnt_recv = 0;
|
||||
int tcnt_send = 0;
|
||||
Entry send = calcHistory(history_send, tcnt_send);
|
||||
Entry recv = calcHistory(history_rec, tcnt_recv);
|
||||
float itr = disconn_ * (float(tcnt_recv) / history_rec.size());
|
||||
float its = disconn_ * (float(tcnt_send) / history_send.size());
|
||||
float hz = interval() / 1000.f;
|
||||
Entry send = calcHistory(history_send, tcnt_send);
|
||||
Entry recv = calcHistory(history_rec, tcnt_recv);
|
||||
float itr = disconn_ * (float(tcnt_recv) / history_rec.size());
|
||||
float its = disconn_ * (float(tcnt_send) / history_send.size());
|
||||
float hz = interval() / 1000.f;
|
||||
if (tcnt_recv == 0) {
|
||||
cur_state.integral_freq = cur_state.immediate_freq = 0;
|
||||
cur_state.received_packets_per_sec = cur_state.received_bytes_per_sec = 0;
|
||||
} else {
|
||||
cur_state.integral_freq = recv.cnt_ok / itr;
|
||||
cur_state.integral_freq = recv.cnt_ok / itr;
|
||||
cur_state.received_packets_per_sec = ullong(float(recv.cnt_ok) / itr);
|
||||
cur_state.received_bytes_per_sec = ullong(double(recv.bytes_ok) / itr);
|
||||
cur_state.immediate_freq = double(history_rec.front().cnt_ok) / hz;
|
||||
cur_state.received_bytes_per_sec = ullong(double(recv.bytes_ok) / itr);
|
||||
cur_state.immediate_freq = double(history_rec.front().cnt_ok) / hz;
|
||||
}
|
||||
if (tcnt_send == 0) {
|
||||
cur_state.sended_packets_per_sec = cur_state.sended_bytes_per_sec = 0;
|
||||
} else {
|
||||
cur_state.sended_packets_per_sec = ullong(float(send.cnt_ok) / its);
|
||||
cur_state.sended_bytes_per_sec = ullong(double(send.bytes_ok) / its);
|
||||
cur_state.sended_bytes_per_sec = ullong(double(send.bytes_ok) / its);
|
||||
}
|
||||
//piCoutObj << "tick" << recv.cnt_ok << send.cnt_ok;
|
||||
// piCoutObj << "tick" << recv.cnt_ok << send.cnt_ok;
|
||||
cur_state.receive_speed = PIString::readableSize(cur_state.received_bytes_per_sec) + "/s";
|
||||
cur_state.send_speed = PIString::readableSize(cur_state.sended_bytes_per_sec) + "/s";
|
||||
int arc = recv.cnt_ok + recv.cnt_fail;
|
||||
float good_percents = 0.f;
|
||||
cur_state.send_speed = PIString::readableSize(cur_state.sended_bytes_per_sec) + "/s";
|
||||
int arc = recv.cnt_ok + recv.cnt_fail;
|
||||
float good_percents = 0.f;
|
||||
if (arc > 0) good_percents = (float)recv.cnt_ok / arc * 100.f;
|
||||
PIDiagnostics::Quality diag;
|
||||
if (tcnt_recv == 0) {
|
||||
diag = PIDiagnostics::Unknown;
|
||||
} else {
|
||||
if (good_percents == 0.f) diag = PIDiagnostics::Failure;
|
||||
else if (good_percents <= 20.f) diag = PIDiagnostics::Bad;
|
||||
else if (good_percents > 20.f && good_percents <= 80.f) diag = PIDiagnostics::Average;
|
||||
else diag = PIDiagnostics::Good;
|
||||
|
||||
if (good_percents == 0.f)
|
||||
diag = PIDiagnostics::Failure;
|
||||
else if (good_percents <= 20.f)
|
||||
diag = PIDiagnostics::Bad;
|
||||
else if (good_percents > 20.f && good_percents <= 80.f)
|
||||
diag = PIDiagnostics::Average;
|
||||
else
|
||||
diag = PIDiagnostics::Good;
|
||||
}
|
||||
if ((tcnt_send + tcnt_recv) != 0) {
|
||||
// piCoutObj << tcnt_recv << tcnt_send;
|
||||
// piCoutObj << tcnt_recv << tcnt_send;
|
||||
history_rec.dequeue();
|
||||
history_send.dequeue();
|
||||
Entry e;
|
||||
@@ -206,7 +207,7 @@ void PIDiagnostics::tick(void * , int ) {
|
||||
cur_state.quality = diag;
|
||||
}
|
||||
mutex_state.unlock();
|
||||
//piCoutObj << "unlock";
|
||||
// piCoutObj << "unlock";
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +222,7 @@ PIDiagnostics::Entry PIDiagnostics::calcHistory(PIQueue<Entry> & hist, int & cnt
|
||||
if (!hist[i].empty) cnt++;
|
||||
}
|
||||
e.empty = false;
|
||||
// piCoutObj << hist.size() << cnt;
|
||||
// piCoutObj << hist.size() << cnt;
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -237,14 +238,13 @@ void PIDiagnostics::changeDisconnectTimeout(float disct) {
|
||||
disconn_ = piMaxf(disct, interval() / 1000.f);
|
||||
if (interval() > 0) {
|
||||
int hist_size = piClampi(int(disconn_ * 1000.f / float(interval())), 1, 65536);
|
||||
//piCoutObj << hist_size << interval();
|
||||
// piCoutObj << hist_size << interval();
|
||||
history_rec.resize(hist_size);
|
||||
history_send.resize(hist_size);
|
||||
} else {
|
||||
history_rec.resize(1);
|
||||
history_send.resize(1);
|
||||
}
|
||||
//piCoutObj << hist_size << disconn_ << interval();
|
||||
// piCoutObj << hist_size << disconn_ << interval();
|
||||
mutex_state.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,50 +5,50 @@
|
||||
* \~russian Диагностика качества связи
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Speed and quality in/out diagnostics
|
||||
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Speed and quality in/out diagnostics
|
||||
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 PIDIAGNOSTICS_H
|
||||
#define PIDIAGNOSTICS_H
|
||||
|
||||
#include "pitimer.h"
|
||||
#include "piqueue.h"
|
||||
#include "pitimer.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIDiagnostics: public PITimer
|
||||
{
|
||||
class PIP_EXPORT PIDiagnostics: public PITimer {
|
||||
PIOBJECT_SUBCLASS(PIDiagnostics, PITimer);
|
||||
friend class PIConnection;
|
||||
|
||||
public:
|
||||
NO_COPY_CLASS(PIDiagnostics);
|
||||
|
||||
|
||||
//! Constructs an empty diagnostics and if "start_" start it
|
||||
PIDiagnostics(bool start_ = true);
|
||||
|
||||
|
||||
virtual ~PIDiagnostics();
|
||||
|
||||
//! Connection quality
|
||||
enum Quality {
|
||||
Unknown /** Unknown, no one packet received yet */ = 1,
|
||||
Unknown /** Unknown, no one packet received yet */ = 1,
|
||||
Failure /** No connection, no one correct packet received for last period */ = 2,
|
||||
Bad /** Bad connection, correct packets received <= 20% */ = 3,
|
||||
Bad /** Bad connection, correct packets received <= 20% */ = 3,
|
||||
Average /** Average connection, correct packets received > 20% and <= 80% */ = 4,
|
||||
Good /** Good connection, correct packets received > 80% */ = 5
|
||||
Good /** Good connection, correct packets received > 80% */ = 5
|
||||
};
|
||||
|
||||
//! Information about current diagnostics state
|
||||
@@ -70,73 +70,85 @@ public:
|
||||
PIString send_speed;
|
||||
PIDiagnostics::Quality quality;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//! Returns current state
|
||||
PIDiagnostics::State state() const;
|
||||
|
||||
|
||||
//! Returns period of full disconnect in seconds and period of averaging frequency
|
||||
float disconnectTimeout() const {return disconn_;}
|
||||
|
||||
float disconnectTimeout() const { return disconn_; }
|
||||
|
||||
//! Returns period of full disconnect in seconds and period of averaging frequency
|
||||
void setDisconnectTimeout(float s) {setProperty("disconnectTimeout", s);}
|
||||
|
||||
void setDisconnectTimeout(float s) { setProperty("disconnectTimeout", s); }
|
||||
|
||||
//! Returns connection quality
|
||||
PIDiagnostics::Quality quality() const;
|
||||
|
||||
|
||||
//! Returns receive speed in format "n {B|kB|MB|GB|TB}/s"
|
||||
PIString receiveSpeed() const;
|
||||
|
||||
|
||||
//! Returns send speed in format "n {B|kB|MB|GB|TB}/s"
|
||||
PIString sendSpeed() const;
|
||||
|
||||
|
||||
EVENT_HANDLER0(void, start) {PITimer::start(100.); changeDisconnectTimeout(disconn_);}
|
||||
EVENT_HANDLER1(void, start, double, msecs) {if (msecs > 0.) {PITimer::start(msecs); changeDisconnectTimeout(disconn_);}}
|
||||
|
||||
|
||||
EVENT_HANDLER0(void, start) {
|
||||
PITimer::start(100.);
|
||||
changeDisconnectTimeout(disconn_);
|
||||
}
|
||||
EVENT_HANDLER1(void, start, double, msecs) {
|
||||
if (msecs > 0.) {
|
||||
PITimer::start(msecs);
|
||||
changeDisconnectTimeout(disconn_);
|
||||
}
|
||||
}
|
||||
EVENT_HANDLER0(void, reset);
|
||||
|
||||
EVENT_HANDLER1(void, received, int, size) {received(size, true);}
|
||||
|
||||
EVENT_HANDLER1(void, received, int, size) { received(size, true); }
|
||||
EVENT_HANDLER2(void, received, int, size, bool, correct);
|
||||
EVENT_HANDLER1(void, sended, int, size);
|
||||
|
||||
|
||||
EVENT2(qualityChanged, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void start(double msecs = 1000.)
|
||||
//! \brief Start diagnostics evaluations with period "msecs" milliseconds
|
||||
|
||||
|
||||
//! \fn void reset()
|
||||
//! \brief Reset diagnostics counters
|
||||
|
||||
|
||||
//! \fn void received(int size, bool correct = true)
|
||||
//! \brief Notify diagnostics about "correct" corected received packet
|
||||
|
||||
|
||||
//! \fn void sended(int size)
|
||||
//! \brief Notify diagnostics about sended packet
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void qualityChanged(PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality)
|
||||
//! \brief Raise on change receive quality from "old_quality" to "new_quality"
|
||||
|
||||
//! \}
|
||||
|
||||
//! \}
|
||||
|
||||
private:
|
||||
struct PIP_EXPORT Entry {
|
||||
Entry() {bytes_ok = bytes_fail = 0; cnt_ok = cnt_fail = 0; empty = true;}
|
||||
Entry() {
|
||||
bytes_ok = bytes_fail = 0;
|
||||
cnt_ok = cnt_fail = 0;
|
||||
empty = true;
|
||||
}
|
||||
ullong bytes_ok;
|
||||
ullong bytes_fail;
|
||||
uint cnt_ok;
|
||||
uint cnt_fail;
|
||||
bool empty;
|
||||
};
|
||||
friend bool operator ==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
|
||||
friend bool operator !=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
|
||||
friend bool operator <(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
|
||||
friend bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
|
||||
friend bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
|
||||
friend bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s);
|
||||
|
||||
void tick(void *, int) override;
|
||||
Entry calcHistory(PIQueue<Entry> & hist, int & cnt);
|
||||
@@ -147,17 +159,17 @@ private:
|
||||
float disconn_;
|
||||
State cur_state;
|
||||
mutable PIMutex mutex_state;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator ==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) {
|
||||
return f.bytes_ok == s.bytes_ok &&
|
||||
f.bytes_fail == s.bytes_fail &&
|
||||
f.cnt_ok == s.cnt_ok &&
|
||||
f.cnt_fail == s.cnt_fail &&
|
||||
f.empty == s.empty;
|
||||
inline bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) {
|
||||
return f.bytes_ok == s.bytes_ok && f.bytes_fail == s.bytes_fail && f.cnt_ok == s.cnt_ok && f.cnt_fail == s.cnt_fail &&
|
||||
f.empty == s.empty;
|
||||
}
|
||||
inline bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) {
|
||||
return !(f == s);
|
||||
}
|
||||
inline bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) {
|
||||
return f.bytes_ok < s.bytes_ok;
|
||||
}
|
||||
inline bool operator !=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) {return !(f == s);}
|
||||
inline bool operator <(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) {return f.bytes_ok < s.bytes_ok;}
|
||||
|
||||
#endif // PIDIAGNOSTICS_H
|
||||
|
||||
@@ -5,29 +5,29 @@
|
||||
* \~russian Базовый класс для утилит ethernet
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Base class for ethernet utils
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Base class for ethernet utils
|
||||
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 PIETHUTILBASE_H
|
||||
#define PIETHUTILBASE_H
|
||||
|
||||
#include "pip_io_utils_export.h"
|
||||
#include "pibytearray.h"
|
||||
#include "pip_io_utils_export.h"
|
||||
|
||||
class PIP_IO_UTILS_EXPORT PIEthUtilBase {
|
||||
public:
|
||||
@@ -58,10 +58,9 @@ public:
|
||||
PIByteArray cryptKey() const;
|
||||
|
||||
protected:
|
||||
|
||||
/*! \brief Returns encrypted data if layer enabled,
|
||||
* otherwise returns unchanged \"data\" */
|
||||
PIByteArray cryptData(const PIByteArray & data);
|
||||
PIByteArray cryptData(const PIByteArray & data);
|
||||
|
||||
/*! \brief Returns decrypted data if layer enabled,
|
||||
* otherwise returns unchanged \"data\". If decryption
|
||||
@@ -71,7 +70,6 @@ protected:
|
||||
private:
|
||||
PIByteArray _key;
|
||||
bool _crypt;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIETHUTILBASE_H
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive files and directories via PIBaseTransfer
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive files and directories via PIBaseTransfer
|
||||
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 "pifiletransfer.h"
|
||||
@@ -22,11 +22,12 @@
|
||||
const char PIFileTransfer::sign[] = {'P', 'F', 'T'};
|
||||
|
||||
PIFileTransfer::PIFileTransfer() {
|
||||
for (uint i = 0; i < sizeof(sign); i++) pftheader.sig[i] = sign[i];
|
||||
pftheader.version = __PIFILETRANSFER_VERSION;
|
||||
for (uint i = 0; i < sizeof(sign); i++)
|
||||
pftheader.sig[i] = sign[i];
|
||||
pftheader.version = __PIFILETRANSFER_VERSION;
|
||||
pftheader.session_id = 0;
|
||||
pftheader.step = pft_None;
|
||||
dir = PIDir::current();
|
||||
pftheader.step = pft_None;
|
||||
dir = PIDir::current();
|
||||
started_ = scanning = false;
|
||||
bytes_file_all = bytes_file_cur = 0;
|
||||
CONNECT1(void, bool, this, sendFinished, this, send_finished);
|
||||
@@ -40,7 +41,7 @@ PIFileTransfer::~PIFileTransfer() {
|
||||
}
|
||||
|
||||
|
||||
bool PIFileTransfer::send(const PIFile& file) {
|
||||
bool PIFileTransfer::send(const PIFile & file) {
|
||||
return send(file.path());
|
||||
}
|
||||
|
||||
@@ -50,9 +51,10 @@ bool PIFileTransfer::send(const PIString & file) {
|
||||
}
|
||||
|
||||
|
||||
bool PIFileTransfer::send(const PIStringList& files) {
|
||||
bool PIFileTransfer::send(const PIStringList & files) {
|
||||
PIVector<PIFile::FileInfo> fil;
|
||||
piForeachC(PIString &file, files) fil << PIFile::fileInfo(file);
|
||||
piForeachC(PIString & file, files)
|
||||
fil << PIFile::fileInfo(file);
|
||||
return send(fil);
|
||||
}
|
||||
|
||||
@@ -66,16 +68,16 @@ bool PIFileTransfer::send(PIVector<PIFile::FileInfo> entries) {
|
||||
if (entries[i].isDir()) {
|
||||
cur_file_string = "scanning ... ";
|
||||
scan_dir.setDir(entries[i].path);
|
||||
scanning = true;
|
||||
scanning = true;
|
||||
PIVector<PIFile::FileInfo> fls = scan_dir.allEntries();
|
||||
scanning = false;
|
||||
scanning = false;
|
||||
scan_dir.up();
|
||||
//piCout << "files rel to" << d.absolutePath();
|
||||
// piCout << "files rel to" << d.absolutePath();
|
||||
for (uint j = 0; j < fls.size(); j++) {
|
||||
allEntries << PFTFileInfo(fls[j]);
|
||||
allEntries.back().dest_path = scan_dir.relative(fls[j].path);
|
||||
//piCout << " abs path" << fls[j].path;
|
||||
//piCout << " rel path" << allEntries.back().dest_path;
|
||||
// piCout << " abs path" << fls[j].path;
|
||||
// piCout << " rel path" << allEntries.back().dest_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,19 +85,18 @@ bool PIFileTransfer::send(PIVector<PIFile::FileInfo> entries) {
|
||||
}
|
||||
|
||||
|
||||
bool PIFileTransfer::sendFiles(const PIVector<PFTFileInfo> &files) {
|
||||
bool PIFileTransfer::sendFiles(const PIVector<PFTFileInfo> & files) {
|
||||
files_ = files;
|
||||
PIStringList names;
|
||||
//piCoutObj << "prepare to send" << files_.size() << "files";
|
||||
// piCoutObj << "prepare to send" << files_.size() << "files";
|
||||
for (int i = 0; i < files_.size_s(); i++) {
|
||||
if (names.contains(files_[i].path)) {
|
||||
files_.remove(i);
|
||||
--i;
|
||||
}
|
||||
else names << files_[i].path;
|
||||
if (files_[i].isDir())
|
||||
files_[i].size = 0;
|
||||
//piCout << "prepare" << i << files_[i].path << files_[i].dest_path << files_[i].name();
|
||||
} else
|
||||
names << files_[i].path;
|
||||
if (files_[i].isDir()) files_[i].size = 0;
|
||||
// piCout << "prepare" << i << files_[i].path << files_[i].dest_path << files_[i].name();
|
||||
}
|
||||
randomize();
|
||||
step_mutex.lock();
|
||||
@@ -129,15 +130,15 @@ bool PIFileTransfer::sendFiles(const PIVector<PFTFileInfo> &files) {
|
||||
|
||||
|
||||
void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
|
||||
//piCout << "processFile" << id << files_.size();
|
||||
PFTFileInfo fi = files_[id-1];
|
||||
bytes_file_all = fi.size;
|
||||
bytes_file_cur = start;
|
||||
// piCout << "processFile" << id << files_.size();
|
||||
PFTFileInfo fi = files_[id - 1];
|
||||
bytes_file_all = fi.size;
|
||||
bytes_file_cur = start;
|
||||
cur_file_string = fi.dest_path;
|
||||
PIString path = dir.absolutePath() + dir.separator + fi.dest_path;
|
||||
//piCout << "receive" << path << fi.size << data.size();
|
||||
PIString path = dir.absolutePath() + dir.separator + fi.dest_path;
|
||||
// piCout << "receive" << path << fi.size << data.size();
|
||||
if (fi.isDir()) {
|
||||
//piCoutObj << "make dir" << fi.entry.path;
|
||||
// piCoutObj << "make dir" << fi.entry.path;
|
||||
if (!PIDir::make(path)) {
|
||||
cur_file_string = "Error: While create directory \"" + path + "\"";
|
||||
piCoutObj << cur_file_string;
|
||||
@@ -147,9 +148,9 @@ void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
|
||||
}
|
||||
if (fi.isFile()) {
|
||||
if (work_file.path() != path || !work_file.isOpened()) {
|
||||
//piCout << "file close";
|
||||
// piCout << "file close";
|
||||
work_file.close();
|
||||
//piCout << "new file" << path << work_file.path() << work_file.isOpened();
|
||||
// piCout << "new file" << path << work_file.path() << work_file.isOpened();
|
||||
if (!work_file.open(path, PIIODevice::ReadWrite)) {
|
||||
cur_file_string = "Error: While open file \"" + path + "\"";
|
||||
piCoutObj << cur_file_string;
|
||||
@@ -158,17 +159,18 @@ void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
|
||||
}
|
||||
PIFile::applyFileInfo(path, fi);
|
||||
if (work_file.size() > fi.size) {
|
||||
//piCoutObj << "error size" << work_file.size() << fi.size;
|
||||
// piCoutObj << "error size" << work_file.size() << fi.size;
|
||||
work_file.clear();
|
||||
work_file.resize(fi.size);
|
||||
//piCoutObj << "correct size" << work_file.size() << fi.size;
|
||||
// piCoutObj << "correct size" << work_file.size() << fi.size;
|
||||
}
|
||||
}
|
||||
//piCoutObj << "write file" << path << work_file.path() << work_file.size() << fi.entry.size << work_file.pos() << fi.fstart << fi.fsize;
|
||||
// piCoutObj << "write file" << path << work_file.path() << work_file.size() << fi.entry.size << work_file.pos() << fi.fstart <<
|
||||
// fi.fsize;
|
||||
if (work_file.size() < (llong)start) {
|
||||
//piCoutObj << "error pos size" << work_file.pos() << fi.fstart;
|
||||
// piCoutObj << "error pos size" << work_file.pos() << fi.fstart;
|
||||
work_file.resize(start);
|
||||
//piCoutObj << "correct pos size" << work_file.pos() << fi.fstart;
|
||||
// piCoutObj << "correct pos size" << work_file.pos() << fi.fstart;
|
||||
}
|
||||
if (work_file.size() > fi.size) {
|
||||
piCoutObj << "****** error size" << work_file.size() << fi.size;
|
||||
@@ -176,11 +178,12 @@ void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
|
||||
work_file.resize(fi.size);
|
||||
piCoutObj << "****** correct size" << work_file.size() << fi.size;
|
||||
}
|
||||
//if (fi.fstart != work_file.pos()) piCoutObj << "error pos" << work_file.pos() << fi.fstart;
|
||||
// if (fi.fstart != work_file.pos()) piCoutObj << "error pos" << work_file.pos() << fi.fstart;
|
||||
work_file.seek(start);
|
||||
int rs = work_file.write(data.data(), data.size());
|
||||
if (rs != data.size_s()) {
|
||||
cur_file_string = "Error: While write file \"" + fi.path + "\" (must " + PIString::fromNumber(data.size()) + ", but write " + PIString::fromNumber(rs) + ")";
|
||||
cur_file_string = "Error: While write file \"" + fi.path + "\" (must " + PIString::fromNumber(data.size()) + ", but write " +
|
||||
PIString::fromNumber(rs) + ")";
|
||||
piCoutObj << cur_file_string;
|
||||
stopReceive();
|
||||
return;
|
||||
@@ -190,46 +193,45 @@ void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
|
||||
|
||||
|
||||
PIByteArray PIFileTransfer::buildPacket(Part p) {
|
||||
//piCoutObj << "Step" << pftheader.step;
|
||||
//piCoutObj << "session id" << pftheader.session_id;
|
||||
// piCoutObj << "Step" << pftheader.step;
|
||||
// piCoutObj << "session id" << pftheader.session_id;
|
||||
PIByteArray ba;
|
||||
switch(pftheader.step) {
|
||||
case pft_None:
|
||||
stopSend();
|
||||
return PIByteArray();
|
||||
case pft_Description:
|
||||
ba.resize(p.size);
|
||||
memcpy(ba.data(), desc.data(p.start), p.size);
|
||||
switch (pftheader.step) {
|
||||
case pft_None: stopSend(); return PIByteArray();
|
||||
case pft_Description:
|
||||
ba.resize(p.size);
|
||||
memcpy(ba.data(), desc.data(p.start), p.size);
|
||||
return ba;
|
||||
case pft_Data:
|
||||
//piCout << "send data" << p.id << files_.size();
|
||||
PIFile::FileInfo fi = files_[p.id-1];
|
||||
if (fi.isFile()) {
|
||||
//piCout << "send file" << fi.name() << fi.size;
|
||||
PIString path = fi.path;
|
||||
if (work_file.path() != path || !work_file.isOpened()) {
|
||||
if (!work_file.open(path, PIIODevice::ReadOnly)) {
|
||||
break_ = true;
|
||||
cur_file_string = "Error: While open file \"" + fi.path + "\"";
|
||||
piCoutObj << cur_file_string;
|
||||
stopSend();
|
||||
return PIByteArray();
|
||||
}
|
||||
}
|
||||
work_file.seek(p.start);
|
||||
ba.resize(p.size);
|
||||
int rs = work_file.read(ba.data(), ba.size());
|
||||
if ((llong)rs != (llong)p.size) {
|
||||
break_ = true;
|
||||
cur_file_string = "Error: While read file \"" + fi.path + "\" (must " + PIString::fromNumber(p.size) + ", but read " + PIString::fromNumber(rs) + ")";
|
||||
case pft_Data:
|
||||
// piCout << "send data" << p.id << files_.size();
|
||||
PIFile::FileInfo fi = files_[p.id - 1];
|
||||
if (fi.isFile()) {
|
||||
// piCout << "send file" << fi.name() << fi.size;
|
||||
PIString path = fi.path;
|
||||
if (work_file.path() != path || !work_file.isOpened()) {
|
||||
if (!work_file.open(path, PIIODevice::ReadOnly)) {
|
||||
break_ = true;
|
||||
cur_file_string = "Error: While open file \"" + fi.path + "\"";
|
||||
piCoutObj << cur_file_string;
|
||||
stopSend();
|
||||
return PIByteArray();
|
||||
}
|
||||
}
|
||||
cur_file_string = fi.path;
|
||||
bytes_file_all = fi.size;
|
||||
bytes_file_cur = p.start;
|
||||
work_file.seek(p.start);
|
||||
ba.resize(p.size);
|
||||
int rs = work_file.read(ba.data(), ba.size());
|
||||
if ((llong)rs != (llong)p.size) {
|
||||
break_ = true;
|
||||
cur_file_string = "Error: While read file \"" + fi.path + "\" (must " + PIString::fromNumber(p.size) + ", but read " +
|
||||
PIString::fromNumber(rs) + ")";
|
||||
piCoutObj << cur_file_string;
|
||||
stopSend();
|
||||
return PIByteArray();
|
||||
}
|
||||
}
|
||||
cur_file_string = fi.path;
|
||||
bytes_file_all = fi.size;
|
||||
bytes_file_cur = p.start;
|
||||
return ba;
|
||||
}
|
||||
return ba;
|
||||
@@ -242,7 +244,7 @@ void PIFileTransfer::receivePart(PIBaseTransfer::Part fi, PIByteArray ba, PIByte
|
||||
pheader >> h;
|
||||
// piCout << h.session_id;
|
||||
PIMutexLocker ml(step_mutex);
|
||||
StepType st = (StepType)h.step;
|
||||
StepType st = (StepType)h.step;
|
||||
pftheader.step = st;
|
||||
if (!h.check_sig()) {
|
||||
cur_file_string = "Error: Check signature: File Transfer incompatable or invalid version!";
|
||||
@@ -250,29 +252,27 @@ void PIFileTransfer::receivePart(PIBaseTransfer::Part fi, PIByteArray ba, PIByte
|
||||
stopReceive();
|
||||
return;
|
||||
}
|
||||
switch(st) {
|
||||
case pft_None:
|
||||
switch (st) {
|
||||
case pft_None: break;
|
||||
case pft_Description:
|
||||
pftheader.session_id = h.session_id;
|
||||
if (desc.size() < fi.start + fi.size) desc.resize(fi.start + fi.size);
|
||||
memcpy(desc.data(fi.start), ba.data(), ba.size_s());
|
||||
break;
|
||||
case pft_Description:
|
||||
pftheader.session_id = h.session_id;
|
||||
if (desc.size() < fi.start + fi.size) desc.resize(fi.start + fi.size);
|
||||
memcpy(desc.data(fi.start), ba.data(), ba.size_s());
|
||||
break;
|
||||
case pft_Data:
|
||||
if (h.session_id == pftheader.session_id)
|
||||
processFile(fi.id, fi.start, ba);
|
||||
else stopReceive();
|
||||
break;
|
||||
default:
|
||||
case pft_Data:
|
||||
if (h.session_id == pftheader.session_id)
|
||||
processFile(fi.id, fi.start, ba);
|
||||
else
|
||||
stopReceive();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIString PIFileTransfer::curFile() const {
|
||||
PIString s = cur_file_string;
|
||||
if (scanning)
|
||||
return s + scan_dir.scanDir();
|
||||
if (scanning) return s + scan_dir.scanDir();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ PIByteArray PIFileTransfer::customHeader() {
|
||||
void PIFileTransfer::beginReceive() {
|
||||
if (pftheader.step == pft_None) {
|
||||
files_.clear();
|
||||
// piCoutObj << "start receive"
|
||||
// piCoutObj << "start receive"
|
||||
started_ = true;
|
||||
receiveFilesStarted();
|
||||
}
|
||||
@@ -301,11 +301,12 @@ void PIFileTransfer::receive_finished(bool ok) {
|
||||
if (st == pft_Description) {
|
||||
bool user_ok = true;
|
||||
if (ok) {
|
||||
// piCoutObj << desc.size() << PICoutManipulators::Hex << desc;
|
||||
// piCoutObj << desc.size() << PICoutManipulators::Hex << desc;
|
||||
desc >> files_;
|
||||
// piCoutObj << files_;
|
||||
// piCoutObj << files_;
|
||||
PIStringList files;
|
||||
piForeachC(PFTFileInfo &fi, files_) files << fi.dest_path;
|
||||
piForeachC(PFTFileInfo & fi, files_)
|
||||
files << fi.dest_path;
|
||||
pause();
|
||||
receiveFilesRequest(files, bytesAll(), &user_ok);
|
||||
}
|
||||
@@ -314,10 +315,11 @@ void PIFileTransfer::receive_finished(bool ok) {
|
||||
piCoutObj << "receive aborted";
|
||||
receiveFilesFinished(false);
|
||||
started_ = false;
|
||||
} else resume();
|
||||
} else
|
||||
resume();
|
||||
}
|
||||
if (st == pft_Data) {
|
||||
//piCoutObj << "file close";
|
||||
// piCoutObj << "file close";
|
||||
work_file.close();
|
||||
receiveFilesFinished(ok);
|
||||
started_ = false;
|
||||
@@ -326,7 +328,7 @@ void PIFileTransfer::receive_finished(bool ok) {
|
||||
|
||||
|
||||
void PIFileTransfer::send_finished(bool ok) {
|
||||
// piCoutObj << "file close";
|
||||
// piCoutObj << "file close";
|
||||
if (pftheader.step == pft_Data) {
|
||||
work_file.close();
|
||||
}
|
||||
|
||||
@@ -5,47 +5,51 @@
|
||||
* \~russian Класс для отправки и приема файлов и папок с помощью \a PIBaseTransfer
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive files and directories via PIBaseTransfer
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Class for send and receive files and directories via PIBaseTransfer
|
||||
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 PIFILETRANSFER_H
|
||||
#define PIFILETRANSFER_H
|
||||
|
||||
#include "pidir.h"
|
||||
#include "pibasetransfer.h"
|
||||
#include "pidir.h"
|
||||
|
||||
#define __PIFILETRANSFER_VERSION 2
|
||||
|
||||
class PIP_EXPORT PIFileTransfer: public PIBaseTransfer
|
||||
{
|
||||
class PIP_EXPORT PIFileTransfer: public PIBaseTransfer {
|
||||
PIOBJECT_SUBCLASS(PIFileTransfer, PIBaseTransfer);
|
||||
|
||||
public:
|
||||
PIFileTransfer();
|
||||
~PIFileTransfer();
|
||||
|
||||
enum StepType {pft_None, pft_Description, pft_Data};
|
||||
enum StepType {
|
||||
pft_None,
|
||||
pft_Description,
|
||||
pft_Data
|
||||
};
|
||||
|
||||
struct PIP_EXPORT PFTFileInfo: public PIFile::FileInfo {
|
||||
PFTFileInfo(const PIFile::FileInfo &fi = PIFile::FileInfo()): PIFile::FileInfo(fi) {}
|
||||
PFTFileInfo(const PIFile::FileInfo & fi = PIFile::FileInfo()): PIFile::FileInfo(fi) {}
|
||||
PIString dest_path;
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
#pragma pack(push, 1)
|
||||
struct PIP_EXPORT PFTHeader {
|
||||
union {
|
||||
struct {
|
||||
@@ -65,29 +69,29 @@ public:
|
||||
|
||||
bool send(const PIFile & file);
|
||||
bool send(const PIString & file);
|
||||
bool send(const PIStringList &files);
|
||||
bool send(PIFile::FileInfo entry) {return send(PIVector<PIFile::FileInfo>() << entry);}
|
||||
bool send(const PIStringList & files);
|
||||
bool send(PIFile::FileInfo entry) { return send(PIVector<PIFile::FileInfo>() << entry); }
|
||||
bool send(PIVector<PIFile::FileInfo> entries);
|
||||
|
||||
void setDirectory(const PIDir &d) {dir = d;}
|
||||
void setDirectory(const PIString &path) {dir.setDir(path);}
|
||||
PIDir directory() const {return dir;}
|
||||
void setDirectory(const PIDir & d) { dir = d; }
|
||||
void setDirectory(const PIString & path) { dir.setDir(path); }
|
||||
PIDir directory() const { return dir; }
|
||||
|
||||
bool isStarted() const {return started_;}
|
||||
bool isStarted() const { return started_; }
|
||||
|
||||
PIString curFile() const;
|
||||
llong bytesFileAll() const {return bytes_file_all;}
|
||||
llong bytesFileCur() const {return bytes_file_cur;}
|
||||
const PIString * curFile_ptr() const {return &cur_file_string;}
|
||||
const llong * bytesFileAll_ptr() const {return &bytes_file_all;}
|
||||
const llong * bytesFileCur_ptr() const {return &bytes_file_cur;}
|
||||
llong bytesFileAll() const { return bytes_file_all; }
|
||||
llong bytesFileCur() const { return bytes_file_cur; }
|
||||
const PIString * curFile_ptr() const { return &cur_file_string; }
|
||||
const llong * bytesFileAll_ptr() const { return &bytes_file_all; }
|
||||
const llong * bytesFileCur_ptr() const { return &bytes_file_cur; }
|
||||
|
||||
EVENT(receiveFilesStarted);
|
||||
EVENT1(receiveFilesFinished, bool, ok);
|
||||
EVENT(sendFilesStarted);
|
||||
EVENT1(sendFilesFinished, bool, ok);
|
||||
EVENT3(receiveFilesRequest, PIStringList, files, llong, total_bytes, bool *, ok);
|
||||
|
||||
|
||||
private:
|
||||
static const char sign[];
|
||||
PIVector<PFTFileInfo> files_;
|
||||
@@ -101,8 +105,8 @@ private:
|
||||
bool started_, scanning;
|
||||
PIMutex step_mutex;
|
||||
|
||||
bool sendFiles(const PIVector<PFTFileInfo> &files);
|
||||
void processFile(int id, ullong start, PIByteArray &data);
|
||||
bool sendFiles(const PIVector<PFTFileInfo> & files);
|
||||
void processFile(int id, ullong start, PIByteArray & data);
|
||||
void receivePart(Part fi, PIByteArray ba, PIByteArray pheader) override;
|
||||
PIByteArray buildPacket(Part fi) override;
|
||||
PIByteArray customHeader() override;
|
||||
@@ -111,26 +115,31 @@ private:
|
||||
EVENT_HANDLER1(void, receive_finished, bool, ok);
|
||||
};
|
||||
|
||||
BINARY_STREAM_WRITE(PIFileTransfer::PFTHeader) {s << v.raw_sig << v.step << v.session_id; return s;}
|
||||
BINARY_STREAM_READ (PIFileTransfer::PFTHeader) {s >> v.raw_sig >> v.step >> v.session_id; return s;}
|
||||
BINARY_STREAM_WRITE(PIFileTransfer::PFTHeader) {
|
||||
s << v.raw_sig << v.step << v.session_id;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIFileTransfer::PFTHeader) {
|
||||
s >> v.raw_sig >> v.step >> v.session_id;
|
||||
return s;
|
||||
}
|
||||
|
||||
BINARY_STREAM_WRITE(PIFileTransfer::PFTFileInfo) {
|
||||
s << v.dest_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.dest_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;
|
||||
}
|
||||
BINARY_STREAM_READ (PIFileTransfer::PFTFileInfo) {
|
||||
s >> v.dest_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;
|
||||
BINARY_STREAM_READ(PIFileTransfer::PFTFileInfo) {
|
||||
s >> v.dest_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;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PIFileTransfer::PFTFileInfo & v) {
|
||||
inline PICout operator<<(PICout s, const PIFileTransfer::PFTFileInfo & v) {
|
||||
s.saveAndSetControls(0);
|
||||
s << "FileInfo(\"" << v.dest_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.dest_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;
|
||||
}
|
||||
|
||||
@@ -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-Utils IO-Utils
|
||||
//! \~\brief
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Packets extractor
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Packets extractor
|
||||
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 "pipacketextractor.h"
|
||||
@@ -91,8 +91,8 @@ PIPacketExtractor::PIPacketExtractor(PIIODevice * device_, PIPacketExtractor::Sp
|
||||
|
||||
|
||||
void PIPacketExtractor::construct() {
|
||||
func_header = nullptr;
|
||||
func_footer = nullptr;
|
||||
func_header = nullptr;
|
||||
func_footer = nullptr;
|
||||
func_payload = nullptr;
|
||||
setPayloadSize(0);
|
||||
setTimeout(100);
|
||||
@@ -104,16 +104,16 @@ void PIPacketExtractor::construct() {
|
||||
setDevice(nullptr);
|
||||
setSplitMode(None);
|
||||
missed = footerInd = 0;
|
||||
header_found = false;
|
||||
header_found = false;
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::propertyChanged(const char *) {
|
||||
mode_ = (SplitMode)(property("splitMode").toInt());
|
||||
dataSize = property("payloadSize").toInt();
|
||||
mode_ = (SplitMode)(property("splitMode").toInt());
|
||||
dataSize = property("payloadSize").toInt();
|
||||
src_header = property("header").toByteArray();
|
||||
src_footer = property("footer").toByteArray();
|
||||
time_ = property("timeout").toDouble();
|
||||
time_ = property("timeout").toDouble();
|
||||
}
|
||||
|
||||
|
||||
@@ -135,8 +135,10 @@ void PIPacketExtractor::setDevice(PIIODevice * device_) {
|
||||
|
||||
|
||||
ssize_t PIPacketExtractor::bytesAvailable() const {
|
||||
if (dev) return dev->bytesAvailable();
|
||||
else return 0;
|
||||
if (dev)
|
||||
return dev->bytesAvailable();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +185,7 @@ bool PIPacketExtractor::validatePayload(const uchar * rec, int size) {
|
||||
|
||||
|
||||
bool PIPacketExtractor::threadedRead(const uchar * readed, ssize_t size_) {
|
||||
//piCoutObj << "readed" << size_;
|
||||
// piCoutObj << "readed" << size_;
|
||||
int ss;
|
||||
tmpbuf.append(readed, size_);
|
||||
switch (mode_) {
|
||||
@@ -194,7 +196,7 @@ bool PIPacketExtractor::threadedRead(const uchar * readed, ssize_t size_) {
|
||||
} else {
|
||||
missed += size_;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case PIPacketExtractor::Header:
|
||||
if (src_header.isEmpty()) return PIIODevice::threadedRead(readed, size_);
|
||||
while (tmpbuf.size() >= src_header.size()) {
|
||||
@@ -249,14 +251,14 @@ bool PIPacketExtractor::threadedRead(const uchar * readed, ssize_t size_) {
|
||||
if (tmpbuf.size_s() < ss) return PIIODevice::threadedRead(readed, size_);
|
||||
}
|
||||
header_found = true;
|
||||
footerInd = src_header.size_s();
|
||||
footerInd = src_header.size_s();
|
||||
} else {
|
||||
if (tmpbuf.size_s() < footerInd + src_footer.size_s()) return PIIODevice::threadedRead(readed, size_);
|
||||
while (!validateFooter(src_footer.data(), tmpbuf.data(footerInd), src_footer.size_s())) {
|
||||
++footerInd;
|
||||
if (tmpbuf.size_s() < footerInd + src_footer.size_s()) return PIIODevice::threadedRead(readed, size_);
|
||||
}
|
||||
//piCout << "footer found at" << footerInd;
|
||||
// piCout << "footer found at" << footerInd;
|
||||
header_found = false;
|
||||
if (!validatePayload(tmpbuf.data(src_header.size_s()), footerInd - src_header.size_s())) {
|
||||
tmpbuf.pop_front();
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Извлекатель пакетов
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Packets extractor
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Packets extractor
|
||||
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 PIPACKETEXTRACTOR_H
|
||||
@@ -41,43 +41,42 @@ typedef std::function<bool(const uchar *, int)> PacketExtractorPayloadFunc;
|
||||
/// Return true if packet is correct, false otherwise.
|
||||
typedef std::function<bool(const uchar *, const uchar *, int)> PacketExtractorFooterFunc;
|
||||
|
||||
class PIP_EXPORT PIPacketExtractor: public PIIODevice
|
||||
{
|
||||
class PIP_EXPORT PIPacketExtractor: public PIIODevice {
|
||||
PIIODEVICE(PIPacketExtractor, "pckext");
|
||||
friend class PIConnection;
|
||||
public:
|
||||
|
||||
public:
|
||||
//! Extract algorithms
|
||||
enum SplitMode {
|
||||
None /** No data processing */ ,
|
||||
Header /** Detect packets with \a header() and following \a payloadSize() */ ,
|
||||
Footer /** Detect packets with \a footer() and leading \a payloadSize() */ ,
|
||||
HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */ ,
|
||||
Size /** Detect packets with \a packetSize() */ ,
|
||||
None /** No data processing */,
|
||||
Header /** Detect packets with \a header() and following \a payloadSize() */,
|
||||
Footer /** Detect packets with \a footer() and leading \a payloadSize() */,
|
||||
HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */,
|
||||
Size /** Detect packets with \a packetSize() */,
|
||||
Timeout /** Wait for first read, then read for \a timeout() milliseconds */
|
||||
};
|
||||
|
||||
//! Contructs extractor with child device "device_" and extract algorithm "mode"
|
||||
explicit PIPacketExtractor(PIIODevice * device_ = nullptr, SplitMode mode = None);
|
||||
|
||||
virtual ~PIPacketExtractor() {stop();}
|
||||
virtual ~PIPacketExtractor() { stop(); }
|
||||
|
||||
|
||||
//! Returns child %device
|
||||
PIIODevice * device() {return dev;}
|
||||
PIIODevice * device() { return dev; }
|
||||
|
||||
//! Set child %device to "device_"
|
||||
void setDevice(PIIODevice * device_);
|
||||
|
||||
ssize_t bytesAvailable() const override;
|
||||
|
||||
void setHeaderCheckSlot(PacketExtractorHeaderFunc f) {func_header = f;}
|
||||
void setPayloadCheckSlot(PacketExtractorPayloadFunc f) {func_payload = f;}
|
||||
void setFooterCheckSlot(PacketExtractorFooterFunc f) {func_footer = f;}
|
||||
void setHeaderCheckSlot(PacketExtractorHeaderFunc f) { func_header = f; }
|
||||
void setPayloadCheckSlot(PacketExtractorPayloadFunc f) { func_payload = f; }
|
||||
void setFooterCheckSlot(PacketExtractorFooterFunc f) { func_footer = f; }
|
||||
|
||||
|
||||
//! Set extract algorithm
|
||||
void setSplitMode(SplitMode mode) {setProperty("splitMode", int(mode));}
|
||||
void setSplitMode(SplitMode mode) { setProperty("splitMode", int(mode)); }
|
||||
|
||||
//! Set payload size, used for PIPacketExtractor::Header and PIPacketExtractor::Footer algorithms
|
||||
void setPayloadSize(int size);
|
||||
@@ -89,45 +88,45 @@ public:
|
||||
void setFooter(const PIByteArray & data);
|
||||
|
||||
//! Set timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
||||
void setTimeout(double msecs) {setProperty("timeout", msecs);}
|
||||
void setTimeout(double msecs) { setProperty("timeout", msecs); }
|
||||
|
||||
|
||||
//! Returns current extract algorithm
|
||||
SplitMode splitMode() const {return mode_;}
|
||||
SplitMode splitMode() const { return mode_; }
|
||||
|
||||
//! Returns current payload size, used for PIPacketExtractor::Header and PIPacketExtractor::Footer and PIPacketExtractor::Size algorithms
|
||||
int payloadSize() const {return dataSize;}
|
||||
//! Returns current payload size, used for PIPacketExtractor::Header and PIPacketExtractor::Footer and PIPacketExtractor::Size
|
||||
//! algorithms
|
||||
int payloadSize() const { return dataSize; }
|
||||
|
||||
//! Returns current header data, used for PIPacketExtractor::Header and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
PIByteArray header() const {return src_header;}
|
||||
PIByteArray header() const { return src_header; }
|
||||
|
||||
//! Returns current footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
PIByteArray footer() const {return src_footer;}
|
||||
PIByteArray footer() const { return src_footer; }
|
||||
|
||||
//! Returns current timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
||||
double timeout() const {return time_;}
|
||||
double timeout() const { return time_; }
|
||||
|
||||
//! Returns missed by validating functions bytes count
|
||||
ullong missedBytes() const {return missed;}
|
||||
ullong missedBytes() const { return missed; }
|
||||
|
||||
//! Add data to extractor, raise \a packetReceived() if packet is ready
|
||||
void appendData(const uchar * d, int s) {threadedRead(d, s);}
|
||||
void appendData(const uchar * d, int s) { threadedRead(d, s); }
|
||||
|
||||
//! Add data to extractor, raise \a packetReceived() if packet is ready
|
||||
void appendData(const PIByteArray & data) {threadedRead(data.data(), data.size_s());}
|
||||
void appendData(const PIByteArray & data) { threadedRead(data.data(), data.size_s()); }
|
||||
|
||||
EVENT2(packetReceived, const uchar * , data, int, size);
|
||||
EVENT2(packetReceived, const uchar *, data, int, size);
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void packetReceived(const uchar * data, int size)
|
||||
//! \brief Raise on successfull \a packetValidate() function
|
||||
|
||||
//! \}
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
/** \brief Function to validate header
|
||||
* \param src Your header content
|
||||
* \param rec Received header
|
||||
@@ -152,7 +151,7 @@ private:
|
||||
void construct();
|
||||
void propertyChanged(const char *) override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
bool threadedRead(const uchar * readed, ssize_t size) override;
|
||||
PIString constructFullPathDevice() const override;
|
||||
bool openDevice() override;
|
||||
@@ -169,8 +168,6 @@ private:
|
||||
double time_;
|
||||
bool header_found;
|
||||
ullong missed;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // PIPACKETEXTRACTOR_H
|
||||
|
||||
@@ -5,29 +5,29 @@
|
||||
* \~russian Класс для автоматизации приема структур
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Helper class to automate structs receive
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Helper class to automate structs receive
|
||||
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 PIPARSEHELPER_H
|
||||
#define PIPARSEHELPER_H
|
||||
|
||||
#include "pip_io_utils_export.h"
|
||||
#include "piobject.h"
|
||||
#include "pip_io_utils_export.h"
|
||||
|
||||
|
||||
/** \class PIParseHelper
|
||||
@@ -84,17 +84,16 @@
|
||||
*
|
||||
**/
|
||||
|
||||
template <typename Key>
|
||||
template<typename Key>
|
||||
class PIParseHelper {
|
||||
public:
|
||||
|
||||
//! \brief Construct %PIParseHelper with target object \"p\"
|
||||
PIParseHelper(PIObject * p): parent(p) {}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to event handler \"handler\" with 1 argument
|
||||
template <typename T, typename Ret>
|
||||
void assign(Key key, Ret(*handler)(void*,T)) {
|
||||
template<typename T, typename Ret>
|
||||
void assign(Key key, Ret (*handler)(void *, T)) {
|
||||
if (!parent) return;
|
||||
auto mf = PIObject::__meta_data().value(parent->classNameID());
|
||||
auto it = mf.eh_func.makeIterator();
|
||||
@@ -102,9 +101,10 @@ public:
|
||||
it.next();
|
||||
if (it.value().addr == handler) {
|
||||
void * addr = it.value().addr;
|
||||
auto func = [addr](PIObject * o, PIByteArray data){
|
||||
T v; data >> v;
|
||||
((void(*)(void*, T))addr)(o, v);
|
||||
auto func = [addr](PIObject * o, PIByteArray data) {
|
||||
T v;
|
||||
data >> v;
|
||||
((void (*)(void *, T))addr)(o, v);
|
||||
};
|
||||
functions[key] << func;
|
||||
break;
|
||||
@@ -114,8 +114,8 @@ public:
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to event handler \"handler\" without arguments
|
||||
template <typename Ret>
|
||||
void assign(Key key, Ret(*handler)(void*)) {
|
||||
template<typename Ret>
|
||||
void assign(Key key, Ret (*handler)(void *)) {
|
||||
if (!parent) return;
|
||||
auto mf = PIObject::__meta_data().value(parent->classNameID());
|
||||
auto it = mf.eh_func.makeIterator();
|
||||
@@ -123,9 +123,7 @@ public:
|
||||
it.next();
|
||||
if (it.value().addr == handler) {
|
||||
void * addr = it.value().addr;
|
||||
auto func = [addr](PIObject * o, PIByteArray ){
|
||||
((void(*)(void*))addr)(o);
|
||||
};
|
||||
auto func = [addr](PIObject * o, PIByteArray) { ((void (*)(void *))addr)(o); };
|
||||
functions[key] << func;
|
||||
break;
|
||||
}
|
||||
@@ -135,12 +133,13 @@ public:
|
||||
|
||||
//! \brief Assign key \"key\" to lambda-function \"func\" with 1 argument
|
||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
void assign(Key key, std::function<void(T)> func) {
|
||||
if (!parent) return;
|
||||
auto lf = [func](PIObject * , PIByteArray data){
|
||||
auto lf = [func](PIObject *, PIByteArray data) {
|
||||
if (!data.isEmpty()) {
|
||||
T v; data >> v;
|
||||
T v;
|
||||
data >> v;
|
||||
func(v);
|
||||
}
|
||||
};
|
||||
@@ -152,9 +151,7 @@ public:
|
||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
||||
void assign(Key key, std::function<void()> func) {
|
||||
if (!parent) return;
|
||||
auto lf = [func](PIObject * , PIByteArray ){
|
||||
func();
|
||||
};
|
||||
auto lf = [func](PIObject *, PIByteArray) { func(); };
|
||||
functions[key] << lf;
|
||||
}
|
||||
|
||||
@@ -170,7 +167,6 @@ public:
|
||||
private:
|
||||
PIMap<Key, PIVector<std::function<void(PIObject *, PIByteArray)>>> functions;
|
||||
PIObject * parent;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -5,69 +5,72 @@
|
||||
* \~russian Простая фрагментация пакетов, использует любой PIIODevice
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Simple packet wrap aroud any PIIODevice
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Simple packet wrap aroud any PIIODevice
|
||||
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 PISTREAMPACKER_H
|
||||
#define PISTREAMPACKER_H
|
||||
|
||||
#include "pip_io_utils_export.h"
|
||||
#include "piobject.h"
|
||||
#include "piethutilbase.h"
|
||||
#include "piobject.h"
|
||||
#include "pip_io_utils_export.h"
|
||||
|
||||
|
||||
class PIIODevice;
|
||||
|
||||
class PIP_IO_UTILS_EXPORT PIStreamPacker: public PIObject, public PIEthUtilBase {
|
||||
class PIP_IO_UTILS_EXPORT PIStreamPacker
|
||||
: public PIObject
|
||||
, public PIEthUtilBase {
|
||||
PIOBJECT(PIStreamPacker)
|
||||
|
||||
public:
|
||||
//! Contructs packer and try to assign \"dev\"
|
||||
PIStreamPacker(PIIODevice * dev = 0);
|
||||
|
||||
|
||||
//! Set maximum size of single packet
|
||||
void setMaxPacketSize(int max_size) {max_packet_size = max_size;}
|
||||
void setMaxPacketSize(int max_size) { max_packet_size = max_size; }
|
||||
|
||||
//! Returns maximum size of single packet, default 1400 bytes
|
||||
int maxPacketSize() const {return max_packet_size;}
|
||||
int maxPacketSize() const { return max_packet_size; }
|
||||
|
||||
|
||||
//! Set packet sinature
|
||||
void setPacketSign(ushort sign_) {packet_sign = sign_;}
|
||||
void setPacketSign(ushort sign_) { packet_sign = sign_; }
|
||||
|
||||
//! Returns packet sinature, default 0xAFBE
|
||||
ushort packetSign() const {return packet_sign;}
|
||||
ushort packetSign() const { return packet_sign; }
|
||||
|
||||
|
||||
//! Set receive aggressive optimization. If yes then %PIStreamPacker doesn`t
|
||||
//! check every byte in incoming stream but check only begin of each read()
|
||||
//! result. Default is \b true.
|
||||
void setaAggressiveOptimization(bool yes) {aggressive_optimization = yes;}
|
||||
void setaAggressiveOptimization(bool yes) { aggressive_optimization = yes; }
|
||||
|
||||
//! Returns aggressive optimization
|
||||
bool aggressiveOptimization() const {return aggressive_optimization;}
|
||||
bool aggressiveOptimization() const { return aggressive_optimization; }
|
||||
|
||||
|
||||
bool cryptFragmentationEnabled() const {return crypt_frag;}
|
||||
void setCryptFragmentationEnabled(bool on) {crypt_frag = on;}
|
||||
int cryptFragmentationSize() const {return crypt_frag_size;}
|
||||
void setCryptFragmentationSize(int size_) {crypt_frag_size = size_;}
|
||||
bool cryptSizeEnabled() const {return crypt_size;}
|
||||
bool cryptFragmentationEnabled() const { return crypt_frag; }
|
||||
void setCryptFragmentationEnabled(bool on) { crypt_frag = on; }
|
||||
int cryptFragmentationSize() const { return crypt_frag_size; }
|
||||
void setCryptFragmentationSize(int size_) { crypt_frag_size = size_; }
|
||||
bool cryptSizeEnabled() const { return crypt_size; }
|
||||
void setCryptSizeEnabled(bool on);
|
||||
|
||||
void clear();
|
||||
@@ -80,7 +83,7 @@ public:
|
||||
//! and \a packetReceived() virtual method
|
||||
void received(const PIByteArray & data);
|
||||
|
||||
EVENT_HANDLER2(void, received, const uchar * , readed, ssize_t, size);
|
||||
EVENT_HANDLER2(void, received, const uchar *, readed, ssize_t, size);
|
||||
|
||||
//! Connect \"dev\" \a PIIODevice::threadedReadEvent() event to \a received() handler
|
||||
//! and \a sendRequest() event to \"dev\" \a PIIODevice::write() handler
|
||||
@@ -92,27 +95,26 @@ public:
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void received(uchar * readed, int size)
|
||||
//! \brief Handler to receive data. \a PIIODevice::threadedReadEvent()
|
||||
//! can be connected to this handler
|
||||
//! \fn void received(uchar * readed, int size)
|
||||
//! \brief Handler to receive data. \a PIIODevice::threadedReadEvent()
|
||||
//! can be connected to this handler
|
||||
|
||||
//! \}
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void packetReceiveEvent(PIByteArray data)
|
||||
//! \brief Raise on packet successfully received
|
||||
//! \fn void packetReceiveEvent(PIByteArray data)
|
||||
//! \brief Raise on packet successfully received
|
||||
|
||||
//! \fn void sendRequest(PIByteArray data)
|
||||
//! \brief Raise from \a send() function. This data should
|
||||
//! be directly sended to your device. You can
|
||||
//! connect this event to \a PIIODevice::write() handler
|
||||
//! \fn void sendRequest(PIByteArray data)
|
||||
//! \brief Raise from \a send() function. This data should
|
||||
//! be directly sended to your device. You can
|
||||
//! connect this event to \a PIIODevice::write() handler
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
//! Packet successfully received, by default does nothing
|
||||
virtual void packetReceived(PIByteArray data) {}
|
||||
|
||||
@@ -123,7 +125,6 @@ private:
|
||||
ushort packet_sign;
|
||||
int max_packet_size, size_crypted_size;
|
||||
mutable PIMutex prog_s_mutex, prog_r_mutex;
|
||||
|
||||
};
|
||||
|
||||
#endif // PISTREAMPACKER_H
|
||||
|
||||
Reference in New Issue
Block a user