From 1688fd872b6097cc957e56116351b2d41f19d61e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 18 Apr 2016 18:35:05 +0200 Subject: [PATCH] - added python bindings --- CMakeLists.txt | 8 ++-- pyiec61850/CMakeLists.txt | 23 ++++++++++ pyiec61850/iec61850.i | 41 ++++++++++++++++++ pyiec61850/test_pyiec61850.py | 82 +++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 pyiec61850/CMakeLists.txt create mode 100644 pyiec61850/iec61850.i create mode 100755 pyiec61850/test_pyiec61850.py diff --git a/CMakeLists.txt b/CMakeLists.txt index b303bdd5..f569a134 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ if(DEFINED ENV{TOOLCHAIN}) endif() project(libiec61850) +ENABLE_TESTING() set(LIB_VERSION_MAJOR "0") set(LIB_VERSION_MINOR "9") @@ -25,6 +26,7 @@ set(CONFIG_MMS_MAXIMUM_PDU_SIZE "65000" CACHE STRING "Configure the maximum size set(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 CACHE STRING "Configure the maximum number of clients allowed to connect to the server") option(BUILD_EXAMPLES "Build the examples" ON) +option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF) option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" OFF) option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF) @@ -119,6 +121,9 @@ add_subdirectory(src) INSTALL(FILES ${API_HEADERS} DESTINATION include/libiec61850) +IF(BUILD_PYTHON_BINDINGS) + add_subdirectory(pyiec61850) +ENDIF(BUILD_PYTHON_BINDINGS) IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") INCLUDE(InstallRequiredSystemLibraries) @@ -144,6 +149,3 @@ SET(CPACK_COMPONENTS_ALL Libraries ApplicationData) INCLUDE(CPack) ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") - - - diff --git a/pyiec61850/CMakeLists.txt b/pyiec61850/CMakeLists.txt new file mode 100644 index 00000000..328a9966 --- /dev/null +++ b/pyiec61850/CMakeLists.txt @@ -0,0 +1,23 @@ +FIND_PACKAGE(SWIG REQUIRED) +INCLUDE(${SWIG_USE_FILE}) +FIND_PACKAGE(PythonLibs REQUIRED) +FIND_PACKAGE ( PythonInterp REQUIRED ) +INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +SET(CMAKE_SWIG_FLAGS "") +SET_PROPERTY(SOURCE iec61850.i PROPERTY CPLUSPLUS ON) +SWIG_ADD_MODULE(iec61850 python iec61850.i) +IF(WIN32) + SWIG_LINK_LIBRARIES(iec61850 ${PYTHON_LIBRARIES} iec61850 ws2_32) +ELSE() + SWIG_LINK_LIBRARIES(iec61850 ${PYTHON_LIBRARIES} iec61850-shared) +ENDIF(WIN32) +EXECUTE_PROCESS ( #Finding python modules install path + COMMAND ${PYTHON_EXECUTABLE} -c + "import site, sys; sys.stdout.write(site.getsitepackages()[-1])" + OUTPUT_VARIABLE PYTHON_SITE_DIR + ) +INSTALL ( FILES ${CMAKE_BINARY_DIR}/iec61850.py DESTINATION ${PYTHON_SITE_DIR}) +INSTALL ( TARGETS _iec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR}) + +add_test(test_pyiec61850 ${PYTHON_EXECUTABLE} test_pyiec61850.py) diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i new file mode 100644 index 00000000..2af52e80 --- /dev/null +++ b/pyiec61850/iec61850.i @@ -0,0 +1,41 @@ +/* File : iec61850.i */ +%module iec61850 +%ignore ControlObjectClient_setTestMode(ControlObjectClient self); +%ignore CDA_OperBoolean(ModelNode* parent, bool isTImeActivated); +%ignore LogicalNode_hasBufferedReports(LogicalNode* node); +%ignore LogicalNode_hasUnbufferedReports(LogicalNode* node); +%ignore MmsConnection_setIsoConnectionParameters(MmsConnection self, IsoConnectionParameters* params); +%include "stdint.i" +%{ +#include +#include +#include +ModelNode* toModelNode(LogicalNode * ln) +{ + return (ModelNode*) ln; +} +ModelNode* toModelNode(DataObject * DO) +{ + return (ModelNode*) DO; +} +DataAttribute* toDataAttribute(DataObject * DO) +{ return (DataAttribute*)DO;} +DataAttribute* toDataAttribute(ModelNode * MN) +{ return (DataAttribute*)MN;} +%} +%apply int *OUTPUT {IedClientError* error}; + +%include "iec61850_client.h" +%include "iso_connection_parameters.h" +%include "mms_client_connection.h" +%include "iso_connection_parameters.h" +%include "iec61850_common.h" +%include "mms_value.h" +%include "iec61850_model.h" +%include "iec61850_server.h" +%include "iec61850_dynamic_model.h" +%include "iec61850_cdc.h" +ModelNode* toModelNode(LogicalNode *); +ModelNode* toModelNode(DataObject *); +DataAttribute* toDataAttribute(DataObject *); +DataAttribute* toDataAttribute(ModelNode *); diff --git a/pyiec61850/test_pyiec61850.py b/pyiec61850/test_pyiec61850.py new file mode 100755 index 00000000..7f5d3655 --- /dev/null +++ b/pyiec61850/test_pyiec61850.py @@ -0,0 +1,82 @@ +#!/usr/bin/python +import sys +import time +import iec61850 +import threading +import traceback +import signal +import sys +def signal_handler(signal, frame): + global running + running =0 + print('You pressed Ctrl+C!') + #sys.exit(0) +signal.signal(signal.SIGINT, signal_handler) +tcpPort = 8102 +running = 1 +class myIECServer(): + def __init__(self): + self.__model = iec61850.IedModel_create("testmodel") + lDevice1 = iec61850.LogicalDevice_create("SENSORS", self.__model); + lln0 = iec61850.LogicalNode_create("LLN0", lDevice1); + ttmp1 = iec61850.LogicalNode_create("TTMP1", lDevice1); + iec61850.CDC_SAV_create("TmpSv", iec61850.toModelNode(ttmp1), 0, False) + iec61850.CDC_ASG_create("TmpSp", iec61850.toModelNode(ttmp1), 0, False) + self.__iedServer = iec61850.IedServer_create(self.__model) + iec61850.IedServer_start(self.__iedServer, tcpPort); + if not(iec61850.IedServer_isRunning(self.__iedServer)) : + print("Starting server failed! Exit.\n") + iec61850.IedServer_destroy(self.__iedServer) + sys.exit(-1) + def run(self): + global running + while running: + time.sleep(0.1) + self.stop() + def stop(self): + iec61850.IedServer_stop(self.__iedServer) + iec61850.IedServer_destroy(self.__iedServer) + iec61850.IedModel_destroy(self.__model) + +def testClient(): + con = iec61850.IedConnection_create() + error = iec61850.IedConnection_connect(con, "localhost", tcpPort) + if (error == iec61850.IED_ERROR_OK): + # Accessing to SAV values + theVal = "testmodelSENSORS/TTMP1.TmpSv.instMag.f" + theValType = iec61850.IEC61850_FC_MX + temperatureValue = iec61850.IedConnection_readFloatValue(con, theVal, theValType) + assert(temperatureValue[1]==0) + newValue= temperatureValue[0]+10 + err = iec61850.IedConnection_writeFloatValue(con, theVal, theValType, newValue) + assert(err==21) + # Accessing to ASG values + theVal = "testmodelSENSORS/TTMP1.TmpSp.setMag.f" + theValType = iec61850.IEC61850_FC_SP + temperatureSetpoint = iec61850.IedConnection_readFloatValue(con, theVal, theValType) + print temperatureSetpoint + assert(temperatureValue[1]==0) + newValue= temperatureValue[0]+10 + err = iec61850.IedConnection_writeFloatValue(con, theVal, theValType, newValue) + assert(err==0) + temperatureSetpoint = iec61850.IedConnection_readFloatValue(con, theVal, theValType) + print temperatureSetpoint + assert(temperatureSetpoint[0]==newValue) + iec61850.IedConnection_close(con) + else: + print "Connection error" + sys.exit(-1) + iec61850.IedConnection_destroy(con) + print "client ok" +try: + srv=myIECServer() + srvThread = threading.Thread(target = srv.run) + srvThread.start() + testClient() + running = 0 + #signal.pause() +except: + running = 0 + print "Error :" + traceback.print_exc(file=sys.stdout) + sys.exit(-1)