Соединение сигналами и слотами класса приложения и класса из dll подгружаемой динамически

87
03 октября 2021, 12:00

Реализую библиотеку по обработки данных с устройства, в последствии количество устройств будет наращиваться и я пишу гибкое решение. У меня есть класс устройства, который в динамике подгружает класс драйвера. Класс драйвера реализован в отдельной dll. Само собой интерфейсный класс для этого дела присутствует, как в dll так и в основном приложении. Проблема в том, что когда происходит эмит сигнала, слот его не отрабатывает, и я не могу понять почему.

   #ifndef DRIVERINTERFACE_H
#define DRIVERINTERFACE_H
#include <QObject>
#include <functional>
#include <QString>
#include <memory>
#include <QHash>
#include <QJsonObject>
class TagModel;
class DriverInterface : public QObject
{
    Q_OBJECT
public:
    DriverInterface(QObject* parent = nullptr): QObject(parent){
    }
    virtual ~DriverInterface(){
    }
    virtual void setMessageAsString(const QString& _message) = 0;
    virtual void initializeChannel(const QJsonObject& _parameters) = 0;
    virtual void setCallBackFunction(const QString &_nameOfCallBack,
                             std::function<void (const QString &)> _callback) = 0;
    virtual bool downloadTagsModel(const QHash<QString,
                           std::shared_ptr<TagModel> >& _tagModels) = 0;
    virtual QString getMessageAsString() = 0;
signals:
    void callBackMessage(QJsonObject _message);
};
#endif // DRIVERINTERFACE_H


 #ifndef DRIVER101104_H
#define DRIVER101104_H
#include <QObject>
#include <functional>
#include <QHash>
#include "driver101-104_global.h"
#include "protocol101104wrapper.h"
#include "driverinterface.h"
class DRIVER101104SHARED_EXPORT Driver101104 : public DriverInterface
{
    Q_OBJECT
public:
    Driver101104(QObject* parent = nullptr);
    virtual ~Driver101104();
public:
    void initializeChannel(const QJsonObject &_parameters);
    void setCallBackFunction(const QString &_nameOfCallBack,
                             std::function<void (const QString &)> _callback);
    bool downloadTagsModel(const QHash<QString,
                           std::shared_ptr<TagModel> > &_tagModels);
    void setMessageAsString(const QString &_message);
    QString getMessageAsString();

private:
    protocol101104Wrapper* wrapper;
};
extern "C"{
    DRIVER101104SHARED_EXPORT DriverInterface* createDriverClass();
}
#endif // DRIVER101104_H

 #include "driver101104.h"
Driver101104::Driver101104(QObject* parent):DriverInterface(parent)
{
    /*Just for calling from wrapper parent class.*/
    wrapper  = new protocol101104Wrapper(this);
}
Driver101104::~Driver101104()
{
}
void Driver101104::initializeChannel(const QJsonObject &_parameters)
{
    wrapper->channelInitializer(_parameters);
}
void Driver101104::setCallBackFunction(const QString &_nameOfCallBack, std::function<void (const QString &)> _callback)
{
    wrapper->setCallBackFunction(_nameOfCallBack,_callback);
}
bool Driver101104::downloadTagsModel(const QHash<QString, std::shared_ptr<TagModel> > &_tagModels)
{
    return true;
}
void Driver101104::setMessageAsString(const QString &_message)
{
}
QString Driver101104::getMessageAsString()
{
    return QString();
}

DriverInterface* createDriverClass(){
        return new Driver101104();
}

#ifndef DEVICE_H
#define DEVICE_H
#include <QObject>
#include <QHash>
#include <QLibrary>
#include <memory>
#include "tcplinkagent.h"
#include "udplinkagent.h"
#include "comlinkagent.h"
#include "externallinkagent.h"
#include "driverinterface.h"
#include "servicenames.h"
class TagModel;
/**
 * @brief The Device class
 * Do not forget to transfer
 * smart pointer inside to add
 * tag method.
 */
