diff --git a/pyiec61850/eventHandlers/commandTermHandler.hpp b/pyiec61850/eventHandlers/commandTermHandler.hpp new file mode 100644 index 00000000..64fb6e38 --- /dev/null +++ b/pyiec61850/eventHandlers/commandTermHandler.hpp @@ -0,0 +1,97 @@ +#ifndef PYIEC61850_COMMANDTERMHANDLER_HPP +#define PYIEC61850_COMMANDTERMHANDLER_HPP + +#include "eventHandler.hpp" + +/* + * Abstract class for processing the received 'Command Termination' events. + */ +class CommandTermHandler: public EventHandler { + public: + virtual ~CommandTermHandler() {} + + virtual void setReceivedData(void *i_data_p) + { + // copy the received data + ControlObjectClient *l_my_data_p = static_cast(i_data_p); + _libiec61850_control_object_client = *l_my_data_p; + } + + ControlObjectClient _libiec61850_control_object_client; +}; + + +/* + * Class for the subscription to the 'Command Termination' events + */ +class CommandTermSubscriber: public EventSubscriber { + public: + CommandTermSubscriber(): EventSubscriber() + { + m_libiec61850_control_object_client = nullptr; + } + + virtual ~CommandTermSubscriber() {} + + virtual bool subscribe() + { + // preconditions + if (nullptr == m_libiec61850_control_object_client) { + fprintf(stderr, "CommandTermSubscriber::subscribe() failed: 'control object client' is null\n"); + return false; + } + + // install the libiec61850 callback: + // the 'function pointer' is the 'static' method of this class + ControlObjectClient_setCommandTerminationHandler( + 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 + static void triggerCommandTermHandler(void *parameter, ControlObjectClient connection) + { + PyThreadStateLock PyThreadLock; + + // Preconditions + if (nullptr == connection) { + fprintf(stderr, "CommandTermSubscriber::triggerCommandTermHandler() failed: input object is null\n"); + return; + } + + // 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(); + } + else { + fprintf(stderr, "CommandTermSubscriber::triggerCommandTermHandler() failed: EventHandler is undefined\n"); + } + } + else { + fprintf(stderr, "CommandTermSubscriber::triggerCommandTermHandler() failed: subscriber is not registered\n"); + } + } + + // Setters + void setLibiec61850ControlObjectClient(const ControlObjectClient &i_libiec61850_control_object_client) + { + m_libiec61850_control_object_client = i_libiec61850_control_object_client; + } + + protected: + // Parameters + ControlObjectClient m_libiec61850_control_object_client; +}; + +#endif 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 a01d3a6a..5984d478 100644 --- a/pyiec61850/eventHandlers/gooseHandler.hpp +++ b/pyiec61850/eventHandlers/gooseHandler.hpp @@ -22,13 +22,30 @@ class GooseHandler: public EventHandler { class GooseSubscriberForPython: public EventSubscriber { public: + GooseSubscriberForPython(): EventSubscriber() + { + m_libiec61850_goose_subscriber = nullptr; + } + + virtual ~GooseSubscriberForPython() {} + + virtual bool subscribe() + { + // preconditions + if (nullptr == m_libiec61850_goose_subscriber) { + fprintf(stderr, "GooseSubscriberForPython::subscribe() failed: 'GOOSE subscriber' is null\n"); + return false; + } - virtual void subscribe() { // install the libiec61850 callback: // the 'function pointer' is the 'static' method of this class 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 @@ -36,17 +53,29 @@ class GooseSubscriberForPython: public EventSubscriber { { PyThreadStateLock PyThreadLock; - // TODO: search the appropriate 'EventSubscriber' object - if (m_last_created_event_subscriber) { - EventHandler *l_event_handler_p = m_last_created_event_subscriber->getEventHandler(); + // Preconditions + if (nullptr == subscriber) { + fprintf(stderr, "GooseSubscriberForPython::triggerGooseHandler() failed: input object is null\n"); + return; + } + + // 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(); } else { - printf("The EventHandler is undefined\n"); + fprintf(stderr, "GooseSubscriberForPython::triggerGooseHandler() failed: EventHandler is undefined\n"); } } + else { + fprintf(stderr, "GooseSubscriberForPython::triggerGooseHandler() failed: subscriber is not registered\n"); + } } // Setters diff --git a/pyiec61850/eventHandlers/reportControlBlockHandler.hpp b/pyiec61850/eventHandlers/reportControlBlockHandler.hpp index ad798c1d..25411ae3 100644 --- a/pyiec61850/eventHandlers/reportControlBlockHandler.hpp +++ b/pyiec61850/eventHandlers/reportControlBlockHandler.hpp @@ -22,8 +22,20 @@ class RCBHandler: public EventHandler { class RCBSubscriber: public EventSubscriber { public: + RCBSubscriber(): EventSubscriber() + { + m_ied_connection = nullptr; + } + + virtual ~RCBSubscriber() {} + + virtual bool subscribe() { + // preconditions + if (nullptr == m_ied_connection) { + fprintf(stderr, "RCBSubscriber::subscribe() failed: 'IedConnection' is null\n"); + return false; + } - virtual void subscribe() { // install the libiec61850 callback: // the 'function pointer' is the 'static' method of this class IedConnection_installReportHandler(m_ied_connection, @@ -31,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 @@ -38,17 +52,29 @@ class RCBSubscriber: public EventSubscriber { { PyThreadStateLock PyThreadLock; - // TODO: search the appropriate 'EventSubscriber' object - if (m_last_created_event_subscriber) { - EventHandler *l_event_handler_p = m_last_created_event_subscriber->getEventHandler(); + // Preconditions + if (nullptr == report) { + fprintf(stderr, "RCBSubscriber::triggerRCBHandler() failed: input object is null\n"); + return; + } + + // 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(); } else { - printf("The EventHandler is undefined\n"); + fprintf(stderr, "RCBSubscriber::triggerRCBHandler() failed: EventHandler is undefined\n"); } } + else { + fprintf(stderr, "RCBSubscriber::triggerRCBHandler() failed: subscriber is not registered\n"); + } } // Setters diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 71aceaef..26f6655f 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -98,15 +98,18 @@ void GooseSubscriber_setDstMac(GooseSubscriber subscriber, /* Event Handler section */ %feature("director") RCBHandler; %feature("director") GooseHandler; +%feature("director") CommandTermHandler; %{ #include "eventHandlers/eventHandler.hpp" #include "eventHandlers/reportControlBlockHandler.hpp" #include "eventHandlers/gooseHandler.hpp" -EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr; +#include "eventHandlers/commandTermHandler.hpp" +std::map< std::string, EventSubscriber*> EventSubscriber::m_subscriber_map = {}; %} %include "eventHandlers/eventHandler.hpp" %include "eventHandlers/reportControlBlockHandler.hpp" %include "eventHandlers/gooseHandler.hpp" +%include "eventHandlers/commandTermHandler.hpp" /* Goose Publisher section */ %{