Реализую библиотеку по обработки данных с устройства, в последствии количество устройств будет наращиваться и я пишу гибкое решение. У меня есть класс устройства, который в динамике подгружает класс драйвера. Класс драйвера реализован в отдельной 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();
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Проблема возникает на этапе чтения из файла, так как я открыл файл hex редактором, и в нем число естьЧто я делаю не так?
Я написал программу и начал проверять ееУ нее стоит условие, что время выполнения меньше 1 секунды
Я пытался разобраться со встраиванием сам, но не особо уверен в некоторых деталяхНасколько я понял встраивание происходит автоматически,...