class Device : public QObject
{
    Q_OBJECT
public:
    explicit Device(QObject* parent = nullptr);
    virtual ~Device();
    QString tagsToString();
    void stringToTags(QString _tags);
    bool isConnected();
    void setLinkAgent(std::shared_ptr<LinkAgent>&& _linkAgent);
    void setDeviceName(const QString& _deviceName);
    void setPathToDriver(const QString& _pathToDriver);
    void setMessage(const QJsonObject& _message);
    virtual void parseInformatoinalMessage(const QJsonObject& _message);
    virtual void parseServiceMessage(const QJsonObject& _message);
    virtual bool connectToChannel();
    virtual bool disconnectFromChannel();
    virtual void setLinkParameters(const QJsonObject& _params);
    void callBackInformMessageMethod(const QString& _message);
    void callBackServiceMessageMethod(const QString& _message);
signals:
    void sendCallBackMessage(QJsonObject _message);
private slots:
    void getMessage(QJsonObject _message);
protected:
    QHash<QString,std::shared_ptr<TagModel>> tags;
    std::shared_ptr<LinkAgent> linkAgent;
    QLibrary driverLibrary;
    DriverInterface* driverInterface;
    QJsonObject serviceData;
};


  #include "device.h"
#include <functional>
#include "logger.h"
#include <QJsonObject>
#include <QDebug>
Device::Device(QObject* parent) : QObject (parent)
{
}
Device::~Device()
{
}

QString Device::tagsToString()
{
    return driverInterface->getMessageAsString();
}
void Device::stringToTags(QString _tags)
{
    driverInterface->setMessageAsString(_tags);
}
bool Device::isConnected()
{
    return true;
}
bool Device::connectToChannel()
{
    return linkAgent->createConnection();
}
bool Device::disconnectFromChannel()
{
    return linkAgent->closeConnection();
}
void Device::setLinkAgent(std::shared_ptr<LinkAgent>&& _linkAgent)
{
    linkAgent = std::move(_linkAgent);
}
void Device::setLinkParameters(const QJsonObject& _params)
{
    linkAgent->setLinkParameters(_params);
}
void Device::callBackInformMessageMethod(const QString &_message)
{
    //emit sendCallBackMessage(_message);
}
void Device::callBackServiceMessageMethod(const QString &_message)
{
    QString mes = _message;
    //emit sendCallBackMessage(mes);
}
void Device::getMessage(QJsonObject _message)
{
    qDebug()<<_message;
}
/**
 * @brief Device::setPathToDriver
 * @param _pathToDriver
 * Connecting to driver while 
 */
void Device::setPathToDriver(const QString& _pathToDriver)
{
    driverLibrary.setFileName(_pathToDriver);
    if(driverLibrary.load()){
        typedef DriverInterface* (*createDriverClass)();
        createDriverClass driverClassConstructor = (createDriverClass)driverLibrary.resolve("createDriverClass");
        if(driverClassConstructor){
            driverInterface = driverClassConstructor();
            /*Do not forget to set callbacks for the loaded library.*/
            driverInterface->setCallBackFunction("InformMessage",
                                                  std::bind(&Device::callBackInformMessageMethod,
                                                            this,std::placeholders::_1));
            driverInterface->setCallBackFunction("ServiceMessage",
                                                  std::bind(&Device::callBackServiceMessageMethod,
                                                            this,std::placeholders::_1));

            //if(!connect(driverInterface,&DriverInterface::callBackMessage,
            //        this,&Device::sendCallBackMessage))
            //    LOG(LevelOfId::LOG_ERROR)<<"Can't connect signal from driver to slot from device";

            connect(driverInterface,&DriverInterface::callBackMessage,
                    this,&Device::getMessage,Qt::DirectConnection);

        }
    } else {
        LOG(LevelOfId::LOG_ERROR)<<"Error while loading driver from so :"<<driverLibrary.errorString();
    }
}
void Device::setMessage(const QJsonObject &_message)
{
    switch (_message[TypeOfMessage].toInt()){
        case TypeOfMessage::Service : {
            parseServiceMessage(_message);
            break;
        }
        case TypeOfMessage::Informational : {
            parseInformatoinalMessage(_message);
            break;
        }
        default : {
        }
    }
}
void Device::parseInformatoinalMessage(const QJsonObject &_message)
{
}
void Device::parseServiceMessage(const QJsonObject& _message)
{
    setLinkParameters(_message);
}
#ifndef PROTOCOL101104WRAPPER_H
#define PROTOCOL101104WRAPPER_H
#include <QObject>
#include <QHash>
#include <QMap>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <functional>
/*Headers for all functions used for initializing
 *channel and the other for good working with driver.*/
