Python wrapper: about the wrapped callbacks, maintain a 'map' of subscribers

The 'callback' function is a part of the 'Subscriber' class.
Once the 'event' (or asynchronous message) is received, the 'Subscriber' object
forwards the data to the 'Handler' object.
With this approach, the 'event' processing algorithm can be defined
in a Python subclass by the user.

Each 'subscriber' class has a function that matches the C function pointer.
But this function is a static method, shared with all instances of the class.
In order to dispatch the message/data to the right instance,
we maintain a dictionary of instantiated objects.

Therfore, we have added the following internal services :
 * bool registerNewSubscriber(EventSubscriber*, id);
 * EventSubscriber* findSubscriber(id);
 * void unregisterSubscriber(id);
pull/309/head
Mikael Bourhis 5 years ago
parent b1fc481ab8
commit e47601a81e

@ -33,12 +33,12 @@ class CommandTermSubscriber: public EventSubscriber {
virtual ~CommandTermSubscriber() {}
virtual void subscribe()
virtual bool subscribe()
{
// preconditions
if (nullptr == m_libiec61850_control_object_client) {
fprintf(stderr, "CommandTermSubscriber::subscribe() failed: 'control object client' is null\n");
return;
return false;
}
// install the libiec61850 callback:
@ -47,6 +47,10 @@ class CommandTermSubscriber: public EventSubscriber {
m_libiec61850_control_object_client,
CommandTermSubscriber::triggerCommandTermHandler,
NULL);
std::string l_object_ref = ControlObjectClient_getObjectReference(m_libiec61850_control_object_client);
return (EventSubscriber::registerNewSubscriber(this, l_object_ref));
}
// Static method: it is the 'callback' for libiec61850 in C
@ -60,9 +64,12 @@ class CommandTermSubscriber: public EventSubscriber {
return;
}
// TODO: search the appropriate 'EventSubscriber' object
if (m_last_created_event_subscriber) {
EventHandler *l_event_handler_p = m_last_created_event_subscriber->getEventHandler();
// Search the appropriate 'EventSubscriber' object
std::string l_subscriber_id = ControlObjectClient_getObjectReference(connection);
EventSubscriber *l_registered_subscriber = EventSubscriber::findSubscriber(l_subscriber_id);
if (l_registered_subscriber) {
EventHandler *l_event_handler_p = l_registered_subscriber->getEventHandler();
if (l_event_handler_p) {
l_event_handler_p->setReceivedData(&connection);
l_event_handler_p->trigger();

@ -28,6 +28,7 @@ private:
class EventHandler {
public:
EventHandler() {}
virtual ~EventHandler() {}
virtual void setReceivedData(void *i_data_p) = 0;
virtual void trigger() = 0;
@ -36,13 +37,9 @@ class EventHandler {
class EventSubscriber {
public:
// TODO: use a map to store and find the instantiated EventSubscriber
static EventSubscriber* m_last_created_event_subscriber;
EventSubscriber(): _event_handler_p(nullptr)
{
m_last_created_event_subscriber = this;
// add python thread support
Py_Initialize();
PyEval_InitThreads();
@ -50,11 +47,11 @@ class EventSubscriber {
virtual ~EventSubscriber()
{
EventSubscriber::unregisterSubscriber(m_subscriber_id);
deleteEventHandler();
m_last_created_event_subscriber = nullptr;
}
virtual void subscribe() = 0;
virtual bool subscribe() = 0;
void deleteEventHandler()
{
@ -75,8 +72,59 @@ class EventSubscriber {
return _event_handler_p;
}
void setSubscriberId(const std::string &i_id)
{
m_subscriber_id = i_id;
}
protected:
static std::map<std::string, EventSubscriber*> m_subscriber_map;
static bool registerNewSubscriber(EventSubscriber *i_new_subscriber, const std::string &i_id)
{
// Preconditions
if (i_id.empty()) {
fprintf(stderr, "EventSubscriber::subscribe() failed: the subscriber id is empty\n");
return false;
}
if (m_subscriber_map.end() != m_subscriber_map.find(i_id)) {
fprintf(stderr, "EventSubscriber::subscribe() failed: the subscriber is already registered\n");
return false;
}
m_subscriber_map[i_id] = i_new_subscriber;
i_new_subscriber->setSubscriberId(i_id);
return true;
}
static EventSubscriber* findSubscriber(const std::string &i_id)
{
EventSubscriber *o_found_event_subscriber_p = nullptr;
std::map<std::string, EventSubscriber*>::iterator l_it = m_subscriber_map.find(i_id);
if (m_subscriber_map.end() != l_it) {
o_found_event_subscriber_p = l_it->second;
}
return o_found_event_subscriber_p;
}
static void unregisterSubscriber(const std::string &i_subscriber_id)
{
std::map<std::string, EventSubscriber*>::iterator l_it = m_subscriber_map.find(i_subscriber_id);
if (m_subscriber_map.end() != l_it) {
m_subscriber_map.erase(l_it);
}
else {
fprintf(stderr, "EventSubscriber::unregisterSubscriber() failed: '%s' is not registered\n");
}
}
private:
EventHandler *_event_handler_p;
std::string m_subscriber_id;
};
#endif

@ -29,13 +29,12 @@ class GooseSubscriberForPython: public EventSubscriber {
virtual ~GooseSubscriberForPython() {}
virtual void subscribe()
virtual bool subscribe()
{
// preconditions
if (nullptr == m_libiec61850_goose_subscriber) {
fprintf(stderr, "GooseSubscriberForPython::subscribe() failed: 'GOOSE subscriber' is null\n");
return;
return false;
}
// install the libiec61850 callback:
@ -43,6 +42,10 @@ class GooseSubscriberForPython: public EventSubscriber {
GooseSubscriber_setListener(m_libiec61850_goose_subscriber,
GooseSubscriberForPython::triggerGooseHandler,
NULL);
std::string l_go_cb_ref = GooseSubscriber_getGoCbRef(m_libiec61850_goose_subscriber);
return (EventSubscriber::registerNewSubscriber(this, l_go_cb_ref));
}
// Static method: it is the 'callback' for libiec61850 in C
@ -56,9 +59,12 @@ class GooseSubscriberForPython: public EventSubscriber {
return;
}
// TODO: search the appropriate 'EventSubscriber' object
if (m_last_created_event_subscriber) {
EventHandler *l_event_handler_p = m_last_created_event_subscriber->getEventHandler();
// Search the appropriate 'EventSubscriber' object
std::string l_subscriber_id = GooseSubscriber_getGoCbRef(subscriber);
EventSubscriber *l_registered_subscriber = EventSubscriber::findSubscriber(l_subscriber_id);
if (l_registered_subscriber) {
EventHandler *l_event_handler_p = l_registered_subscriber->getEventHandler();
if (l_event_handler_p) {
l_event_handler_p->setReceivedData(&subscriber);
l_event_handler_p->trigger();

@ -29,12 +29,11 @@ class RCBSubscriber: public EventSubscriber {
virtual ~RCBSubscriber() {}
virtual void subscribe() {
virtual bool subscribe() {
// preconditions
if (nullptr == m_ied_connection) {
fprintf(stderr, "RCBSubscriber::subscribe() failed: 'IedConnection' is null\n");
return;
return false;
}
// install the libiec61850 callback:
@ -44,6 +43,8 @@ class RCBSubscriber: public EventSubscriber {
m_rcb_rpt_id.c_str(),
RCBSubscriber::triggerRCBHandler,
NULL);
return (EventSubscriber::registerNewSubscriber(this, m_rcb_reference));
}
// Static method: it is the 'callback' for libiec61850 in C
@ -57,9 +58,12 @@ class RCBSubscriber: public EventSubscriber {
return;
}
// TODO: search the appropriate 'EventSubscriber' object
if (m_last_created_event_subscriber) {
EventHandler *l_event_handler_p = m_last_created_event_subscriber->getEventHandler();
// Search the appropriate 'EventSubscriber' object
std::string l_subscriber_id = ClientReport_getRcbReference(report);
EventSubscriber *l_registered_subscriber = EventSubscriber::findSubscriber(l_subscriber_id);
if (l_registered_subscriber) {
EventHandler *l_event_handler_p = l_registered_subscriber->getEventHandler();
if (l_event_handler_p) {
l_event_handler_p->setReceivedData(&report);
l_event_handler_p->trigger();

@ -104,7 +104,7 @@ void GooseSubscriber_setDstMac(GooseSubscriber subscriber,
#include "eventHandlers/reportControlBlockHandler.hpp"
#include "eventHandlers/gooseHandler.hpp"
#include "eventHandlers/commandTermHandler.hpp"
EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr;
std::map< std::string, EventSubscriber*> EventSubscriber::m_subscriber_map = {};
%}
%include "eventHandlers/eventHandler.hpp"
%include "eventHandlers/reportControlBlockHandler.hpp"

Loading…
Cancel
Save