From e47601a81e5cb0a2fa0a1c49f6800a2579bd96ef Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Wed, 3 Feb 2021 14:46:50 +0100 Subject: [PATCH] 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); --- .../eventHandlers/commandTermHandler.hpp | 17 ++++-- pyiec61850/eventHandlers/eventHandler.hpp | 60 +++++++++++++++++-- pyiec61850/eventHandlers/gooseHandler.hpp | 18 ++++-- .../reportControlBlockHandler.hpp | 16 +++-- pyiec61850/iec61850.i | 2 +- 5 files changed, 89 insertions(+), 24 deletions(-) diff --git a/pyiec61850/eventHandlers/commandTermHandler.hpp b/pyiec61850/eventHandlers/commandTermHandler.hpp index 2c91e338..64fb6e38 100644 --- a/pyiec61850/eventHandlers/commandTermHandler.hpp +++ b/pyiec61850/eventHandlers/commandTermHandler.hpp @@ -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(); diff --git a/pyiec61850/eventHandlers/eventHandler.hpp b/pyiec61850/eventHandlers/eventHandler.hpp index 1ef20f7b..e69bf476 100644 --- a/pyiec61850/eventHandlers/eventHandler.hpp +++ b/pyiec61850/eventHandlers/eventHandler.hpp @@ -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 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::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::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 diff --git a/pyiec61850/eventHandlers/gooseHandler.hpp b/pyiec61850/eventHandlers/gooseHandler.hpp index f0b4f1d2..5984d478 100644 --- a/pyiec61850/eventHandlers/gooseHandler.hpp +++ b/pyiec61850/eventHandlers/gooseHandler.hpp @@ -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(); diff --git a/pyiec61850/eventHandlers/reportControlBlockHandler.hpp b/pyiec61850/eventHandlers/reportControlBlockHandler.hpp index 13d71e9d..25411ae3 100644 --- a/pyiec61850/eventHandlers/reportControlBlockHandler.hpp +++ b/pyiec61850/eventHandlers/reportControlBlockHandler.hpp @@ -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(); diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 64cd3298..26f6655f 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -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"