Files
pip/libs/main/io_utils/piconnection.h
2026-03-07 17:00:45 +03:00

539 lines
31 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*! \file piconnection.h
* \ingroup IO-Utils
* \~\brief
* \~english Connection routing helper built on shared devices and packet filters
* \~russian Вспомогательный класс маршрутизации поверх общих устройств и пакетных фильтров
*/
/*
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 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/>.
*/
#ifndef PICONNECTION_H
#define PICONNECTION_H
#include "pidiagnostics.h"
#include "pipacketextractor.h"
class PIConfig;
//! \ingroup IO-Utils
//! \~\brief
//! \~english Routes data between shared devices, packet extractors, channels and periodic senders.
//! \~russian Маршрутизирует данные между общими устройствами, извлекателями пакетов, каналами и периодическими отправителями.
//!
//! \~\details
//! \~english
//! %PIConnection uses a process-wide device pool so several connections can
//! share the same physical device. Raw device data may be forwarded into named
//! filters, routed through channels, monitored with diagnostics and emitted by
//! periodic senders.
//! \~russian
//! %PIConnection использует общий для процесса пул устройств, поэтому несколько
//! соединений могут разделять одно физическое устройство. Сырые данные
//! устройств могут передаваться в именованные фильтры, маршрутизироваться по
//! каналам, контролироваться диагностикой и отправляться периодическими
//! отправителями.
class PIP_EXPORT PIConnection: public PIObject {
PIOBJECT_SUBCLASS(PIConnection, PIObject);
public:
//! \~english Constructs an empty connection with name "name".
//! \~russian Создает пустое соединение с именем "name".
PIConnection(const PIString & name = PIStringAscii("connection"));
//! \~english Constructs a connection and immediately configures it from section "name" of file "config".
//! \~russian Создает соединение и сразу настраивает его из секции "name" файла "config".
PIConnection(const PIString & config, const PIString & name);
//! \~english Constructs a connection and immediately configures it from section "name" stored in "string".
//! \~russian Создает соединение и сразу настраивает его из секции "name", хранящейся в "string".
PIConnection(PIString * string, const PIString & name);
//! \~english Releases all bindings owned by this connection.
//! \~russian Освобождает все привязки, принадлежащие этому соединению.
~PIConnection();
//! \~english Reconfigures the connection from section "name" of file "config".
//! \~russian Перенастраивает соединение из секции "name" файла "config".
//! \~english Clears current devices, filters, channels and senders before applying the new configuration.
//! \~russian Перед применением новой конфигурации удаляет текущие устройства, фильтры, каналы и отправители.
bool configureFromConfig(const PIString & config, const PIString & name = PIStringAscii("connection"));
//! \~english Reconfigures the connection from section "name" stored in "string".
//! \~russian Перенастраивает соединение из секции "name", хранящейся в "string".
//! \~english Clears current devices, filters, channels and senders before applying the new configuration.
//! \~russian Перед применением новой конфигурации удаляет текущие устройства, фильтры, каналы и отправители.
bool configureFromString(PIString * string, const PIString & name = PIStringAscii("connection"));
//! \~english Serializes current connection state into one configuration section.
//! \~russian Сериализует текущее состояние соединения в одну секцию конфигурации.
PIString makeConfig() const;
//! \~english Adds device "full_path" to the shared device pool and binds it to this connection.
//! \~russian Добавляет устройство "full_path" в общий пул устройств и привязывает его к этому соединению.
//! \~english Returns the shared device instance or \c nullptr when creation fails. When "start" is \b true, threaded read starts immediately.
//! \~russian Возвращает общий экземпляр устройства или \c nullptr, если создание не удалось. Если "start" равно \b true, потоковое чтение запускается сразу.
PIIODevice * addDevice(const PIString & full_path, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = false);
//! \~english Assigns alias "name" to device "dev" inside this connection.
//! \~russian Назначает устройству "dev" псевдоним "name" внутри этого соединения.
void setDeviceName(PIIODevice * dev, const PIString & name);
//! \~english Returns all aliases assigned to device "dev" in this connection.
//! \~russian Возвращает все псевдонимы устройства "dev" в этом соединении.
PIStringList deviceNames(const PIIODevice * dev) const;
//! \~english Unbinds device "full_path" from this connection.
//! \~russian Отвязывает устройство "full_path" от этого соединения.
//! \~english The shared device object is deleted from the pool only when no connections still use it.
//! \~russian Общий объект устройства удаляется из пула только тогда, когда им больше не пользуется ни одно соединение.
bool removeDevice(const PIString & full_path);
//! \~english Removes all devices currently bound to this connection.
//! \~russian Удаляет все устройства, привязанные к этому соединению.
//! \~english Devices remain in the shared pool while they are still referenced by other connections.
//! \~russian Устройства остаются в общем пуле, пока на них ссылаются другие соединения.
void removeAllDevices();
//! \~english Returns bound device by normalized full path.
//! \~russian Возвращает привязанное устройство по нормализованному полному пути.
PIIODevice * deviceByFullPath(const PIString & full_path) const;
//! \~english Returns bound device by alias.
//! \~russian Возвращает привязанное устройство по псевдониму.
PIIODevice * deviceByName(const PIString & name) const;
//! \~english Returns all devices currently bound to this connection.
//! \~russian Возвращает все устройства, привязанные к этому соединению.
PIVector<PIIODevice *> boundedDevices() const;
//! \~english Creates or reuses filter "name" and binds source "full_path_name" to it.
//! \~russian Создает или повторно использует фильтр "name" и привязывает к нему источник "full_path_name".
//! \~english The source may resolve to a device full path, a device alias or another filter. "mode" is used only when a new filter is created.
//! \~russian Источник может ссылаться на полный путь устройства, псевдоним устройства или другой фильтр. "mode" используется только при создании нового фильтра.
PIPacketExtractor *
addFilter(const PIString & name, const PIString & full_path_name, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None);
//! \~english Creates or reuses filter "name" and binds device "dev" to it.
//! \~russian Создает или повторно использует фильтр "name" и привязывает к нему устройство "dev".
PIPacketExtractor *
addFilter(const PIString & name, const PIIODevice * dev, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None) {
return addFilter(name, devFPath(dev), mode);
}
//! \~english Binds existing extractor object "filter" to source "full_path_name".
//! \~russian Привязывает существующий объект извлекателя "filter" к источнику "full_path_name".
PIPacketExtractor * addFilter(PIPacketExtractor * filter, const PIString & full_path_name);
//! \~english Binds existing extractor object "filter" to device "dev".
//! \~russian Привязывает существующий объект извлекателя "filter" к устройству "dev".
PIPacketExtractor * addFilter(PIPacketExtractor * filter, const PIIODevice * dev) { return addFilter(filter, devFPath(dev)); }
//! \~english Unbinds source "full_path_name" from filter "name".
//! \~russian Отвязывает источник "full_path_name" от фильтра "name".
//! \~english Removes the filter itself when it no longer has any bound sources.
//! \~russian Удаляет сам фильтр, когда у него больше не остается привязанных источников.
bool removeFilter(const PIString & name, const PIString & full_path_name);
//! \~english Unbinds device or upstream filter "dev" from filter "name".
//! \~russian Отвязывает устройство или вышестоящий фильтр "dev" от фильтра "name".
bool removeFilter(const PIString & name, const PIIODevice * dev);
//! \~english Removes filter "name" together with all its bindings.
//! \~russian Удаляет фильтр "name" вместе со всеми его привязками.
bool removeFilter(const PIString & name);
//! \~english Removes all filters from this connection.
//! \~russian Удаляет все фильтры из этого соединения.
void removeAllFilters();
//! \~english Returns all filters owned by this connection.
//! \~russian Возвращает все фильтры, принадлежащие этому соединению.
PIVector<PIPacketExtractor *> filters() const;
//! \~english Returns names of all filters owned by this connection.
//! \~russian Возвращает имена всех фильтров, принадлежащих этому соединению.
PIStringList filterNames() const;
//! \~english Returns filter "name" or \c nullptr when it does not exist.
//! \~russian Возвращает фильтр "name" или \c nullptr, если такого фильтра нет.
PIPacketExtractor * filter(const PIString & name) const;
//! \~english Returns all sources currently bound to filter "name".
//! \~russian Возвращает все источники, привязанные к фильтру "name".
PIVector<PIIODevice *> filterBoundedDevices(const PIString & name) const;
//! \~english Adds a routing channel from "name_from" to "name_to".
//! \~russian Добавляет канал маршрутизации от "name_from" к "name_to".
//! \~english Both endpoints may reference a device full path, a device alias or a filter name.
//! \~russian Оба конца канала могут ссылаться на полный путь устройства, псевдоним устройства или имя фильтра.
bool addChannel(const PIString & name_from, const PIString & name_to);
//! \~english Adds a routing channel from "name_from" to device "dev_to".
//! \~russian Добавляет канал маршрутизации от "name_from" к устройству "dev_to".
bool addChannel(const PIString & name_from, const PIIODevice * dev_to) { return addChannel(name_from, devFPath(dev_to)); }
//! \~english Adds a routing channel from device "dev_from" to "name_to".
//! \~russian Добавляет канал маршрутизации от устройства "dev_from" к "name_to".
bool addChannel(const PIIODevice * dev_from, const PIString & name_to) { return addChannel(devFPath(dev_from), name_to); }
//! \~english Adds a routing channel from device "dev_from" to device "dev_to".
//! \~russian Добавляет канал маршрутизации от устройства "dev_from" к устройству "dev_to".
bool addChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) { return addChannel(devFPath(dev_from), devFPath(dev_to)); }
//! \~english Removes routing channel from "name_from" to "name_to".
//! \~russian Удаляет канал маршрутизации от "name_from" к "name_to".
bool removeChannel(const PIString & name_from, const PIString & name_to);
//! \~english Removes routing channel from "name_from" to device "dev_to".
//! \~russian Удаляет канал маршрутизации от "name_from" к устройству "dev_to".
bool removeChannel(const PIString & name_from, const PIIODevice * dev_to) { return removeChannel(name_from, devFPath(dev_to)); }
//! \~english Removes routing channel from device "dev_from" to "name_to".
//! \~russian Удаляет канал маршрутизации от устройства "dev_from" к "name_to".
bool removeChannel(const PIIODevice * dev_from, const PIString & name_to) { return removeChannel(devFPath(dev_from), name_to); }
//! \~english Removes routing channel from device "dev_from" to device "dev_to".
//! \~russian Удаляет канал маршрутизации от устройства "dev_from" к устройству "dev_to".
bool removeChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) {
return removeChannel(devFPath(dev_from), devFPath(dev_to));
}
//! \~english Removes all outgoing channels starting from "name_from".
//! \~russian Удаляет все исходящие каналы, начинающиеся в "name_from".
bool removeChannel(const PIString & name_from);
//! \~english Removes all outgoing channels starting from device "dev_from".
//! \~russian Удаляет все исходящие каналы, начинающиеся от устройства "dev_from".
bool removeChannel(const PIIODevice * dev_from) { return removeChannel(devFPath(dev_from)); }
//! \~english Removes all routing channels from this connection.
//! \~russian Удаляет все каналы маршрутизации из этого соединения.
void removeAllChannels();
//! \~english Returns all routing channels as source and destination pairs.
//! \~russian Возвращает все каналы маршрутизации как пары источника и назначения.
PIVector<PIPair<PIString, PIString>> channels() const;
//! \~english Creates or reuses sender "name" and binds device "full_path_name" to it.
//! \~russian Создает или повторно использует отправитель "name" и привязывает к нему устройство "full_path_name".
//! \~english "frequency" is applied when a new sender is created. When "start" is \b true, the timer starts immediately.
//! \~russian "frequency" применяется при создании нового отправителя. Если "start" равно \b true, таймер запускается сразу.
void addSender(const PIString & name, const PIString & full_path_name, float frequency, bool start = false);
//! \~english Creates or reuses sender "name" and binds device "dev" to it.
//! \~russian Создает или повторно использует отправитель "name" и привязывает к нему устройство "dev".
void addSender(const PIString & name, const PIIODevice * dev, float frequency, bool start = false) {
addSender(name, devFPath(dev), frequency, start);
}
//! \~english Unbinds device "full_path_name" from sender "name".
//! \~russian Отвязывает устройство "full_path_name" от отправителя "name".
bool removeSender(const PIString & name, const PIString & full_path_name);
//! \~english Unbinds device "dev" from sender "name".
//! \~russian Отвязывает устройство "dev" от отправителя "name".
bool removeSender(const PIString & name, const PIIODevice * dev) { return removeSender(name, devFPath(dev)); }
//! \~english Removes sender "name" together with its timer state.
//! \~russian Удаляет отправитель "name" вместе с состоянием его таймера.
bool removeSender(const PIString & name);
//! \~english Assigns fixed payload "data" to sender "name".
//! \~russian Назначает фиксированную нагрузку "data" отправителю "name".
bool setSenderFixedData(const PIString & name, const PIByteArray & data);
//! \~english Clears fixed payload for sender "name".
//! \~russian Очищает фиксированную нагрузку отправителя "name".
bool clearSenderFixedData(const PIString & name);
//! \~english Returns fixed payload configured for sender "name".
//! \~russian Возвращает фиксированную нагрузку, настроенную для отправителя "name".
PIByteArray senderFixedData(const PIString & name) const;
//! \~english Returns sender timer frequency.
//! \~russian Возвращает частоту таймера отправителя.
//! \~english Returns -1 when the sender does not exist and 0 when it exists but is not running.
//! \~russian Возвращает -1, если отправителя не существует, и 0, если он существует, но не запущен.
float senderFrequency(const PIString & name) const;
//! \~english Removes all senders from this connection.
//! \~russian Удаляет все отправители из этого соединения.
void removeAllSenders();
//! \~english Starts threaded read for source "full_path_name".
//! \~russian Запускает потоковое чтение для источника "full_path_name".
void startThreadedRead(const PIString & full_path_name);
//! \~english Starts threaded read for device "dev".
//! \~russian Запускает потоковое чтение для устройства "dev".
void startThreadedRead(const PIIODevice * dev) { startThreadedRead(devFPath(dev)); }
//! \~english Starts threaded read for all devices bound to the shared pool.
//! \~russian Запускает потоковое чтение для всех устройств, привязанных к общему пулу.
void startAllThreadedReads();
//! \~english Starts sender timer "name".
//! \~russian Запускает таймер отправителя "name".
void startSender(const PIString & name);
//! \~english Starts all sender timers.
//! \~russian Запускает таймеры всех отправителей.
void startAllSenders();
//! \~english Starts all threaded reads and all senders.
//! \~russian Запускает все потоковые чтения и все отправители.
void start() {
startAllThreadedReads();
startAllSenders();
}
//! \~english Stops threaded read for source "full_path_name".
//! \~russian Останавливает потоковое чтение для источника "full_path_name".
void stopThreadedRead(const PIString & full_path_name);
//! \~english Stops threaded read for device "dev".
//! \~russian Останавливает потоковое чтение для устройства "dev".
void stopThreadedRead(const PIIODevice * dev) { stopThreadedRead(devFPath(dev)); }
//! \~english Stops threaded read for all bound devices.
//! \~russian Останавливает потоковое чтение для всех привязанных устройств.
void stopAllThreadedReads();
//! \~english Stops sender timer "name".
//! \~russian Останавливает таймер отправителя "name".
void stopSender(const PIString & name);
//! \~english Stops all sender timers.
//! \~russian Останавливает таймеры всех отправителей.
void stopAllSenders();
//! \~english Stops all threaded reads and all senders.
//! \~russian Останавливает все потоковые чтения и все отправители.
void stop() {
stopAllThreadedReads();
stopAllSenders();
}
//! \~english Stops the connection and removes all bound devices.
//! \~russian Останавливает соединение и удаляет все привязанные устройства.
void destroy() {
stop();
removeAllDevices();
}
//! \~english Returns whether the connection currently has no bound devices.
//! \~russian Возвращает, нет ли сейчас у соединения привязанных устройств.
bool isEmpty() const { return device_modes.isEmpty(); }
//! \~english Returns diagnostics object for device or filter "full_path_name".
//! \~russian Возвращает объект диагностики для устройства или фильтра "full_path_name".
PIDiagnostics * diagnostic(const PIString & full_path_name) const;
//! \~english Returns diagnostics object associated with device or filter "dev".
//! \~russian Возвращает объект диагностики, связанный с устройством или фильтром "dev".
PIDiagnostics * diagnostic(const PIIODevice * dev) const { return diags_.value(const_cast<PIIODevice *>(dev), 0); }
//! \~english Writes "data" to device resolved by full path "full_path".
//! \~russian Записывает "data" в устройство, найденное по полному пути "full_path".
int writeByFullPath(const PIString & full_path, const PIByteArray & data);
//! \~english Writes "data" to device resolved by alias "name".
//! \~russian Записывает "data" в устройство, найденное по псевдониму "name".
int writeByName(const PIString & name, const PIByteArray & data);
//! \~english Writes "data" directly to device "dev".
//! \~russian Записывает "data" непосредственно в устройство "dev".
int write(PIIODevice * dev, const PIByteArray & data);
//! \~english Returns all currently alive %PIConnection objects.
//! \~russian Возвращает все существующие в приложении объекты %PIConnection.
static PIVector<PIConnection *> allConnections();
//! \~english Returns all devices currently stored in the shared device pool.
//! \~russian Возвращает все устройства, которые сейчас хранятся в общем пуле устройств.
static PIVector<PIIODevice *> allDevices();
//! \~english Enables or disables shared device-pool fake mode and returns previous state.
//! \~russian Включает или выключает режим имитации общего пула устройств и возвращает предыдущее состояние.
static bool setFakeMode(bool yes);
//! \~english Returns whether the shared device pool works in fake mode.
//! \~russian Возвращает, работает ли общий пул устройств в режиме имитации.
static bool isFakeMode();
//! \~english Process-wide pool of shared devices used by %PIConnection.
//! \~russian Глобальный для процесса пул общих устройств, используемый %PIConnection.
class PIP_EXPORT DevicePool: public PIThread {
PIOBJECT_SUBCLASS(DevicePool, PIThread);
friend void __DevicePool_threadReadDP(void * ddp);
friend class PIConnection;
protected:
struct DeviceData;
public:
//! \~english Constructs an empty device pool controller.
//! \~russian Создает пустой контроллер пула устройств.
DevicePool();
//! \~english Destroys the device pool controller.
//! \~russian Уничтожает контроллер пула устройств.
~DevicePool();
//! \~english Starts internal pool processing if it is not running yet.
//! \~russian Запускает внутреннюю обработку пула, если она еще не выполняется.
void init();
//! \~english Creates or reuses shared device "fp" for connection "parent".
//! \~russian Создает или повторно использует общее устройство "fp" для соединения "parent".
PIIODevice *
addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = true);
//! \~english Removes binding between connection "parent" and shared device "fp".
//! \~russian Удаляет привязку между соединением "parent" и общим устройством "fp".
bool removeDevice(PIConnection * parent, const PIString & fp);
//! \~english Removes every binding owned by connection "parent".
//! \~russian Удаляет все привязки, принадлежащие соединению "parent".
void unboundConnection(PIConnection * parent);
//! \~english Returns shared device by normalized full path "fp".
//! \~russian Возвращает общее устройство по нормализованному полному пути "fp".
PIIODevice * device(const PIString & fp) const;
//! \~english Returns internal bookkeeping for device "d".
//! \~russian Возвращает внутренние служебные данные устройства "d".
DeviceData * deviceData(PIIODevice * d) const;
//! \~english Returns all connections currently using this pool.
//! \~russian Возвращает все соединения, которые сейчас используют этот пул.
PIVector<PIConnection *> boundedConnections() const;
//! \~english Returns all devices currently stored in this pool.
//! \~russian Возвращает все устройства, которые сейчас хранятся в этом пуле.
PIVector<PIIODevice *> boundedDevices() const;
//! \~english Returns devices currently bound to connection "parent".
//! \~russian Возвращает устройства, которые сейчас привязаны к соединению "parent".
PIVector<PIIODevice *> boundedDevices(const PIConnection * parent) const;
protected:
//! \~english Internal state of one shared device entry.
//! \~russian Внутреннее состояние одной записи общего устройства.
struct PIP_EXPORT DeviceData {
DeviceData(): dev(0), rthread(0), started(false) {}
~DeviceData();
PIIODevice * dev;
PIThread * rthread;
bool started;
PIVector<PIConnection *> listeners;
};
void run() override;
void deviceReaded(DeviceData * dd, const PIByteArray & data);
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
//! \{
//! \fn void dataReceivedEvent(const PIString & from, const PIByteArray & data)
//! \~english Emitted when raw data is received from source "from".
//! \~russian Генерируется при получении сырых данных от источника "from".
//! \fn void packetReceivedEvent(const PIString & from, const PIByteArray & data)
//! \~english Emitted when filter "from" produces a packet.
//! \~russian Генерируется, когда фильтр "from" выдает пакет.
//! \fn void qualityChanged(const PIIODevice * device, PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality)
//! \~english Emitted when diagnostics quality of "device" changes.
//! \~russian Генерируется при изменении качества диагностики устройства "device".
//! \}
protected:
//! \~english Called after raw data is received from source "from".
//! \~russian Вызывается после получения сырых данных от источника "from".
virtual void dataReceived(const PIString & from, const PIByteArray & data) {}
//! \~english Called after filter "from" produces a packet.
//! \~russian Вызывается после того, как фильтр "from" выдает пакет.
virtual void packetReceived(const PIString & from, const PIByteArray & data) {}
//! \~english Returns dynamic payload for sender "sender_name".
//! \~russian Возвращает динамическую нагрузку для отправителя "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, 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;
};
class PIP_EXPORT Sender: public PITimer {
PIOBJECT_SUBCLASS(Sender, PIObject);
public:
Sender(PIConnection * parent_ = 0);
~Sender() { stopAndWait(); }
PIConnection * parent;
PIVector<PIIODevice *> devices;
PIByteArray sdata;
PISystemTime int_;
void tick(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;
};
void __DevicePool_threadReadDP(void * ddp);
extern PIP_EXPORT PIConnection::DevicePool * __device_pool__;
class PIP_EXPORT __DevicePoolContainer__ {
public:
__DevicePoolContainer__();
static bool inited_;
};
static __DevicePoolContainer__ __device_pool_container__;
#endif // PICONNECTION_H