#include "../Driver101-104/LibraryHeaders/lib60870.h"
class protocol101104Wrapper : public QObject
{
    Q_OBJECT
public:
    protocol101104Wrapper(QObject* parent);
    ~protocol101104Wrapper();
    void setCallableObject(void* _obj);
    void getMessageFromDevice();
    void channelInitializer(const QJsonObject& _init);
    void setMessageToChannel(const QString& message);
    void createClientConnection(const QJsonObject& _init);
    void createServerConnection(const QJsonObject& _init);
    void createServiceMessage(QJsonObject& _obj);
    void createInformMessage(QJsonObject& _obj);
    void closeConnection();
    void connectionHandler(CS104_Connection&& connection, CS104_ConnectionEvent&& event);
    bool asduReceiveHandler(int address, CS101_ASDU&& asdu);
    void setCallBackFunction(const QString& _nameOfCallBack,std::function<void(const QJsonObject& _message, void* )>);
    void packInformationalMessage(const SinglePointInformation& _inform, QJsonArray& _tagsArray);
    void sendInformMessage(QJsonObject& _message,QJsonArray &values);
    void sendServiceMessage(QJsonObject& _message);
    static void connectionHandlerWrapper(void* parameter, CS104_Connection connection, CS104_ConnectionEvent event);
    static bool asduReceivedHandlerWrapper (void* parameter, int address, CS101_ASDU asdu);
private slots:
    void getMessageSlot(QJsonObject _message);

private:
    QHash<QString,
    std::function<void(const QJsonObject& , void* )>> nameAndFunction;
    void fromStringToJson(const QString& _init);
    QJsonObject channelParameters;
    CS104_Connection con;
    QMap<int,QString> typeOfField;
    void* obj;
};
#endif // PROTOCOL101104WRAPPER_H


  protocol101104Wrapper::~protocol101104Wrapper()
{
    closeConnection();
}
void protocol101104Wrapper::setCallableObject(void* _obj)
{
    obj = _obj;
}
void protocol101104Wrapper::getMessageFromDevice()
{
}
void protocol101104Wrapper::channelInitializer(const QJsonObject& _init)
{
     if(_init[ConnectionState].toInt() == ConnectState::On){
         switch (channelParameters[TcpTypeConnection].toInt()){
            case Client :{
                 createClientConnection(_init);
                 break;
            }
            case Server: {
                 createServerConnection(_init);
                 break;
            }
            default :
                LOG(LevelOfId::LOG_ERROR)<<"Can't create connection in cs104 driver because incorrect type of connection was set";
         }
     } else {
         closeConnection();
     }
}
void protocol101104Wrapper::setMessageToChannel(const QString &message)
{
}
/**
 * @brief protocol101104Wrapper::createClientConnection
 * do not forget about rapport for succesfully opened
 * connection. It's not Opened yet.
 */
void protocol101104Wrapper::createClientConnection(const QJsonObject& _init)
{
    con = CS104_Connection_create(_init[IpAddr].toString().toUtf8().data(),
                                  _init[Port].toInt());
    CS104_Connection_setConnectionHandler(con, connectionHandlerWrapper, this);
    CS104_Connection_setASDUReceivedHandler(con, asduReceivedHandlerWrapper, this);

    /*Open connection and check for it succesfully connection! This lines have to be used
     *  in creating informational message*/
    if (!CS104_Connection_connect(con)){
         LOG(LevelOfId::LOG_INFO)<<"Can't open connection for CS104 driver while initialization";
         closeConnection();
         return;
    }
    /*Set ask message!*/
    CS104_Connection_sendStartDT(con);
    Thread_sleep(2000);
    /*Just send Test Message for writing*/
    /*Should be rewriten after for morecomplex data class!*/
    CS104_Connection_sendInterrogationCommand(con, CS101_COT_ACTIVATION, 1, IEC60870_QOI_STATION);
    Thread_sleep(5000);
}
void protocol101104Wrapper::createServerConnection(const QJsonObject& _init)
{

}
void protocol101104Wrapper::createServiceMessage(QJsonObject& _obj)
{
     _obj[TypeOfMessage] = TypeOfMessage::Service;
     _obj[TcpTypeConnection] = TcpLinkType::Client;
     _obj[TypeOfDevice] = EXTERNAL;
}

/**
 * @brief protocol101104Wrapper::createInformMessage
 * Are all this fields are necessary, or just use an
 *
 * @param _obj
 */
void protocol101104Wrapper::createInformMessage(QJsonObject &_obj)
{
    _obj[TypeOfMessage] = TypeOfMessage::Informational;
    _obj[TcpTypeConnection] = TcpLinkType::Client;
    _obj[TypeOfDevice] = EXTERNAL;
}
void protocol101104Wrapper::closeConnection()
{
    CS104_Connection_destroy(con);
}
/**
 * @brief protocol101104Wrapper::connectionHandler
 * @param connection - object for 104 connection
 * functionality with connection event for detecting
 * state of connection.
 * @param event
 */
void protocol101104Wrapper::connectionHandler(CS104_Connection &&connection, CS104_ConnectionEvent &&event)
{
    QJsonObject initResult;
    createServiceMessage(initResult);
    switch (event) {
    case CS104_CONNECTION_OPENED:
        initResult[ConnectionState] = ConnectState::On;
        break;
    case CS104_CONNECTION_CLOSED:
        initResult[ConnectionState] = ConnectState::OFF;
        break;
    case CS104_CONNECTION_STARTDT_CON_RECEIVED:
        //result = "Received STARTDT_CON";
        break;
    case CS104_CONNECTION_STOPDT_CON_RECEIVED:
        //result = "Received STOPDT_CON";
        break;
    }
    sendServiceMessage(initResult);
}
/**
 * @brief protocol101104Wrapper::asduReceiveHandler
 * a callback for receiveing message from library
 * functional for tags model serialization have to
 * be added after. It's like method fromBytesToString.
 * @param address
 * @param asdu
 * @return
 */
bool protocol101104Wrapper::asduReceiveHandler(int address, CS101_ASDU &&asdu)
{
    QJsonObject recInformData;
    QJsonArray recFields;
    createInformMessage(recInformData);
    if (CS101_ASDU_getTypeID(asdu) == M_ME_TE_1) {
        printf("  measured scaled values with CP56Time2a timestamp:\n");
        int i;
        for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
            MeasuredValueScaledWithCP56Time2a io =
                    (MeasuredValueScaledWithCP56Time2a) CS101_ASDU_getElement(asdu, i);
            /*Just added from me for initializing tags from received values*/
            //overload this function
            //packInformationalMessage(io,recData);

            printf("    IOA: %i value: %i\n",
                    InformationObject_getObjectAddress((InformationObject) io),
                    MeasuredValueScaled_getValue((MeasuredValueScaled) io)
            );

            MeasuredValueScaledWithCP56Time2a_destroy(io);
        }
        sendInformMessage(recInformData,recFields);
    } else if (CS101_ASDU_getTypeID(asdu) == M_SP_NA_1) {
        printf("  single point information:\n");
        int i;
        for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
            SinglePointInformation io =
                    (SinglePointInformation) CS101_ASDU_getElement(asdu, i);
            /*Just added from me for initializing tags from received values*/
            packInformationalMessage(io,recFields);
            SinglePointInformation_destroy(io);
        }
        sendInformMessage(recInformData,recFields);
    }
    return true;
}
/**
 * @brief protocol101104Wrapper::setCallBackFunction
 * This method for some new informational functions
 * for creating more complex functionality.
 * @param _nameOfCallBack
 * @param _callBack
 */
