Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Included ModelChanged Eventhandling. Fixed update of nodes after reconnection. #368

Closed
wants to merge 22 commits into from

Conversation

mdornaus
Copy link
Contributor

@mdornaus mdornaus commented Mar 7, 2023

Added ModelChanged Eventhandling. Refactored Model Changed Eventhandling. Solved Reconnection Issue.

@CLAassistant
Copy link

CLAassistant commented Mar 7, 2023

CLA assistant check
All committers have signed the CLA.

@mdornaus mdornaus changed the title Flatglas2 Included ModelChanged Eventhandling. Fixed update of nodes after reconnection. Mar 7, 2023
Copy link
Member

@ccvca ccvca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are may additional LOG(INFO), are some of them outdated, or do all provide useful information?

DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardClient/IDashboardDataClient.hpp Outdated Show resolved Hide resolved
DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardClient/DashboardClient.cpp Outdated Show resolved Hide resolved
DashboardOpcUaClient.hpp Outdated Show resolved Hide resolved
DashboardClient/IDashboardDataClient.hpp Show resolved Hide resolved
Copy link
Member

@Kantiran91 Kantiran91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ccvca I´m finish with the review

}
}
}
//Hotfix clear subscription cache.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this currently a hotfix? What would be a better solution?

if(value && value.get()->getNodeId() == pNode.get()->NodeId)
return;
if(value && value.get()->getNodeId() == pNode.get()->NodeId) {
//LOG(INFO) << "Allready Subscribed" << value.get()->getNodeId();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remove the comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll Remove the comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you?

MachineObserver/DashboardMachineObserver.cpp Outdated Show resolved Hide resolved
OpcUaClient/OpcUaInterface.hpp Outdated Show resolved Hide resolved
Copy link
Member

@ccvca ccvca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GoetzGoerisch The linter check seems broken?

}
}
//Hotfix clear subscription cache.
m_subscribedValues.clear();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intended to be outside the If's?

if(placeHolderNode == nullptr) { continue;}
std::list<ModelOpcUa::PlaceholderElement> instances = placeHolderNode->getInstances();
for(auto& el : instances) {
deleteAndUnsubscribeNode(el);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::foreach

if(placeHolderNode != nullptr) {
std::list<ModelOpcUa::PlaceholderElement> instances = placeHolderNode->getInstances();
for(std::list<ModelOpcUa::PlaceholderElement>::iterator it = instances.begin(); it != instances.end(); it++) {
deleteAndUnsubscribeNode(*it);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::foreach

this->updateAddDataSet(sce.refreshNode);
this->Publish();
});
t.detach();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is ensured, that the DashboardClient instance is available until this thread is completed. (e.g. when started before a shutdown of the application)

}
this -> Publish();
});
t.detach();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Object lifetime issues? (this)

MachineObserver/DashboardMachineObserver.hpp Outdated Show resolved Hide resolved
OpcUaClient/OpcUaClient.cpp Outdated Show resolved Hide resolved
OpcUaClient/OpcUaInterface.hpp Show resolved Hide resolved
OpcUaClient/OpcUaInterface.hpp Outdated Show resolved Hide resolved
OpcUaClient/OpcUaInterface.hpp Outdated Show resolved Hide resolved
@Kantiran91 Kantiran91 added this to the HMI 2023 milestone Mar 17, 2023
Copy link
Member

@ccvca ccvca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run a memory check, There are propably more memory leaks.

}
this -> Publish();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation looks suscious.
A continue inside should allow to preoces more than 10 Events per seconds (in case of busy OPC UA Servers)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by Threadsafe queue!


