diff --git a/CMakeLists.txt b/CMakeLists.txt index 1741d21..f2826b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ endif () include(SDKMacros.cmake) set(PIP_LIBRARY pip) -set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io" "console" "math" "code" "geo" "resources" "opencl" "crypt") +set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io_devices" "io_utils" "console" "math" "code" "geo" "resources" "opencl" "crypt") set(PIP_INCLUDES) if (LIB) diff --git a/kx_utils/CMakeLists.txt b/kx_utils/CMakeLists.txt index 3af569c..cf3a787 100644 --- a/kx_utils/CMakeLists.txt +++ b/kx_utils/CMakeLists.txt @@ -18,8 +18,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") if (DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") endif() -set(CPPS_UTILS "kx_coeffs.cpp") -set(HDRS_UTILS "kx_coeffs.h" "kx_protocol_x.h" "kx_protocol_c.h") +set(CPPS_UTILS "kx_coeffs.cpp" "piprotocol.cpp") +set(HDRS_UTILS "kx_coeffs.h" "kx_protocol_x.h" "kx_protocol_c.h" "piprotocol.h") if (DEFINED ENV{QNX_HOST}) add_library(${PROJECT_NAME} STATIC ${CPPS_UTILS}) else() diff --git a/kx_utils/piprotocol.cpp b/kx_utils/piprotocol.cpp new file mode 100644 index 0000000..8d0b09b --- /dev/null +++ b/kx_utils/piprotocol.cpp @@ -0,0 +1,718 @@ +/* + PIP - Platform Independent Primitives + Protocol, input/output channel (COM, UDP) + Copyright (C) 2018 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 General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "piprotocol.h" + +/** \class PIProtocol + * \brief + * \details + * \section PIProtocol_sec0 Synopsis + * + * + * + * */ + + /// DEPRECATED +PIProtocol::PIProtocol(const PIString & config, const PIString & name_, void * recHeaderPtr, int recHeaderSize, void * recDataPtr, int recDataSize, void * sendDataPtr_, int sendDataSize_): PIObject() { + init(); + protName = name_; + PIObject::setName(name_); + PIConfig conf(config, PIIODevice::ReadOnly); + if (!conf.isOpened()) { + piCoutObj << "Can`t open \"" << config << "\"!"; + devReceiverState = devSenderState = "Config error"; + return; + } + PIConfig::Entry & b(conf.getValue(name_)), + & rb(b.getValue("receiver")), + & sb(b.getValue("sender")); + + init_receiver(b, rb, config); + init_sender(b, sb, config); + + headerPtr = (uchar * )recHeaderPtr; + headerSize = recHeaderSize; + dataPtr = (uchar * )recDataPtr; + dataSize = recDataSize; + sendDataPtr = (uchar * )sendDataPtr_; + sendDataSize = sendDataSize_; + packet_ext->setHeader(PIByteArray(recHeaderPtr, recHeaderSize)); + packet_ext->setPayloadSize(recDataSize); + packet_ext->setPacketSize(recDataSize); + packet_ext->setSplitMode(PIPacketExtractor::Header); + bool null_h = (recHeaderPtr == 0 || recHeaderSize == 0), null_d = (recDataPtr == 0 || recDataSize == 0); + if (null_h && null_d) packet_ext->setSplitMode(PIPacketExtractor::None); + else { + if (null_h) packet_ext->setSplitMode(PIPacketExtractor::Size); + } +} + + +PIProtocol::~PIProtocol() { + delete diagTimer; + delete sendTimer; + delete secTimer; + delete packet_ext; + if (eth != 0) delete eth; + if (ser != 0) delete ser; +} + + +void PIProtocol::init() { + packet_ext = new PIPacketExtractor(0, PIPacketExtractor::None); + packet_ext->setThreadedReadData(this); + packet_ext->setThreadedReadSlot(receiveEvent); + packet_ext->setHeaderCheckSlot(headerValidateEvent); + packet_ext->setName("__S__PIProtocol::packet_ext"); + work = new_mp_prot = false; + eth = 0; + ser = 0; + ret_func = 0; + mp_owner = 0; + net_diag = PIProtocol::Unknown; + cur_pckt = 0; + packets[0] = packets[1] = pckt_cnt = pckt_cnt_max = 0; + diagTimer = 0; + timeout_ = 3.f; + sendTimer = new PITimer(sendEvent, this); + diagTimer = new PITimer(diagEvent, this); + secTimer = new PITimer(secEvent, this); + sendTimer->setName("__S__PIProtocol::sendTimer"); + diagTimer->setName("__S__PIProtocol::diagTimer"); + secTimer->setName("__S__PIProtocol::secTimer"); + wrong_count = receive_count = send_count = missed_count = 0; + packets_in_sec = packets_out_sec = bytes_in_sec = bytes_out_sec = 0; + immediate_freq = integral_freq = ifreq = 0.f; + headerPtr = dataPtr = sendDataPtr = 0; + headerSize = dataSize = sendDataSize = 0; + type_rec = type_send = PIProtocol::None; + devSenderState = devReceiverState = "Unknown"; + devSenderName = devReceiverName = "no device"; + secTimer->start(1000.); + /*addEvent("receiver started"); + addEvent("receiver stopped"); + addEvent("sender started"); + addEvent("sender stopped"); + addEvent("received"); + addEvent("quality changed"); + addEventHandler(HANDLER(PIProtocol, startReceive)); + addEventHandler(HANDLER(PIProtocol, startSend)); + addEventHandler(HANDLER(PIProtocol, start)); + addEventHandler(HANDLER(PIProtocol, stopReceive)); + addEventHandler(HANDLER(PIProtocol, stopSend)); + addEventHandler(HANDLER(PIProtocol, stop));*/ +} + + +void PIProtocol::init_sender(PIConfig::Entry & b, PIConfig::Entry & sb, const PIString & config) { + int ps, gps; + bool ok, gok, flag, gflag, has_dev = false; + float freq, gfreq; + PIFlags pp(0); + PIString dev, gdev; + + if (sb.isEntryExists("ip") && sb.isEntryExists("device")) { + piCoutObj << "Ambiguous sender type in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + dev = sb.getValue("ip", "", &ok); + gdev = b.getValue("ip", "", &gok); + has_dev = false; + if (ok || gok) { + if (gok && !ok) dev = gdev; + if (gok && ok && (dev != gdev)) { + piCoutObj << "Ambiguous sender type in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + ps = sb.getValue("port", 0, &ok); + gps = b.getValue("port", 0, &gok); + if (ok || gok) { + if (gok && !ok) ps = gps; + if (gok && ok && (ps != gps)) { + piCoutObj << "Ambiguous send port in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + type_send = PIProtocol::Ethernet; + if (eth == 0) eth = new PIEthernet(); + eth->setName("__S__PIProtocol::eth"); + setSenderAddress(dev, ps); + //setReceiverAddress(dev, ps); + has_dev = true; + flag = sb.getValue("reconnectEnabled", true, &ok); + gflag = b.getValue("reconnectEnabled", true, &gok); + if (ok || gok) { + if (gok && !ok) flag = gflag; + if (gok && ok && (flag != gflag)) { + piCoutObj << "Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + eth->setReopenEnabled(flag); + } + freq = sb.getValue("reconnectTimeout", 1., &ok); + gfreq = b.getValue("reconnectTimeout", 1., &gok); + if (ok || gok) { + if (gok && !ok) freq = gfreq; + if (gok && ok && (freq != gfreq)) { + piCoutObj << "Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + eth->setReopenTimeout(freq * 1000); + } + /*if (sendDataPtr_ == 0) + piCoutObj << "Warning: null send data pointer!"; + if (sendDataSize_ == 0) + piCoutObj << "Warning: null send data size!";*/ + } else { + piCoutObj << "Can`t find \"" << name() << ".sender.port\" or \"" << name() << ".port\" in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + } + dev = sb.getValue("device", "", &ok); + gdev = b.getValue("device", "", &gok); + if (ok || gok) { + if (gok && !ok) dev = gdev; + if (gok && ok && (dev != gdev)) { + piCoutObj << "Ambiguous sender type in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + ps = sb.getValue("speed", 0, &ok); + gps = b.getValue("speed", 0, &gok); + if (ok || gok) { + if (gok && !ok) ps = gps; + if (gok && ok && (ps != gps)) { + piCoutObj << "Ambiguous send \"speed\" in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + flag = sb.getValue("parity", false, &ok); + gflag = b.getValue("parity", false, &gok); + if (ok || gok) { + if (gok && !ok) flag = gflag; + if (gok && ok && (flag != gflag)) { + piCoutObj << "Ambiguous send \"parity\" in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + pp.setFlag(PISerial::ParityControl, flag); + } + flag = sb.getValue("twoStopBits", false, &ok); + gflag = b.getValue("twoStopBits", false, &gok); + if (ok || gok) { + if (gok && !ok) flag = gflag; + if (gok && ok && (flag != gflag)) { + piCoutObj << "Ambiguous send \"twoStopBits\" parity in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + pp.setFlag(PISerial::TwoStopBits, flag); + } + } else { + piCoutObj << "Can`t find \"" << name() << ".sender.speed\" or \"" << name() << ".speed\" in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + type_send = PIProtocol::Serial; + if (ser == 0) ser = new PISerial(dev); + ser->setName("__S__PIProtocol::ser"); + setSenderDevice(dev, (PISerial::Speed)ps); + ser->setOutSpeed((PISerial::Speed)ps); + ser->setParameters(pp); + has_dev = true; + /*if (sendDataPtr_ == 0) + piCoutObj << "Warning: null send data pointer!"; + if (sendDataSize_ == 0) + piCoutObj << "Warning: null send data size!";*/ + } + freq = sb.getValue("frequency", -1.f, &ok); + gfreq = b.getValue("frequency", -1.f, &gok); + if (gok && !ok) freq = gfreq; + if (gok && ok && (freq != gfreq)) { + piCoutObj << "Ambiguous sender frequency in \"" << config << "\"!"; + devSenderState = "Config error"; + return; + } + if (freq > 0.f && !has_dev) + piCoutObj << "Warning: no sender device and not null send frequency!"; + setSenderFrequency(freq); +} + + +void PIProtocol::init_receiver(PIConfig::Entry & b, PIConfig::Entry & rb, const PIString & config) { + int ps, gps; + bool ok, gok, flag, gflag, has_dev = false; + float freq, gfreq; + PIFlags pp(0); + PIString dev, gdev; + + if (rb.isEntryExists("ip") && rb.isEntryExists("device")) { + piCoutObj << "Ambiguous receiver type in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + dev = rb.getValue("ip", "", &ok); + gdev = b.getValue("ip", "", &gok); + if (ok || gok) { + if (gok && !ok) dev = gdev; + if (gok && ok && (dev != gdev)) { + piCoutObj << "Ambiguous receiver type in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + ps = rb.getValue("port", 0, &ok); + gps = b.getValue("port", 0, &gok); + if (ok || gok) { + if (gok && !ok) ps = gps; + if (gok && ok && (ps != gps)) { + piCoutObj << "Ambiguous receive port in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + type_rec = PIProtocol::Ethernet; + eth = new PIEthernet(); + eth->setName("__S__PIProtocol::eth"); + packet_ext->setDevice(eth); + //setSenderAddress(dev, ps); + setReceiverAddress(dev, ps); + has_dev = true; + flag = rb.getValue("reconnectEnabled", true, &ok); + gflag = b.getValue("reconnectEnabled", true, &gok); + if (ok || gok) { + if (gok && !ok) flag = gflag; + if (gok && ok && (flag != gflag)) { + piCoutObj << "Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + eth->setReopenEnabled(flag); + } + freq = rb.getValue("reconnectTimeout", 1., &ok); + gfreq = b.getValue("reconnectTimeout", 1., &gok); + if (ok || gok) { + if (gok && !ok) freq = gfreq; + if (gok && ok && (freq != gfreq)) { + piCoutObj << "Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + eth->setReopenTimeout(freq * 1000); + } + /*if (recDataPtr == 0) + piCoutObj << "Warning: null receive data pointer!"; + if (recDataSize == 0) + piCoutObj << "Warning: null receive data size!";*/ + } else { + piCoutObj << "Can`t find \"" << name() << ".receiver.port\" or \"" << name() << ".port\" in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + } + dev = rb.getValue("device", "", &ok); + gdev = b.getValue("device", "", &gok); + if (ok || gok) { + if (gok && !ok) dev = gdev; + if (gok && ok && (dev != gdev)) { + piCoutObj << "Ambiguous receiver type in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + ps = rb.getValue("speed", 0, &ok); + gps = b.getValue("speed", 0, &gok); + if (ok || gok) { + if (gok && !ok) ps = gps; + if (gok && ok && (ps != gps)) { + piCoutObj << "Ambiguous receive \"speed\" in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + flag = rb.getValue("parity", false, &ok); + gflag = b.getValue("parity", false, &gok); + if (ok || gok) { + if (gok && !ok) flag = gflag; + if (gok && ok && (flag != gflag)) { + piCoutObj << "Ambiguous receive \"parity\" in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + pp.setFlag(PISerial::ParityControl, flag); + } + flag = rb.getValue("twoStopBits", false, &ok); + gflag = b.getValue("twoStopBits", false, &gok); + if (ok || gok) { + if (gok && !ok) flag = gflag; + if (gok && ok && (flag != gflag)) { + piCoutObj << "Ambiguous receive \"twoStopBits\" parity in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + pp.setFlag(PISerial::TwoStopBits, flag); + } + type_rec = PIProtocol::Serial; + type_send = PIProtocol::Serial; + ser = new PISerial(dev); + ser->setName("__S__PIProtocol::ser"); + packet_ext->setDevice(ser); + //setSenderDevice(dev, (PISerial::Speed)ps); + setReceiverDevice(dev, (PISerial::Speed)ps); + ser->setInSpeed((PISerial::Speed)ps); + ser->setParameters(pp); + ps = rb.getValue("vtime", 1, &ok); + gps = b.getValue("vtime", 1, &gok); + if (ok || gok) { + if (gok && !ok) ps = gps; + if (gok && ok && (ps != gps)) { + piCoutObj << "Ambiguous receive \"vtime\" in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + ser->setVTime(ps); + } + has_dev = true; + /*if (recDataPtr == 0) + piCoutObj << "Warning: null receive data pointer!"; + if (recDataSize == 0) + piCoutObj << "Warning: null receive data size!";*/ + } else { + piCoutObj << "Can`t find \"" << name() << ".receiver.speed\" or \"" << name() << ".speed\" in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + } + freq = rb.getValue("frequency", -1.f, &ok); + gfreq = b.getValue("frequency", -1.f, &gok); + if (gok && !ok) freq = gfreq; + if (gok && ok && (freq != gfreq)) { + piCoutObj << "Ambiguous expected frequency in \"" << config << "\"!"; + devReceiverState = "Config error"; + return; + } + if (freq > 0.f && !has_dev) + piCoutObj << "Warning: no receiver device and not null expected frequency!"; + float tm = b.getValue("disconnectTimeout", 3.f); + if (tm <= 0.f) + piCoutObj << "Warning: diconnect timeout <= 0 s!"; + timeout_ = (tm < 0.f) ? 0.f : tm; + setExpectedFrequency(freq); +} + + +void PIProtocol::setReceiverDevice(const PIString & device, PISerial::Speed speed, bool force) { + if (force) { + type_send = type_rec = PIProtocol::Serial; + if (ser == 0) { + ser = new PISerial(); + ser->setName("__S__PIProtocol::ser"); + packet_ext->setDevice(ser); + } + } + if (type_rec == PIProtocol::Serial && ser != 0) { + ser->setDevice(device); + ser->setSpeed(speed); + devReceiverName = device; + devSenderName = device; + } +} + + +void PIProtocol::setReceiverAddress(const PIString & ip, int port, bool force) { + if (force) { + type_rec = PIProtocol::Ethernet; + if (eth == 0) { + eth = new PIEthernet(); + eth->setName("__S__PIProtocol::eth"); + packet_ext->setDevice(eth); + } + } + if (type_rec == PIProtocol::Ethernet && eth != 0) { + eth->setReadAddress(ip, port); + if (ip.trimmed().isEmpty()) devReceiverName = "no ip"; + else devReceiverName = ip + ":" + PIString::fromNumber(port); + } +} + + +void PIProtocol::setSenderDevice(const PIString & device, PISerial::Speed speed, bool force) { + if (force) { + type_send = type_rec = PIProtocol::Serial; + if (ser == 0) ser = new PISerial(); + ser->setName("__S__PIProtocol::ser"); + } + if (type_send == PIProtocol::Serial && ser != 0) { + ser->setDevice(device); + ser->setSpeed(speed); + ser->open(); + devSenderName = device; + } +} + + +void PIProtocol::setSenderAddress(const PIString & ip, int port, bool force) { + if (force) { + type_send = PIProtocol::Ethernet; + if (eth == 0) eth = new PIEthernet(); + eth->setName("__S__PIProtocol::eth"); + } + if (type_send == PIProtocol::Ethernet && eth != 0) { + eth->setSendAddress(ip, port); + if (ip.isEmpty()) devSenderName = "no ip"; + else devSenderName = ip + ":" + PIString::fromNumber(port); + } +} + + +void PIProtocol::setSenderIP(const PIString & ip, bool force) { + if (force) { + type_send = PIProtocol::Ethernet; + if (eth == 0) eth = new PIEthernet(); + } + if (type_send == PIProtocol::Ethernet && eth != 0) { + eth->setSendIP(ip); + if (ip.isEmpty()) devSenderName = "no ip"; + else devSenderName = ip + ":" + PIString::fromNumber(eth->sendPort()); + } +} + + +void PIProtocol::setSenderPort(int port, bool force) { + if (force) { + type_send = PIProtocol::Ethernet; + if (eth == 0) eth = new PIEthernet(); + eth->setName("__S__PIProtocol::eth"); + } + if (type_send == PIProtocol::Ethernet && eth != 0) { + eth->setSendPort(port); + if (eth->sendIP().isEmpty()) devSenderName = "no ip"; + else devSenderName = eth->sendIP() + ":" + PIString::fromNumber(port); + } +} + + +void PIProtocol::setExpectedFrequency(float frequency) { + exp_freq = frequency; + changeDisconnectTimeout(); +} + + +void PIProtocol::changeDisconnectTimeout() { + pckt_cnt_max = int(piRound(timeout_ * exp_freq)); + if (pckt_cnt_max < 3) pckt_cnt_max = 3; + last_packets.resize(pckt_cnt_max); +} + + +void PIProtocol::startReceive(float exp_frequency) { + if (exp_frequency > 0.f) exp_freq = exp_frequency; + //if (type_rec == PIProtocol::Serial) ser->start(); + //if (type_rec == PIProtocol::Ethernet) eth->start(); + packet_ext->startThreadedRead(); + msleep(1); + check_state(); + if (exp_freq <= 0.f) return; + setExpectedFrequency(exp_freq); + diagTimer->start(1000. / exp_freq); + diag_tm.reset(); + receiverStarted(); +} + + +void PIProtocol::startSend(float frequency) { + //cout << "** start send " << send_freq << ", " << frequency << endl; + if (frequency > 0.f) send_freq = frequency; + msleep(1); + check_state(); + if (send_freq <= 0.f) return; + sendTimer->start(1000. / send_freq); + diag_tm.reset(); + senderStarted(); +} + + +void PIProtocol::stopReceive() { + //if (type_rec == PIProtocol::Serial) ser->stop(); + //if (type_rec == PIProtocol::Ethernet) eth->stop(); + packet_ext->stop(); + diagTimer->stop(); + receiverStopped(); +} + + +bool PIProtocol::receiveEvent(void * t, uchar * data, int size) { + PIProtocol * p = (PIProtocol * )t; + if (!p->receive(data, size)) return false; + p->work = true; + //p->lock(); + if (p->validate()) { + p->received(true); + //p->unlock(); + p->ifreq = p->diag_tm.elapsed_m(); + if (p->ifreq > 0.) p->ifreq = 1000. / p->ifreq; + p->diag_tm.reset(); + p->receive_count++; + p->packets_in_sec++; + p->bytes_in_sec += size; + p->cur_pckt = 1; + if (p->ret_func != 0) p->ret_func(p); + if (p->mp_owner != 0) PIMultiProtocolBase::receiveEvent(p->mp_owner, p, true, data, size); + return true; + } + p->received(false); + //p->unlock(); + p->wrong_count++; + if (p->mp_owner != 0) PIMultiProtocolBase::receiveEvent(p->mp_owner, p, false, data, size); + return false; +} + + +void PIProtocol::diagEvent(void * t, int) { + PIProtocol * p = (PIProtocol * )t; + p->calc_freq(); + p->calc_diag(); + p->check_state(); + if (p->ser != 0) p->missed_count = p->packet_ext->missedPackets(); +} + + +void PIProtocol::secEvent(void * t, int ) { + PIProtocol * p = (PIProtocol * )t; + p->speedIn = PIString::readableSize(p->bytes_in_sec) + "/s"; + p->speedOut = PIString::readableSize(p->bytes_out_sec) + "/s"; + p->bytes_in_sec = p->bytes_out_sec = p->packets_in_sec = p->packets_out_sec = 0; + if (p->ser != 0) p->missed_count = p->packet_ext->missedPackets(); +} + + +void PIProtocol::calc_diag() { + PIProtocol::Quality diag; + if (!work) { + diag = PIProtocol::Unknown; + return; + } + if (pckt_cnt < pckt_cnt_max) { + last_packets[pckt_cnt] = cur_pckt; + pckt_cnt++; + } else { + packets[(int)last_packets.back()]--; + if (!last_packets.isEmpty()) last_packets.pop_back(); + last_packets.push_front(cur_pckt); + } + packets[(int)cur_pckt]++; + cur_pckt = 0; + float good_percents; + good_percents = (float)packets[1] / pckt_cnt * 100.f; + if (good_percents == 0.f) diag = PIProtocol::Failure; + else if (good_percents <= 20.f) diag = PIProtocol::Bad; + else if (good_percents > 20.f && good_percents <= 80.f) diag = PIProtocol::Average; + else diag = PIProtocol::Good; + if (diag != net_diag) { + qualityChanged(diag, net_diag); + net_diag = diag; + } +} + + +void PIProtocol::calc_freq() { + float tf;// = float(1000.f / diagTimer->elapsed_m()); + tf = immediate_freq = ifreq; + ifreq = 0.f; + if (last_freq.size_s() >= pckt_cnt_max && last_freq.size_s() > 0) last_freq.pop_front(); + last_freq.push_back(tf); + tf = last_freq[0]; + for (uint i = 1; i < last_freq.size(); ++i) + tf += last_freq[i]; + integral_freq = tf / last_freq.size(); +} + + +void PIProtocol::check_state() { + if (type_rec == PIProtocol::Serial) { + if (ser != 0) { + if (ser->isOpened()) devReceiverState = "Opened"; + else devReceiverState = "Not opened"; + } + else devReceiverState = "Not exists"; + } + if (type_rec == PIProtocol::Ethernet) { + if (eth != 0) { + if (eth->isOpened()) devReceiverState = "Opened"; + else devReceiverState = "Not opened"; + } + else devReceiverState = "Not exists"; + } + if (type_send == PIProtocol::Serial) { + if (ser != 0) { + if (ser->isOpened()) devSenderState = "Opened"; + else devSenderState = "Not opened"; + } + else devSenderState = "Not exists"; + } + if (type_send == PIProtocol::Ethernet) { + if (eth != 0) { + if (eth->isOpened()) devSenderState = "Opened"; + else devSenderState = "Not opened"; + } + else devSenderState = "Not exists"; + } +} + + +void PIProtocol::send(const void * data, int size, bool direct) { + if (!direct) { + if (data == 0 || size == 0) return; + if (!aboutSend()) return; + } + if (type_send == PIProtocol::Serial) + if (ser->send(data, size)) { + send_count++; + packets_out_sec++; + bytes_out_sec += size; + } + if (type_send == PIProtocol::Ethernet) + if (eth->send(data, size)) { + send_count++; + packets_out_sec++; + bytes_out_sec += size; + } +} + + +void PIProtocol::send() { + //lock(); + //memcpy(packet, sendDataPtr, sendDataSize); + //unlock(); + if (!aboutSend()) return; + if (sendDataPtr == 0 || sendDataSize == 0) return; + if (type_send == PIProtocol::Serial) + if (ser->send(sendDataPtr, sendDataSize)) { + send_count++; + packets_out_sec++; + bytes_out_sec += sendDataSize; + } + if (type_send == PIProtocol::Ethernet) + if (eth->send(sendDataPtr, sendDataSize)) { + send_count++; + packets_out_sec++; + bytes_out_sec += sendDataSize; + } +} diff --git a/kx_utils/piprotocol.h b/kx_utils/piprotocol.h new file mode 100644 index 0000000..e5ebca8 --- /dev/null +++ b/kx_utils/piprotocol.h @@ -0,0 +1,238 @@ +/*! \file piprotocol.h + * \brief Highly configurable from file I/O channel +*/ +/* + PIP - Platform Independent Primitives + Protocol, input/output channel (COM, UDP) + Copyright (C) 2018 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 General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PIPROTOCOL_H +#define PIPROTOCOL_H + +#include "piserial.h" +#include "piethernet.h" +#include "pipacketextractor.h" +#include "pitimer.h" +#include "piconfig.h" +#include "pifile.h" + +class PIProtocol; /// DEPRECATED + +class PIP_EXPORT PIMultiProtocolBase: protected PIObject /// DEPRECATED +{ + PIOBJECT_SUBCLASS(PIMultiProtocolBase, PIObject) + friend class PIProtocol; +public: + PIMultiProtocolBase() {;} /// DEPRECATED + virtual ~PIMultiProtocolBase() {;} + +protected: + virtual void received(PIProtocol * prot, bool corrected, uchar * data, int size) {;} + +private: + static void receiveEvent(PIMultiProtocolBase * p, PIProtocol * prot, bool corrected, uchar * data, int size) {p->mutex_receive.lock(); p->received(prot, corrected, data, size); p->mutex_receive.unlock();} + + PIMutex mutex_receive; + +}; + +typedef void (*ReceiveFunc)(void * ); + +/// events: +/// void receiverStarted() +/// void receiverStopped() +/// void senderStarted() +/// void senderStopped() +/// void received(bool validate_is_ok) +/// void qualityChanged(PIProtocol::Quality old_quality, PIProtocol::Quality new_quality) +/// +/// handlers: +/// void startReceive(float exp_frequency = -1.f) +/// void stopReceive() +/// void startSend(float frequency = -1.f) +/// void stopSend() +/// void start() +/// void stop() +/// void send() +/// void send(const void * data, int size, bool direct = false) +class PIP_EXPORT PIProtocol: public PIObject /// DEPRECATED +{ + PIOBJECT_SUBCLASS(PIProtocol, PIObject) + friend class PIMultiProtocolBase; + friend class PIMultiProtocol; + enum Type {None, Serial, Ethernet}; +public: + + //! Contructs an empty unconfigured protocol + PIProtocol(): PIObject() {init();} /// DEPRECATED + + //! Contructs protocol configured from file "config", config file section "name" + PIProtocol(const PIString & config, const PIString & name, void * recHeaderPtr = 0, int recHeaderSize = 0, + void * recDataPtr = 0, int recDataSize = 0, void * sendDataPtr = 0, int sendDataSize = 0); // from config + + virtual ~PIProtocol(); + + //! Connection quality + enum Quality { + 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, + Average /** Average connection, correct packets received > 20% and <= 80% */ = 4, + Good /** Good connection, correct packets received > 80% */ = 5 + }; + + EVENT_HANDLER0(void, startReceive) {startReceive(-1.f);} + EVENT_HANDLER1(void, startReceive, float, exp_frequency); // if "frequency = -1" used last passed value + EVENT_HANDLER0(void, stopReceive); + void setExpectedFrequency(float frequency); // for connection quality diagnostic + void setReceiverDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial + void setReceiverData(void * dataPtr, int dataSize) {this->dataPtr = (uchar * )dataPtr; this->dataSize = dataSize; packet_ext->setHeader(PIByteArray(headerPtr, headerSize)); packet_ext->setPayloadSize(dataSize); packet_ext->setPacketSize(dataSize);} + void setReceiverDataHeader(void * headerPtr, int headerSize) {this->headerPtr = (uchar * )headerPtr; this->headerSize = headerSize; packet_ext->setHeader(PIByteArray(headerPtr, headerSize)); packet_ext->setPayloadSize(dataSize); packet_ext->setPacketSize(dataSize);} + void setReceiverAddress(const PIString & ip, int port, bool force = false); // for Ethernet + void setReceiverParameters(PIFlags parameters) {if (type_rec == PIProtocol::Serial || type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial + void setReceiveSlot(ReceiveFunc slot) {ret_func = slot;} + float expectedFrequency() const {return exp_freq;} + + EVENT_HANDLER0(void, startSend) {startSend(-1.f);} // if "frequency = -1" used last passed value + EVENT_HANDLER1(void, startSend, float, frequency); // if "frequency = -1" used last passed value + EVENT_HANDLER0(void, stopSend) {sendTimer->stop(); senderStopped();} + void setSenderFrequency(float frequency) {send_freq = frequency;} + void setSenderDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial + void setSenderData(void * dataPtr, int dataSize) {sendDataPtr = (uchar * )dataPtr; sendDataSize = dataSize;} + void setSenderAddress(const PIString & ip, int port, bool force = false); // for Ethernet + void setSenderIP(const PIString & ip, bool force = false); // for Ethernet + void setSenderPort(int port, bool force = false); // for Ethernet + void setSenderParameters(PIFlags parameters) {if (type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial + float senderFrequency() const {return send_freq;} + + EVENT_HANDLER0(void, start) {startReceive(); startSend();} + EVENT_HANDLER0(void, stop) {stopReceive(); stopSend();} + EVENT_HANDLER0(void, send); + EVENT_HANDLER2(void, send, const void *, data, int, size) {send(data, size, false);} + EVENT_HANDLER3(void, send, const void *, data, int, size, bool, direct); + + void setName(const PIString & name) {protName = name; PIObject::setName(name);} + PIString name() const {return protName;} + void setDisconnectTimeout(float timeout) {timeout_ = timeout; changeDisconnectTimeout();} + float disconnectTimeout() const {return timeout_;} + const float * disconnectTimeout_ptr() const {return &timeout_;} + float immediateFrequency() const {return immediate_freq;} + float integralFrequency() const {return integral_freq;} + const float * immediateFrequency_ptr() const {return &immediate_freq;} + const float * integralFrequency_ptr() const {return &integral_freq;} + ullong receiveCountPerSec() const {return packets_in_sec;} + const ullong * receiveCountPerSec_ptr() const {return &packets_in_sec;} + ullong sendCountPerSec() const {return packets_out_sec;} + const ullong * sendCountPerSec_ptr() const {return &packets_out_sec;} + ullong receiveBytesPerSec() const {return bytes_in_sec;} + const ullong * receiveBytesPerSec_ptr() const {return &bytes_in_sec;} + ullong sendBytesPerSec() const {return bytes_out_sec;} + const ullong * sendBytesPerSec_ptr() const {return &bytes_out_sec;} + ullong receiveCount() const {return receive_count;} + const ullong * receiveCount_ptr() const {return &receive_count;} + ullong wrongCount() const {return wrong_count;} + const ullong * wrongCount_ptr() const {return &wrong_count;} + ullong sendCount() const {return send_count;} + const ullong * sendCount_ptr() const {return &send_count;} + ullong missedCount() const {return missed_count;} + const ullong * missedCount_ptr() const {return &missed_count;} + PIProtocol::Quality quality() const {return net_diag;} // receive quality + const int * quality_ptr() const {return (int * )&net_diag;} // receive quality pointer + PIString receiverDeviceName() const {return devReceiverName;} + PIString senderDeviceName() const {return devSenderName;} + PIString receiverDeviceState() const {return devReceiverState;} + const PIString * receiverDeviceState_ptr() const {return &devReceiverState;} + PIString senderDeviceState() const {return devSenderState;} + const PIString * senderDeviceState_ptr() const {return &devSenderState;} + PIString receiveSpeed() const {return speedIn;} + const PIString * receiveSpeed_ptr() const {return &speedIn;} + PIString sendSpeed() const {return speedOut;} + const PIString * sendSpeed_ptr() const {return &speedOut;} + + void * receiveData() {return dataPtr;} + void * sendData() {return sendDataPtr;} + + PIPacketExtractor * packetExtractor() {return packet_ext;} +// PIByteArray lastHeader() {return packet_ext->lastHeader();} + + EVENT0(receiverStarted) + EVENT0(receiverStopped) + EVENT0(senderStarted) + EVENT0(senderStopped) + EVENT1(received, bool, validate_is_ok) + EVENT2(qualityChanged, PIProtocol::Quality, new_quality, PIProtocol::Quality, old_quality) + +protected: + virtual bool receive(uchar * data, int size) {if (dataPtr != 0) memcpy(dataPtr, data, size); return true;} // executed when raw data received, break if 'false' return + virtual bool validate() {return true;} // function for validate algorithm and save data from dataPtr to external struct + virtual bool headerValidate(uchar * src, uchar * rec, int size) {for (int i = 0; i < size; ++i) if (src[i] != rec[i]) return false; return true;} // function for validate header (COM-port and headerSize > 0) + virtual uint checksum_i(void * data, int size) { // function for checksum (uint) + uint c = 0; + for (int i = 0; i < size; ++i) + c += ((uchar*)data)[i]; + return ~(c + 1); + } + virtual uchar checksum_c(void * data, int size) { // function for checksum (uchar) + uchar c = 0; + for (int i = 0; i < size; ++i) + c += ((uchar*)data)[i]; + return ~(c + 1); + } + virtual bool aboutSend() {return true;} // executed before send data, if return 'false' then data is not sending + + void init(); + void init_sender(PIConfig::Entry & b, PIConfig::Entry & sb, const PIString & config); + void init_receiver(PIConfig::Entry & b, PIConfig::Entry & rb, const PIString & config); + void check_state(); + void calc_freq(); + void calc_diag(); + + PISerial * ser; + PIEthernet * eth; + uint dataSize, headerSize, sendDataSize; + uchar * dataPtr, * headerPtr, * sendDataPtr; + +private: + static void sendEvent(void * e, int) {((PIProtocol * )e)->send();} + static bool receiveEvent(void * t, uchar * data, int size); + static bool headerValidateEvent(void * t, uchar * src, uchar * rec, int size) {return ((PIProtocol * )t)->headerValidate(src, rec, size);} + static void diagEvent(void * t, int); + static void secEvent(void * t, int); + + void setMultiProtocolOwner(PIMultiProtocolBase * mp) {mp_owner = mp;} + PIMultiProtocolBase * multiProtocolOwner() const {return mp_owner;} + void changeDisconnectTimeout(); + + ReceiveFunc ret_func; + PIPacketExtractor * packet_ext; + PITimer * diagTimer, * sendTimer, * secTimer; + PITimeMeasurer diag_tm; + PIMultiProtocolBase * mp_owner; + PIProtocol::Type type_send, type_rec; + PIProtocol::Quality net_diag; + PIDeque last_freq; + PIDeque last_packets; + PIString protName, devReceiverName, devReceiverState, devSenderName, devSenderState, speedIn, speedOut; + bool work, new_mp_prot; + float exp_freq, send_freq, ifreq, immediate_freq, integral_freq, timeout_; + int packets[2], pckt_cnt, pckt_cnt_max; + char cur_pckt; + ullong wrong_count, receive_count, send_count, missed_count, packets_in_sec, packets_out_sec, bytes_in_sec, bytes_out_sec; + +}; + +#endif // PIPROTOCOL_H diff --git a/piqt_utils/CMakeLists.txt b/piqt_utils/CMakeLists.txt index 1849460..c105be4 100644 --- a/piqt_utils/CMakeLists.txt +++ b/piqt_utils/CMakeLists.txt @@ -24,7 +24,7 @@ list(APPEND QT_MULTILIB_LIST ${PROJECT_NAME}) set(QT_MULTILIB_LIST ${QT_MULTILIB_LIST} PARENT_SCOPE) include_directories(${PIP_INCLUDES} ${QAD_INCLUDES}) file(GLOB SRC "*.h" "*.cpp" "*.ui" "*.qrc" "lang/*.ts") -pip_code_model(CCM "../pip/src_main/io/piiodevice.h" "../pip/src_main/io/pipacketextractor.h" OPTIONS "-DPIP_EXPORT" "-Es") +pip_code_model(CCM "../pip/src_main/io_devices/piiodevice.h" "../pip/src_main/io_utils/pipacketextractor.h" OPTIONS "-DPIP_EXPORT" "-Es") find_qt(${QtVersions} Core Gui) qt_wrap(${SRC} HDRS out_HDR CPPS out_CPP QMS out_QM) qt_add_library(${PROJECT_NAME} ${LIBTYPE} out_CPP CCM)