void protocol101104Wrapper::setCallBackFunction(const QString& _nameOfCallBack, std::function<void (const QJsonObject &, void*)> _callBack)
{
    nameAndFunction[_nameOfCallBack] = _callBack;
}

void protocol101104Wrapper::packInformationalMessage(const SinglePointInformation &_inform, QJsonArray& tagArray)
{
    QJsonObject tmp;
    tmp[iecField] = typeOfField[_inform->type];
    tmp[iecAddr] = _inform->objectAddress;
    tmp[value] = _inform->value;
    tmp[quality] = _inform->quality;
    tagArray.append(tmp);
}

/**
 * @brief protocol101104Wrapper::sendInformMessage
 * @param values
 * cannot emit from this method for event loop
 */
void protocol101104Wrapper::sendInformMessage(QJsonObject& _message,QJsonArray &values)
{
    _message[informData] = values;
    nameAndFunction[InformFunction](_message,obj);
    QMetaObject::invokeMethod(this,"getMessageSlot",
                              Qt::QueuedConnection,
                              Q_ARG(QJsonObject,_message));
}
void protocol101104Wrapper::sendServiceMessage(QJsonObject &_message)
{
    //nameAndFunction[ServiceFunction](_message,obj);
    QMetaObject::invokeMethod(this,"getMessageSlot",
                              Qt::QueuedConnection,
                              Q_ARG(QJsonObject,_message));
}
void protocol101104Wrapper::connectionHandlerWrapper(void *parameter, CS104_Connection connection, CS104_ConnectionEvent event)
{
    protocol101104Wrapper* tmp = reinterpret_cast<protocol101104Wrapper*>(parameter);
    tmp->connectionHandler(std::move(connection),std::move(event));
}
bool protocol101104Wrapper::asduReceivedHandlerWrapper(void *parameter, int address, CS101_ASDU asdu)
{
   protocol101104Wrapper* tmp = reinterpret_cast<protocol101104Wrapper*>(parameter);
   return tmp->asduReceiveHandler(address,std::move(asdu));
}
void protocol101104Wrapper::getMessageSlot(QJsonObject _message)
{
    auto ptr = reinterpret_cast<Driver101104*>(parent());
    emit ptr->callBackMessage(_message);
}
void protocol101104Wrapper::fromStringToJson(const QString &_init)
{
    QJsonDocument doc = QJsonDocument::fromJson(_init.toUtf8());
    channelParameters = doc.object();
}
READ ALSO
postgresql для разработчика С++

postgresql для разработчика С++

Всем приветПожалуйста, помогите разобраться в ситуации

83
Проблема с вводом-выводом бинарных файлов

Проблема с вводом-выводом бинарных файлов

Проблема возникает на этапе чтения из файла, так как я открыл файл hex редактором, и в нем число естьЧто я делаю не так?

82
Как можно сократить время компиляции в c++

Как можно сократить время компиляции в c++

Я написал программу и начал проверять ееУ нее стоит условие, что время выполнения меньше 1 секунды

91
Вопросы по поводу inline (встраивания) геттеров

Вопросы по поводу inline (встраивания) геттеров

Я пытался разобраться со встраиванием сам, но не особо уверен в некоторых деталяхНасколько я понял встраивание происходит автоматически,...

218