void DashboardClient::updateDeleteDataSet(ModelOpcUa::NodeId_t refreshNodeId) {
auto search = browsedSimpleNodes.find(refreshNodeId);
if( search != browsedSimpleNodes.end()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invert + Return

if( search != browsedSimpleNodes.end()) {
std::shared_ptr<const ModelOpcUa::SimpleNode> simpleNode = search->second;
auto childNodes = simpleNode->ChildNodes;
if(!childNodes.empty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invert + Return

}
void DashboardClient::deleteAndUnsubscribeNode(const ModelOpcUa::SimpleNode simpleNode) {
const std::list<std::shared_ptr<const ModelOpcUa::Node>> children = simpleNode.ChildNodes;
for(auto node : children) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks identical to the method above? Use a single function for this?

}
void DashboardClient::subscribeEvents() {
auto ecbf = [this](IDashboardDataClient::StructureChangeEvent sce) {
this->m_eventqueue.push(sce);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::queue is not thread safe, mutex required.

}

contentFilter.elementsSize = 1;
contentFilter.elements = (UA_ContentFilterElement* ) UA_Array_new(contentFilter.elementsSize, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UA_ContentFilterElement_new?

if(contentFilterElement.filterOperands) {
contentFilterElement.filterOperands[0] = extensionObject;
} else {
UA_ContentFilterElement_delete(&contentFilterElement);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleting a stack variable?

item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER];

UA_MonitoredItemCreateResult result = UA_Client_MonitoredItems_createEvent(client, subId, UA_TIMESTAMPSTORETURN_BOTH, item, this, handler_events, NULL);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
UA_DeleteSubscriptionsRequest_clear(&deleteRequest);
UA_DeleteSubscriptionsResponse_clear(&response);
UA_Array_delete(pSubscriptionId, 1, &UA_TYPES[UA_TYPES_UINT32]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this already deleted by the previous UA_DeleteSubscriptionsRequest_clear ?

Dashboard::IDashboardDataClient::eventCallbackFunction_t eventcallback) {
this->eventcallback = eventcallback;
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request, NULL, NULL, NULL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing _clear

}

void DashboardClient::startEventThread() {
if (m_eventThreadRunning)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_eventThreadRunning is

  • a missleading name, more like m_keepEventThreadRunning
  • is m_eventThreadRunning synchronized and wrapped by a mutex?

m_eventThread = std::thread(func);
}
void DashboardClient::stopEventThread() {
m_eventThreadRunning = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_eventThreadRunning is not protected. Might lead to memory corruption

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by atomic bool.

@@ -25,7 +25,22 @@ namespace Umati
class IDashboardDataClient
{
public:
/// Struct for handling Events
struct StructureChangeEvent{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can there be more than one true, otherwise use ENUM?

};
} // namespace OpcUa
} // namespace Umati
void SubscriptionUnsubscribe(UA_Client *client, std::vector<int32_t> monItemIds, std::vector<int32_t> clientHandles){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving some parts out to reusable functions?

this->startEventThread();
}

DashboardClient::~DashboardClient() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best practice is following the rule of tree.

https://en.cppreference.com/w/cpp/language/rule_of_three


auto func = [this]() {
int cnt = 0;
while (this->m_eventThreadRunning) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not protected by mutex

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by atomic.

std::recursive_mutex m_dataSetMutex;
std::list<std::shared_ptr<DataSetStorage_t>> m_dataSets;
std::map<std::string, LastMessage_t> m_latestMessages;

bool m_eventThreadRunning;
std::thread m_eventThread;
std::queue<IDashboardDataClient::StructureChangeEvent> m_eventqueue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::queue is not threadsafe! Add mutex/lockfree queue or sth

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by a threadsafe queue.

if(value && value.get()->getNodeId() == pNode.get()->NodeId)
return;
if(value && value.get()->getNodeId() == pNode.get()->NodeId) {
//LOG(INFO) << "Allready Subscribed" << value.get()->getNodeId();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you?

return;
}
auto child = childNodes.front();
std::shared_ptr<const ModelOpcUa::PlaceholderNode> placeholderNode = std::dynamic_pointer_cast<const ModelOpcUa::PlaceholderNode>(child);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make data model non-const?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This involves changeing some classes in the model and i the codebase. I want to do this, but maybe it is better to do this in a separate task.

@wlkrm
Copy link
Contributor

wlkrm commented Apr 28, 2023

LGTM, after the remaining comments are resolved.

@GoetzGoerisch
Copy link
Member

@mdornaus when could you resolve the remaining comments and rebase?

@DasbachVDMA
Copy link
Contributor

Don't merge, moce to new gateway.

@DasbachVDMA DasbachVDMA closed this Apr 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants