From c2c7c7171ebfc81ce22773f3e0ff41d52228bd8d Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Thu, 16 Jul 2020 00:35:20 +0200 Subject: [PATCH 01/10] Python wrapper: add 'user-defined data types' for Timestamp (msSinceEpoch, nsSinceEpoch) --- pyiec61850/iec61850.i | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 65e0906f..d4a91afb 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -41,6 +41,11 @@ DataAttribute* toDataAttribute(ModelNode * MN) %include "iec61850_dynamic_model.h" %include "iec61850_cdc.h" %include "linked_list.h" + +/* User-defined data types, also used: */ +typedef uint64_t msSinceEpoch; +typedef uint64_t nsSinceEpoch; + ModelNode* toModelNode(LogicalNode *); ModelNode* toModelNode(DataObject *); DataAttribute* toDataAttribute(DataObject *); From 7c68e3e3f6efc9d7df55f2b5b2a6943c2115660b Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Mon, 27 Jul 2020 15:44:55 +0200 Subject: [PATCH 02/10] Python wrapper: add the support of the 'Goose subscription' The callback for the processing of the received GOOSE is still missing for now. --- pyiec61850/iec61850.i | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index d4a91afb..9869c69f 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -51,3 +51,42 @@ ModelNode* toModelNode(DataObject *); DataAttribute* toDataAttribute(DataObject *); DataAttribute* toDataAttribute(ModelNode *); char* toCharP(void *); + +/* Goose Subscriber section */ +%{ +struct sGooseSubscriber; +typedef struct sGooseSubscriber* GooseSubscriber; +#include "goose_subscriber.h" +#include "goose_receiver.h" + +void GooseSubscriber_setDstMac(GooseSubscriber subscriber, + uint8_t dst_mac_0, + uint8_t dst_mac_1, + uint8_t dst_mac_2, + uint8_t dst_mac_3, + uint8_t dst_mac_4, + uint8_t dst_mac_5) +{ + uint8_t dst_mac[6]; + dst_mac[0] = dst_mac_0; + dst_mac[1] = dst_mac_1; + dst_mac[2] = dst_mac_2; + dst_mac[3] = dst_mac_3; + dst_mac[4] = dst_mac_4; + dst_mac[5] = dst_mac_5; + + GooseSubscriber_setDstMac(subscriber, dst_mac); +} +%} + +%include "goose_subscriber.h" +%include "goose_receiver.h" + +void GooseSubscriber_setDstMac(GooseSubscriber subscriber, + uint8_t dst_mac_0, + uint8_t dst_mac_1, + uint8_t dst_mac_2, + uint8_t dst_mac_3, + uint8_t dst_mac_4, + uint8_t dst_mac_5); + From 7bac9356486de5f8ee1103449c172a94baa628ca Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Wed, 29 Jul 2020 16:01:33 +0200 Subject: [PATCH 03/10] Python wrapper: add generic classes for handling events (like ReportControlBlock or GOOSE) --- pyiec61850/eventHandler.hpp | 82 +++++++++++++++++++++++++++++++++++++ pyiec61850/iec61850.i | 8 +++- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 pyiec61850/eventHandler.hpp diff --git a/pyiec61850/eventHandler.hpp b/pyiec61850/eventHandler.hpp new file mode 100644 index 00000000..1ef20f7b --- /dev/null +++ b/pyiec61850/eventHandler.hpp @@ -0,0 +1,82 @@ +#ifndef PYIEC61850_EVENTHANDLER_HPP +#define PYIEC61850_EVENTHANDLER_HPP + + +#include "iec61850_client.h" +#include +#include + + +class PyThreadStateLock +{ +public: + PyThreadStateLock(void) + { + state = PyGILState_Ensure( ); + } + + ~PyThreadStateLock(void) + { + PyGILState_Release( state ); + } + +private: + PyGILState_STATE state; +}; + + + +class EventHandler { + public: + virtual ~EventHandler() {} + virtual void setReceivedData(void *i_data_p) = 0; + virtual void trigger() = 0; +}; + + +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(); + } + + virtual ~EventSubscriber() + { + deleteEventHandler(); + m_last_created_event_subscriber = nullptr; + } + + virtual void subscribe() = 0; + + void deleteEventHandler() + { + if (_event_handler_p) { + delete _event_handler_p; + } + _event_handler_p = nullptr; + } + + void setEventHandler(EventHandler *i_event_handler_p) + { + deleteEventHandler(); + _event_handler_p = i_event_handler_p; + } + + EventHandler *getEventHandler() + { + return _event_handler_p; + } + + private: + EventHandler *_event_handler_p; +}; + +#endif diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 9869c69f..23c5e746 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -1,5 +1,5 @@ /* File : iec61850.i */ -%module iec61850 +%module(directors="1") iec61850 %ignore ControlObjectClient_setTestMode(ControlObjectClient self); %ignore CDA_OperBoolean(ModelNode* parent, bool isTImeActivated); %ignore LogicalNode_hasBufferedReports(LogicalNode* node); @@ -90,3 +90,9 @@ void GooseSubscriber_setDstMac(GooseSubscriber subscriber, uint8_t dst_mac_4, uint8_t dst_mac_5); +/* Event Handler section */ +%{ +#include "eventHandler.hpp" +EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr; +%} +%include "eventHandler.hpp" From ca97f2548fa8fa37a245d43edf136dee7f6aafdd Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Wed, 29 Jul 2020 16:04:03 +0200 Subject: [PATCH 04/10] Python wrapper: add handler class for the reception of ReportControlBlock events --- pyiec61850/iec61850.i | 3 ++ pyiec61850/reportControlBlockHandler.hpp | 66 ++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 pyiec61850/reportControlBlockHandler.hpp diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 23c5e746..0a5d45d0 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -91,8 +91,11 @@ void GooseSubscriber_setDstMac(GooseSubscriber subscriber, uint8_t dst_mac_5); /* Event Handler section */ +%feature("director") RCBHandler; %{ #include "eventHandler.hpp" +#include "reportControlBlockHandler.hpp" EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr; %} %include "eventHandler.hpp" +%include "reportControlBlockHandler.hpp" diff --git a/pyiec61850/reportControlBlockHandler.hpp b/pyiec61850/reportControlBlockHandler.hpp new file mode 100644 index 00000000..ad798c1d --- /dev/null +++ b/pyiec61850/reportControlBlockHandler.hpp @@ -0,0 +1,66 @@ +#ifndef PYIEC61850_RCBHANDLER_HPP +#define PYIEC61850_RCBHANDLER_HPP + +#include "eventHandler.hpp" + + +class RCBHandler: public EventHandler { + public: + virtual ~RCBHandler() {} + + virtual void setReceivedData(void *i_data_p) + { + // copy the received data + ClientReport *l_my_data_p = static_cast(i_data_p); + _client_report = *l_my_data_p; + } + + ClientReport _client_report; +}; + + + +class RCBSubscriber: public EventSubscriber { + public: + + virtual void subscribe() { + // install the libiec61850 callback: + // the 'function pointer' is the 'static' method of this class + IedConnection_installReportHandler(m_ied_connection, + m_rcb_reference.c_str(), + m_rcb_rpt_id.c_str(), + RCBSubscriber::triggerRCBHandler, + NULL); + } + + // Static method: it is the 'callback' for libiec61850 in C + static void triggerRCBHandler(void *parameter, ClientReport report) + { + 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(); + if (l_event_handler_p) { + l_event_handler_p->setReceivedData(&report); + l_event_handler_p->trigger(); + } + else { + printf("The EventHandler is undefined\n"); + } + } + } + + // Setters + void setIedConnection(const IedConnection &i_ied_connection) {m_ied_connection = i_ied_connection;} + void setRcbReference(const char *i_rcb_reference) {m_rcb_reference = i_rcb_reference;} + void setRcbRptId(const char *i_rcb_rpt_id) {m_rcb_rpt_id = i_rcb_rpt_id;} + + protected: + // Parameters + IedConnection m_ied_connection; + std::string m_rcb_reference; + std::string m_rcb_rpt_id; +}; + +#endif From 30f98e54cb833177db5e9404ed34506b89d76e32 Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Thu, 30 Jul 2020 14:39:26 +0200 Subject: [PATCH 05/10] Python wrapper: add handler class for the reception of GOOSE events --- pyiec61850/gooseHandler.hpp | 63 +++++++++++++++++++++++++++++++++++++ pyiec61850/iec61850.i | 3 ++ 2 files changed, 66 insertions(+) create mode 100644 pyiec61850/gooseHandler.hpp diff --git a/pyiec61850/gooseHandler.hpp b/pyiec61850/gooseHandler.hpp new file mode 100644 index 00000000..a01d3a6a --- /dev/null +++ b/pyiec61850/gooseHandler.hpp @@ -0,0 +1,63 @@ +#ifndef PYIEC61850_GOOSEHANDLER_HPP +#define PYIEC61850_GOOSEHANDLER_HPP + +#include "eventHandler.hpp" + + +class GooseHandler: public EventHandler { + public: + virtual ~GooseHandler() {} + + virtual void setReceivedData(void *i_data_p) + { + // copy the received data + GooseSubscriber *l_my_data_p = static_cast(i_data_p); + _libiec61850_goose_subscriber = *l_my_data_p; + } + + GooseSubscriber _libiec61850_goose_subscriber; +}; + + + +class GooseSubscriberForPython: public EventSubscriber { + public: + + 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); + } + + // Static method: it is the 'callback' for libiec61850 in C + static void triggerGooseHandler(GooseSubscriber subscriber, void *parameter) + { + 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(); + if (l_event_handler_p) { + l_event_handler_p->setReceivedData(&subscriber); + l_event_handler_p->trigger(); + } + else { + printf("The EventHandler is undefined\n"); + } + } + } + + // Setters + void setLibiec61850GooseSubscriber(const GooseSubscriber &i_libiec61850_goose_subscriber) + { + m_libiec61850_goose_subscriber = i_libiec61850_goose_subscriber; + } + + protected: + // Parameters + GooseSubscriber m_libiec61850_goose_subscriber; +}; + +#endif diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 0a5d45d0..ffbf2f8b 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -92,10 +92,13 @@ void GooseSubscriber_setDstMac(GooseSubscriber subscriber, /* Event Handler section */ %feature("director") RCBHandler; +%feature("director") GooseHandler; %{ #include "eventHandler.hpp" #include "reportControlBlockHandler.hpp" +#include "gooseHandler.hpp" EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr; %} %include "eventHandler.hpp" %include "reportControlBlockHandler.hpp" +%include "gooseHandler.hpp" From 172883478a032103e8b977ba7ee1f7e6a17d41dd Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Fri, 31 Jul 2020 12:06:35 +0200 Subject: [PATCH 06/10] Python wrapper: declare all the C 'char *buffer' output parameters as a Python output string of 1024 max size Needed for example for: - MmsValue_printToBuffer(values, buffer, buffer_size); --- pyiec61850/iec61850.i | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index ffbf2f8b..50d8b2ff 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -29,6 +29,9 @@ DataAttribute* toDataAttribute(ModelNode * MN) %} %apply int *OUTPUT {IedClientError* error}; +%include "cstring.i" +%cstring_bounded_output(char *buffer, 1024); + %include "libiec61850_common_api.h" %include "iec61850_client.h" %include "iso_connection_parameters.h" From dcbd9f94ab055784c38c0a93413b00d668e93ecc Mon Sep 17 00:00:00 2001 From: Romain Naour Date: Thu, 7 May 2020 09:16:14 +0200 Subject: [PATCH 07/10] examples/server_example_basic_io There is an access error while using iec61850_client_example1 with server_example_basic_io. From [1]: /* write a variable to the server */ value = MmsValue_newVisibleString("libiec61850.com"); IedConnection_writeObject(con, &error, "simpleIOGenericIO/GGIO1.NamPlt.vendor", IEC61850_FC_DC, value); The error code is IED_ERROR_ACCESS_DENIED = 21. By default access to variables with FC=DC and FC=CF is not allowed, fix this by changing the access policy as suggested by [2]. [1] https://github.com/mz-automation/libiec61850/blob/v1.4.2.1/examples/iec61850_client_example1/client_example1.c#L71 [2] https://libiec61850.com/libiec61850/documentation/iec-61850-client-tutorial/#comment-61994 Signed-off-by: Romain Naour --- examples/server_example_basic_io/server_example_basic_io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/server_example_basic_io/server_example_basic_io.c b/examples/server_example_basic_io/server_example_basic_io.c index 4966f33d..d2fc9279 100644 --- a/examples/server_example_basic_io/server_example_basic_io.c +++ b/examples/server_example_basic_io/server_example_basic_io.c @@ -136,6 +136,12 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + /* By default access to variables with FC=DC and FC=CF is not allowed. + * This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used + * by iec61850_client_example1. + */ + IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW); + /* MMS server will be instructed to start listening for client connections. */ IedServer_start(iedServer, 102); From f5b5c0d3ad7ee4c2d4e9397c51433a024988dc7f Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Wed, 2 Sep 2020 16:26:32 +0200 Subject: [PATCH 08/10] Python wrapper: add the support of the 'Goose publishing' --- pyiec61850/iec61850.i | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 50d8b2ff..f638aa35 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -105,3 +105,38 @@ EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr; %include "eventHandler.hpp" %include "reportControlBlockHandler.hpp" %include "gooseHandler.hpp" + +/* Goose Publisher section */ +%{ +#include "goose_publisher.h" + +void LinkedList_destroyDeep_MmsValueDelete(LinkedList dataSetValues) +{ + LinkedList_destroyDeep(dataSetValues, (LinkedListValueDeleteFunction) MmsValue_delete); +} +void CommParameters_setDstAddress(CommParameters *gooseCommParameters, + uint8_t dst_mac_0, + uint8_t dst_mac_1, + uint8_t dst_mac_2, + uint8_t dst_mac_3, + uint8_t dst_mac_4, + uint8_t dst_mac_5) +{ + gooseCommParameters->dstAddress[0] = dst_mac_0; + gooseCommParameters->dstAddress[1] = dst_mac_1; + gooseCommParameters->dstAddress[2] = dst_mac_2; + gooseCommParameters->dstAddress[3] = dst_mac_3; + gooseCommParameters->dstAddress[4] = dst_mac_4; + gooseCommParameters->dstAddress[5] = dst_mac_5; +} +%} +%include "goose_publisher.h" +void LinkedList_destroyDeep_MmsValueDelete(LinkedList dataSetValues); +void CommParameters_setDstAddress(CommParameters *gooseCommParameters, + uint8_t dst_mac_0, + uint8_t dst_mac_1, + uint8_t dst_mac_2, + uint8_t dst_mac_3, + uint8_t dst_mac_4, + uint8_t dst_mac_5); + From 473eec846494e0f3afa73cc302d4e35b58553a4b Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Wed, 2 Sep 2020 12:38:21 +0200 Subject: [PATCH 09/10] - GOOSE/SV publisher: remove internal header file from API header (cherry picked from commit 46d6769a891f90b12aea48b443724e3a6e35fafb) [Romain: Apply the patch to v1.5] Signed-off-by: Romain Naour --- src/goose/goose_publisher.h | 2 +- src/sampled_values/sv_publisher.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/goose/goose_publisher.h b/src/goose/goose_publisher.h index 412a4e7b..848608d2 100644 --- a/src/goose/goose_publisher.h +++ b/src/goose/goose_publisher.h @@ -24,7 +24,7 @@ #ifndef GOOSE_PUBLISHER_H_ #define GOOSE_PUBLISHER_H_ -#include "libiec61850_platform_includes.h" +#include "iec61850_common.h" #include "linked_list.h" #include "mms_value.h" diff --git a/src/sampled_values/sv_publisher.h b/src/sampled_values/sv_publisher.h index c737ae5f..f753dc5d 100644 --- a/src/sampled_values/sv_publisher.h +++ b/src/sampled_values/sv_publisher.h @@ -25,7 +25,6 @@ #ifndef LIBIEC61850_SRC_SAMPLED_VALUES_SV_PUBLISHER_H_ #define LIBIEC61850_SRC_SAMPLED_VALUES_SV_PUBLISHER_H_ -#include "libiec61850_platform_includes.h" #include "iec61850_common.h" #ifdef __cplusplus From 401a436c95650477e98f495533a92a3a796c2352 Mon Sep 17 00:00:00 2001 From: Mikael Bourhis Date: Fri, 18 Sep 2020 15:37:58 +0200 Subject: [PATCH 10/10] Python wrapper: move the 'event handler' classes into a subdirectory --- pyiec61850/{ => eventHandlers}/eventHandler.hpp | 0 pyiec61850/{ => eventHandlers}/gooseHandler.hpp | 0 .../reportControlBlockHandler.hpp | 0 pyiec61850/iec61850.i | 12 ++++++------ 4 files changed, 6 insertions(+), 6 deletions(-) rename pyiec61850/{ => eventHandlers}/eventHandler.hpp (100%) rename pyiec61850/{ => eventHandlers}/gooseHandler.hpp (100%) rename pyiec61850/{ => eventHandlers}/reportControlBlockHandler.hpp (100%) diff --git a/pyiec61850/eventHandler.hpp b/pyiec61850/eventHandlers/eventHandler.hpp similarity index 100% rename from pyiec61850/eventHandler.hpp rename to pyiec61850/eventHandlers/eventHandler.hpp diff --git a/pyiec61850/gooseHandler.hpp b/pyiec61850/eventHandlers/gooseHandler.hpp similarity index 100% rename from pyiec61850/gooseHandler.hpp rename to pyiec61850/eventHandlers/gooseHandler.hpp diff --git a/pyiec61850/reportControlBlockHandler.hpp b/pyiec61850/eventHandlers/reportControlBlockHandler.hpp similarity index 100% rename from pyiec61850/reportControlBlockHandler.hpp rename to pyiec61850/eventHandlers/reportControlBlockHandler.hpp diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index f638aa35..a99b01cb 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -97,14 +97,14 @@ void GooseSubscriber_setDstMac(GooseSubscriber subscriber, %feature("director") RCBHandler; %feature("director") GooseHandler; %{ -#include "eventHandler.hpp" -#include "reportControlBlockHandler.hpp" -#include "gooseHandler.hpp" +#include "eventHandlers/eventHandler.hpp" +#include "eventHandlers/reportControlBlockHandler.hpp" +#include "eventHandlers/gooseHandler.hpp" EventSubscriber* EventSubscriber::m_last_created_event_subscriber = nullptr; %} -%include "eventHandler.hpp" -%include "reportControlBlockHandler.hpp" -%include "gooseHandler.hpp" +%include "eventHandlers/eventHandler.hpp" +%include "eventHandlers/reportControlBlockHandler.hpp" +%include "eventHandlers/gooseHandler.hpp" /* Goose Publisher section */ %{