23.06.2014 - PICodeParser, PICodeInfo, PIConnection, new binary "pip_cmg"
This commit is contained in:
764
piconnection.cpp
Normal file
764
piconnection.cpp
Normal file
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piconnection.h"
|
||||
#include "piconfig.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_config Configuration
|
||||
* You can create %PIConnection from config file section or configure
|
||||
* it later with function \a configureFromConfig(). Devices describes
|
||||
* with its full pathes, for details see \ref PIIODevice_sec7. Example:
|
||||
* \image html piconnection_conf.png
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
PIVector<PIConnection * > PIConnection::_connections;
|
||||
|
||||
|
||||
PIConnection::PIConnection(): PIObject() {
|
||||
_connections << this;
|
||||
}
|
||||
|
||||
|
||||
PIConnection::PIConnection(const PIString & config, const PIString & name_): PIObject(name_) {
|
||||
_connections << this;
|
||||
configureFromConfig(config, name_);
|
||||
}
|
||||
|
||||
|
||||
PIConnection::~PIConnection() {
|
||||
__device_pool__->unboundConnection(this);
|
||||
removeAllFilters();
|
||||
_connections.removeAll(this);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::configureFromConfig(const PIString & conf_path, const PIString & name_) {
|
||||
PIConfig conf(conf_path, PIIODevice::ReadOnly);
|
||||
if (!conf.isOpened()) return false;
|
||||
__device_pool__->unboundConnection(this);
|
||||
removeAllChannels();
|
||||
removeAllFilters();
|
||||
removeAllDevices();
|
||||
setName(name_);
|
||||
PIConfig::Entry ce(conf.getValue(name_));
|
||||
PIConfig::Branch db(ce.getValue("device").children()), fb(ce.getValue("filter").children()), cb(ce.getValue("channel").children());
|
||||
PIStringList dev_list(ce.getValue("device").value());
|
||||
piForeachC (PIConfig::Entry * e, db)
|
||||
dev_list << e->value();
|
||||
dev_list.removeStrings("");
|
||||
piForeachC (PIString & s, dev_list) {
|
||||
PIString fn(s);
|
||||
PIIODevice::DeviceMode dm = PIIODevice::ReadWrite;
|
||||
if (fn.find("(") > 0 && fn.find(")") > 0) {
|
||||
PIString dms(fn.right(fn.length() - fn.find("(")).takeRange("(", ")").trim().toLowerCase().removeAll(" "));
|
||||
//piCout << dms;
|
||||
if (dms == "r" || dms == "ro" || dms == "read" || dms == "readonly")
|
||||
dm = PIIODevice::ReadOnly;
|
||||
if (dms == "w" || dms == "wo" || dms == "write" || dms == "writeonly")
|
||||
dm = PIIODevice::WriteOnly;
|
||||
fn.cutRight(fn.length() - fn.find("(") + 1).trim();
|
||||
}
|
||||
//piCout << fn;
|
||||
PIIODevice * dev = addDevice(fn, dm);
|
||||
if (dev) dev->setName(name_ + ".device." + s);
|
||||
}
|
||||
piForeachC (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;
|
||||
else {
|
||||
sms = sms.trim().toLowerCase();
|
||||
if (sms.find("header") >= 0 && sms.find("footer") >= 0)
|
||||
sm = PIPacketExtractor::HeaderAndFooter;
|
||||
else {
|
||||
if (sms.find("header") >= 0)
|
||||
sm = PIPacketExtractor::Header;
|
||||
else {
|
||||
if (sms.find("footer") >= 0)
|
||||
sm = PIPacketExtractor::Footer;
|
||||
else {
|
||||
if (sms.find("time") >= 0)
|
||||
sm = PIPacketExtractor::Timeout;
|
||||
else {
|
||||
if (sms.find("size") >= 0)
|
||||
sm = PIPacketExtractor::Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PIStringList devs(e->value());
|
||||
PIConfig::Branch db(e->getValue("device").children());
|
||||
piForeachC (PIConfig::Entry * e2, db)
|
||||
devs << e2->value();
|
||||
devs.removeStrings("");
|
||||
if (devs.isEmpty()) continue;
|
||||
PIPacketExtractor * pe = addFilter(e->name(), devs.front(), sm);
|
||||
if (pe == 0) continue;
|
||||
for (int i = 1; i < devs.size_s(); ++i)
|
||||
addFilter(e->name(), devs[i], sm);
|
||||
pe->setPayloadSize(e->getValue("payloadSize", pe->payloadSize()));
|
||||
pe->setPacketSize(e->getValue("packetSize", pe->packetSize()));
|
||||
pe->setTimeout(e->getValue("timeout", pe->timeout()));
|
||||
pe->setHeader(PIByteArray::fromString(e->getValue("header", "").value()));
|
||||
pe->setFooter(PIByteArray::fromString(e->getValue("footer", "").value()));
|
||||
}
|
||||
piForeachC (PIConfig::Entry * e, cb) {
|
||||
PIString f(e->getValue("from").value()), t(e->getValue("to").value());
|
||||
addChannel(f, t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PIConnection::makeConfig() const {
|
||||
PIString ret;
|
||||
ret << "[" << name() << "]\n";
|
||||
PIVector<PIIODevice * > devs(boundedDevices());
|
||||
int dn(0);
|
||||
piForeachC (PIIODevice * d, devs) {
|
||||
ret << "device." << dn << " = " << d->constructFullPath(); ++dn;
|
||||
if (d->mode() == PIIODevice::ReadOnly) ret << " (ro)";
|
||||
if (d->mode() == PIIODevice::WriteOnly) ret << " (wo)";
|
||||
ret << "\n";
|
||||
}
|
||||
piForeachC (PEPair & f, extractors) {
|
||||
if (f.second == 0) continue;
|
||||
if (f.second->extractor == 0) continue;
|
||||
PIString prefix = "filter." + f.first;
|
||||
for (int i = 0; i < f.second->devices.size_s(); ++i)
|
||||
ret << prefix << ".device." << i << " = " << f.second->devices[i]->constructFullPath() << "\n";
|
||||
ret << prefix << ".splitMode = ";
|
||||
switch (f.second->extractor->splitMode()) {
|
||||
case PIPacketExtractor::None: ret << "none"; break;
|
||||
case PIPacketExtractor::Header: ret << "header"; break;
|
||||
case PIPacketExtractor::Footer: ret << "footer"; break;
|
||||
case PIPacketExtractor::HeaderAndFooter: ret << "header & footer"; break;
|
||||
case PIPacketExtractor::Size: ret << "size"; break;
|
||||
case PIPacketExtractor::Timeout: ret << "timeout"; break;
|
||||
}
|
||||
ret << "\n";
|
||||
ret << prefix << ".payloadSize = " << f.second->extractor->payloadSize() << "\n";
|
||||
ret << prefix << ".packetSize = " << f.second->extractor->packetSize() << "\n";
|
||||
ret << prefix << ".timeout = " << f.second->extractor->timeout() << "\n";
|
||||
ret << prefix << ".header = " << f.second->extractor->header().toString() << "\n";
|
||||
ret << prefix << ".footer = " << f.second->extractor->footer().toString() << "\n";
|
||||
}
|
||||
dn = 0;
|
||||
piForeachC (CPair & c, channels_) {
|
||||
piForeachC (PIIODevice * d, c.second) {
|
||||
PIString prefix = "channel." + PIString::fromNumber(dn); ++dn;
|
||||
ret << prefix << ".from = " << devPath(c.first) << "\n";
|
||||
ret << prefix << ".to = " << devPath(d) << "\n";
|
||||
}
|
||||
}
|
||||
ret << "[]\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIConnection::addDevice(const PIString & full_path, PIIODevice::DeviceMode mode, bool start) {
|
||||
PIIODevice * dev = __device_pool__->addDevice(this, full_path, mode, start);
|
||||
if (dev) {
|
||||
dev->setName(name() + ".device." + full_path);
|
||||
device_modes[dev] = mode;
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeDevice(const PIString & full_path) {
|
||||
PIIODevice * dev = __device_pool__->device(full_path);
|
||||
if (dev == 0) return false;
|
||||
device_modes.remove(dev);
|
||||
piForeachC (PEPair & i, extractors) {
|
||||
if (i.second == 0) continue;
|
||||
i.second->devices.removeAll(dev);
|
||||
}
|
||||
bounded_extractors.remove(dev);
|
||||
channels_.remove(dev);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(dev);
|
||||
return __device_pool__->removeDevice(this, full_path);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::removeAllDevices() {
|
||||
PIVector<PIIODevice * > bdevs(__device_pool__->boundedDevices(this));
|
||||
piForeach (PIIODevice * d, bdevs) {
|
||||
channels_.remove(d);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(d);
|
||||
}
|
||||
__device_pool__->unboundConnection(this);
|
||||
device_modes.clear();
|
||||
bounded_extractors.clear();
|
||||
piForeachC (PEPair & i, extractors) {
|
||||
if (i.second == 0) continue;
|
||||
i.second->devices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIConnection::device(const PIString & full_path) const {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(full_path);
|
||||
if (dd == 0) return 0;
|
||||
if (dd->dev == 0) return 0;
|
||||
if (!dd->listeners.contains(const_cast<PIConnection * >(this))) return 0;
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::boundedDevices() const {
|
||||
return __device_pool__->boundedDevices(this);
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIString & full_path, PIPacketExtractor::SplitMode mode) {
|
||||
Extractor * e = extractors.value(name_);
|
||||
PIIODevice * dev = __device_pool__->device(full_path);
|
||||
if (dev == 0) {
|
||||
piCoutObj << "\"addPacketExtractor\" error: no such device \"" << full_path << "\"!";
|
||||
return 0;
|
||||
}
|
||||
if (e == 0) {
|
||||
e = new Extractor();
|
||||
extractors[name_] = e;
|
||||
}
|
||||
if (e->extractor == 0) {
|
||||
e->extractor = new PIPacketExtractor(0, mode);
|
||||
e->extractor->setName(name_);
|
||||
e->extractor->setThreadedReadData(new PIPair<PIConnection * , PIString>(this, name_));
|
||||
e->extractor->setHeaderCheckSlot(filterValidateHeaderS);
|
||||
e->extractor->setFooterCheckSlot(filterValidateFooterS);
|
||||
e->extractor->setPayloadCheckSlot(filterValidatePayloadS);
|
||||
CONNECT2(void, uchar * , int, e->extractor, packetReceived, this, packetExtractorReceived)
|
||||
}
|
||||
if (!e->devices.contains(dev)) {
|
||||
bounded_extractors[dev] << e->extractor;
|
||||
e->devices << dev;
|
||||
}
|
||||
return e->extractor;
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIIODevice * dev, PIPacketExtractor::SplitMode mode) {
|
||||
if (dev == 0) return 0;
|
||||
PIString fp;
|
||||
if (dev->isPropertyExists("__fullPath__")) fp = dev->property("__fullPath__").toString();
|
||||
fp = dev->constructFullPath();
|
||||
return addFilter(name_, fp, mode);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeFilter(const PIString & name_, const PIString & full_path) {
|
||||
Extractor * p = extractors.value(name_);
|
||||
if (p == 0) return false;
|
||||
bool ret = false;
|
||||
for (int i = 0; i < p->devices.size_s(); ++i) {
|
||||
if (p->devices[i]->property("__fullPath__").toString() == full_path) {
|
||||
bounded_extractors[p->devices[i]].removeAll(p->extractor);
|
||||
p->devices.remove(i);
|
||||
--i;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
if (p->devices.isEmpty()) {
|
||||
unboundExtractor(p->extractor);
|
||||
delete p;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeFilter(const PIString & name, const PIIODevice * dev) {
|
||||
if (dev == 0) return false;
|
||||
return removeFilter(name, dev->property("__fullPath__").toString());
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeFilter(const PIString & name_) {
|
||||
Extractor * p = extractors.value(name_);
|
||||
if (p == 0) return false;
|
||||
unboundExtractor(p->extractor);
|
||||
delete p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::removeAllFilters() {
|
||||
piForeachC (PEPair & i, extractors) {
|
||||
if (i.second == 0) continue;
|
||||
channels_.remove(i.second->extractor);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(i.second->extractor);
|
||||
delete i.second;
|
||||
}
|
||||
extractors.clear();
|
||||
bounded_extractors.clear();
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIPacketExtractor * > PIConnection::filters() const {
|
||||
PIVector<PIPacketExtractor * > ret;
|
||||
piForeachC (PEPair & i, extractors)
|
||||
if (i.second != 0)
|
||||
if (i.second->extractor != 0) ret << i.second->extractor;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIConnection::filterNames() const {
|
||||
PIStringList ret;
|
||||
piForeachC (PEPair & i, extractors)
|
||||
if (i.second != 0)
|
||||
if (i.second->extractor != 0) ret << i.first;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::filter(const PIString & name) const {
|
||||
piForeachC (PEPair & i, extractors)
|
||||
if (i.second != 0)
|
||||
if (i.second->extractor != 0 && i.first == name)
|
||||
return i.second->extractor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::filterBoundedDevices(const PIString & name_) const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
Extractor * p = extractors.value(name_);
|
||||
if (p == 0) return ret;
|
||||
return p->devices;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::addChannel(const PIString & name0, const PIString & name1) {
|
||||
//piCout << "addChannel" << name0 << name1;
|
||||
if (name0.isEmpty() || name1.isEmpty()) return false;
|
||||
PIIODevice * dev0 = device(name0), * dev1 = device(name1);
|
||||
PIPacketExtractor * pe0(0), * pe1(0);
|
||||
if (extractors.value(name0) != 0) pe0 = extractors.value(name0)->extractor;
|
||||
if (extractors.value(name1) != 0) pe1 = extractors.value(name1)->extractor;
|
||||
if (pe0 != 0) dev0 = pe0;
|
||||
if (pe1 != 0) dev1 = pe1;
|
||||
if (dev0 == 0 || dev1 == 0) {
|
||||
if (dev0 == 0) piCoutObj << "\"addChannel\" error: no such device \"" << name0 << "\"!";
|
||||
if (dev1 == 0) piCoutObj << "\"addChannel\" error: no such device \"" << name1 << "\"!";
|
||||
return false;
|
||||
}
|
||||
if (!channels_[dev0].contains(dev1))
|
||||
channels_[dev0] << dev1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeChannel(const PIString & name0, const PIString & name1) {
|
||||
PIIODevice * dev0 = device(name0), * dev1 = device(name1);
|
||||
PIPacketExtractor * pe0(0), * pe1(0);
|
||||
if (extractors.value(name0) != 0) pe0 = extractors.value(name0)->extractor;
|
||||
if (extractors.value(name1) != 0) pe1 = extractors.value(name1)->extractor;
|
||||
if (pe0 != 0) dev0 = pe0;
|
||||
if (pe1 != 0) dev1 = pe1;
|
||||
if (dev0 == 0 || dev1 == 0) return false;
|
||||
channels_[dev0].removeAll(dev1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeChannel(const PIString & name0) {
|
||||
PIIODevice * dev0 = device(name0);
|
||||
PIPacketExtractor * pe0(0);
|
||||
if (extractors.value(name0) != 0) pe0 = extractors.value(name0)->extractor;
|
||||
if (pe0 != 0) dev0 = pe0;
|
||||
if (dev0 == 0) return false;
|
||||
channels_.remove(dev0);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(dev0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::removeAllChannels() {
|
||||
channels_.clear();
|
||||
}
|
||||
|
||||
|
||||
PIString PIConnection::devPath(const PIIODevice * d) const {
|
||||
if (d == 0) return PIString();
|
||||
if (strcmp(d->className(), "PIPacketExtractor") == 0) return d->name();
|
||||
return d->constructFullPath();
|
||||
}
|
||||
|
||||
|
||||
PIString PIConnection::devFPath(const PIIODevice * d) const {
|
||||
if (d == 0) return PIString();
|
||||
if (d->isPropertyExists("__fullPath__")) return d->property("__fullPath__").toString();
|
||||
return d->name();
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIPair<PIString, PIString > > PIConnection::channels() const {
|
||||
PIVector<PIPair<PIString, PIString > > ret;
|
||||
piForeachC (CPair & i, channels_) {
|
||||
PIString fp0(devFPath(i.first));
|
||||
piForeachC (PIIODevice * d, i.second)
|
||||
ret << PIPair<PIString, PIString>(fp0, devFPath(d));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::startThreadedRead(const PIString & full_path) {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(full_path, 0);
|
||||
if (dd == 0) return;
|
||||
if (dd->dev == 0) return;
|
||||
if (dd->started || dd->dev->mode() == PIIODevice::WriteOnly) return;
|
||||
dd->rthread->start();
|
||||
dd->started = true;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::startAllThreadedReads() {
|
||||
piForeachC (DevicePool::DDPair & d, __device_pool__->devices)
|
||||
startThreadedRead(d.first);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::stopThreadedRead(const PIString & full_path) {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(full_path, 0);
|
||||
if (dd == 0) return;
|
||||
if (dd->dev == 0) return;
|
||||
if (!dd->started || dd->dev->mode() == PIIODevice::WriteOnly) return;
|
||||
dd->rthread->stop();
|
||||
dd->started = false;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::stopAllThreadedReads() {
|
||||
piForeachC (DevicePool::DDPair & d, __device_pool__->devices)
|
||||
stopThreadedRead(d.first);
|
||||
}
|
||||
|
||||
|
||||
int PIConnection::write(const PIString & full_path, const PIByteArray & data) {
|
||||
PIIODevice * dev = __device_pool__->device(full_path);
|
||||
if (dev == 0) {
|
||||
piCoutObj << "Null Device!";
|
||||
return -1;
|
||||
}
|
||||
if (!dev->canWrite()) {
|
||||
piCoutObj << "Device \"" << full_path << "\" can`t write!";
|
||||
return -1;
|
||||
}
|
||||
return dev->write(data);
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIConnection * > PIConnection::allConnections() {
|
||||
return _connections;
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIIODevice * > PIConnection::allDevices() {
|
||||
return __device_pool__->boundedDevices();
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode, bool start) {
|
||||
DeviceData * dd = devices[fp];
|
||||
int pmode(0);
|
||||
bool need_start = false;
|
||||
if (dd == 0) {
|
||||
dd = new DeviceData();
|
||||
devices[fp] = dd;
|
||||
}
|
||||
if (dd->dev == 0) {
|
||||
//piCout << "new device" << fp;
|
||||
dd->dev = PIIODevice::createFromFullPath(fp);
|
||||
if (dd->dev == 0) {
|
||||
piCoutObj << "Error: can`t create device \"" << fp << "\"!"; //:" << errorString();
|
||||
return 0;
|
||||
}
|
||||
dd->dev->setProperty("__fullPath__", fp);
|
||||
} else
|
||||
pmode = dd->dev->mode();
|
||||
if (!dd->listeners.contains(parent))
|
||||
dd->listeners << parent;
|
||||
if (pmode == mode || pmode == PIIODevice::ReadWrite)
|
||||
return dd->dev;
|
||||
if ((mode & PIIODevice::ReadOnly) > 0) {
|
||||
if (dd->rthread != 0) {
|
||||
delete dd->rthread;
|
||||
dd->rthread = 0;
|
||||
dd->started = false;
|
||||
}
|
||||
dd->rthread = new PIThread(dd, threadReadDP);
|
||||
need_start = true;
|
||||
pmode |= PIIODevice::ReadOnly;
|
||||
}
|
||||
if ((mode & PIIODevice::WriteOnly) > 0)
|
||||
pmode |= PIIODevice::WriteOnly;
|
||||
dd->dev->close();
|
||||
dd->dev->open((PIIODevice::DeviceMode)pmode);
|
||||
if (need_start && start) {
|
||||
dd->rthread->start();
|
||||
dd->started = true;
|
||||
}
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::DevicePool::removeDevice(PIConnection * parent, const PIString & fp) {
|
||||
DeviceData * dd = devices.value(fp);
|
||||
if (dd == 0)
|
||||
return false;
|
||||
if (dd->dev == 0)
|
||||
return false;
|
||||
bool ok = dd->listeners.contains(parent);
|
||||
dd->listeners.removeAll(parent);
|
||||
if (dd->listeners.isEmpty()) {
|
||||
delete dd;
|
||||
devices.remove(fp);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::unboundConnection(PIConnection * parent) {
|
||||
PIStringList rem;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0) {
|
||||
rem << i.first;
|
||||
continue;
|
||||
}
|
||||
i.second->listeners.removeAll(parent);
|
||||
if (i.second->listeners.isEmpty())
|
||||
rem << i.first;
|
||||
}
|
||||
piForeachC (PIString & i, rem) {
|
||||
DeviceData * dd = devices.value(i);
|
||||
if (dd == 0)
|
||||
continue;
|
||||
delete dd;
|
||||
devices.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIConnection::DevicePool::device(const PIString & fp) const {
|
||||
DeviceData * dd = devices.value(fp);
|
||||
if (dd == 0) return 0;
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIConnection * > PIConnection::DevicePool::boundedConnections() const {
|
||||
PIVector<PIConnection * > ret;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0)
|
||||
continue;
|
||||
ret << i.second->listeners;
|
||||
}
|
||||
for (int i = 0; i < ret.size_s(); ++i)
|
||||
for (int j = i + 1; j < ret.size_s(); ++j)
|
||||
if (ret[i] == ret[j]) {
|
||||
ret.remove(j);
|
||||
--j;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIIODevice * > PIConnection::DevicePool::boundedDevices() const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0) continue;
|
||||
if (i.second->dev == 0) continue;
|
||||
ret << i.second->dev;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::DevicePool::boundedDevices(const PIConnection * parent) const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0) continue;
|
||||
if (i.second->dev == 0) continue;
|
||||
if (i.second->listeners.contains(const_cast<PIConnection*>(parent)))
|
||||
ret << i.second->dev;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIConnection::DevicePool::DeviceData::~DeviceData() {
|
||||
if (rthread != 0) {
|
||||
rthread->stop();
|
||||
delete rthread;
|
||||
rthread = 0;
|
||||
}
|
||||
if (dev != 0) {
|
||||
delete dev;
|
||||
dev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::threadReadDP(void * ddp) {
|
||||
DeviceData * dd((DeviceData * )ddp);
|
||||
if (dd->dev == 0) {piMSleep(100); return;}
|
||||
PIByteArray ba;
|
||||
ba = dd->dev->read(dd->dev->threadedReadBufferSize());
|
||||
if (ba.isEmpty()) {piMSleep(10); return;}
|
||||
//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();
|
||||
piForeach (PIConnection * ld, dd->listeners)
|
||||
ld->rawReceived(dd->dev, from, data);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateHeaderS(void * c, uchar * src, uchar * rec, int size) {
|
||||
PIPair<PIConnection * , PIString> * p((PIPair<PIConnection * , PIString> * )c);
|
||||
return p->first->filterValidateHeader(p->second, src, rec, size);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateFooterS(void * c, uchar * src, uchar * rec, int size) {
|
||||
PIPair<PIConnection * , PIString> * p((PIPair<PIConnection * , PIString> * )c);
|
||||
return p->first->filterValidateFooter(p->second, src, rec, size);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidatePayloadS(void * c, uchar * rec, int size) {
|
||||
PIPair<PIConnection * , PIString> * p((PIPair<PIConnection * , PIString> * )c);
|
||||
return p->first->filterValidatePayload(p->second, rec, size);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
piForeach (PIPacketExtractor * i, be)
|
||||
i->threadedRead(const_cast<uchar * >(data.data()), data.size_s());
|
||||
PIVector<PIIODevice * > chd(channels_.value(dev));
|
||||
piForeach (PIIODevice * d, chd)
|
||||
d->write(data);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateHeader(const PIString & filter_name, uchar * src, uchar * rec, int size) {
|
||||
for (int i = 0; i < size; ++i)
|
||||
if (src[i] != rec[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateFooter(const PIString & filter_name, uchar * src, uchar * rec, int size) {
|
||||
for (int i = 0; i < size; ++i)
|
||||
if (src[i] != rec[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidatePayload(const PIString & filter_name, uchar * rec, int size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIConnection::Extractor::~Extractor() {
|
||||
if (extractor != 0) {
|
||||
if (extractor->threadedReadData() != 0)
|
||||
delete (PIPair<PIConnection * , PIString> * )(extractor->threadedReadData());
|
||||
delete extractor;
|
||||
extractor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
|
||||
if (pe == 0) return;
|
||||
channels_.remove(pe);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(pe);
|
||||
PIVector<PIIODevice * > k = bounded_extractors.keys();
|
||||
piForeach (PIIODevice * i, k) {
|
||||
PIVector<PIPacketExtractor*> & be(bounded_extractors[i]);
|
||||
be.removeAll(pe);
|
||||
if (be.isEmpty())
|
||||
bounded_extractors.remove(i);
|
||||
}
|
||||
extractors.remove(pe->name());
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::packetExtractorReceived(uchar * data, int size) {
|
||||
PIString from(emitter() == 0 ? "" : emitter()->name());
|
||||
packetReceived(from, PIByteArray(data, size));
|
||||
packetReceivedEvent(from, PIByteArray(data, size));
|
||||
PIIODevice * cd = (PIIODevice * )emitter();
|
||||
if (cd == 0) return;
|
||||
PIVector<PIIODevice * > chd(channels_.value(cd));
|
||||
piForeach (PIIODevice * d, chd)
|
||||
d->write(data, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIConnection::DevicePool * __device_pool__;
|
||||
|
||||
bool __DevicePoolContainer__::inited_(false);
|
||||
|
||||
__DevicePoolContainer__::__DevicePoolContainer__() {
|
||||
if (inited_) return;
|
||||
inited_ = true;
|
||||
__device_pool__ = new PIConnection::DevicePool();
|
||||
}
|
||||
Reference in New Issue
Block a user