- sampled values - WIP

pull/6/head
Michael Zillgith 10 years ago
parent ae3ddfd89c
commit a4730069ff

@ -0,0 +1,17 @@
set(iec61850_sv_client_example_SRCS
sv_client_example.c
)
IF(WIN32)
set_source_files_properties(${iec61850_sv_client_example_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(WIN32)
add_executable(iec61850_sv_client_example
${iec61850_sv_client_example_SRCS}
)
target_link_libraries(iec61850_sv_client_example
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = sv_client_example
PROJECT_SOURCES = sv_client_example.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,74 @@
/*
* sv_client_example.c
*
* This example is intended to show how SV control blocks are accessed
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
int main(int argc, char** argv) {
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
char* svcbRef = "simpleIOGenericIO/LLN0.Volt";
ClientSVControlBlock svcb = ClientSVControlBlock_create(con, svcbRef);
if (svcb != NULL) {
if (ClientSVControlBlock_isMulticast(svcb))
printf("SVCB is multicast\n");
else
printf("SVCB is unicast\n");
if (ClientSVControlBlock_setSvEna(svcb, true))
printf("SVCB enabled\n");
else
printf("Failed to enable SVCB\n");
printf("SvEna state: %i\n", ClientSVControlBlock_getSvEna(svcb));
char* msvID = ClientSVControlBlock_getMsvID(svcb);
if (msvID != NULL) {
printf("MsvID: %s\n", msvID);
free(msvID);
}
}
else {
printf("SVCB %s does not exist on server!\n", svcbRef);
}
IedConnection_close(con);
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
}

@ -125,6 +125,10 @@ FunctionalConstraint_toString(FunctionalConstraint fc) {
return "EX";
case IEC61850_FC_CO:
return "CO";
case IEC61850_FC_US:
return "US";
case IEC61850_FC_MS:
return "MS";
default:
return NULL;
}

@ -1,7 +1,7 @@
/*
* iec61850_client.h
*
* Copyright 2013, 2014 Michael Zillgith
* Copyright 2013, 2014, 2015 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -306,6 +306,51 @@ IedConnection_getMmsConnection(IedConnection self);
/** @} */
/**
* @defgroup IEC61850_CLIENT_SV Client side SV control block handling functions
*
* @{
*/
/** an opaque handle to the instance data of a ClientSVControlBlock object */
typedef struct sClientSVControlBlock* ClientSVControlBlock;
/**
* \brief Create a new ClientSVControlBlock instance
*
* This function simplifies client side access to server MSV/USV control blocks
* NOTE: Do not use the functions after the IedConnection object is invalidated!
*
* \param connection the IedConnection object with a valid connection to the server.
* \param reference the object reference of the control block
*
* \return the new instance
*/
ClientSVControlBlock
ClientSVControlBlock_create(IedConnection connection, const char* reference);
/**
* \brief Free all resources related to the ClientSVControlBlock instance.
*
* \param self the ClientSVControlBlock instance to operate on
*/
void
ClientSVControlBlock_destroy(ClientSVControlBlock self);
bool
ClientSVControlBlock_isMulticast(ClientSVControlBlock self);
bool
ClientSVControlBlock_setSvEna(ClientSVControlBlock self, bool svEna);
bool
ClientSVControlBlock_getSvEna(ClientSVControlBlock self);
char*
ClientSVControlBlock_getMsvID(ClientSVControlBlock self);
/** @} */
/**
* @defgroup IEC61850_CLIENT_GOOSE Client side GOOSE control block handling functions
*

@ -217,6 +217,11 @@ typedef enum eFunctionalConstraint {
IEC61850_FC_EX = 11,
/** Control */
IEC61850_FC_CO = 12,
/** Unicast SV */
IEC61850_FC_US = 13,
/** Multicast SV */
IEC61850_FC_MS = 14,
IEC61850_FC_ALL = 99,
IEC61850_FC_NONE = -1
} FunctionalConstraint;

@ -40,4 +40,8 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
MmsValue*
LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig);
MmsDataAccessError
LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection);
#endif /* LIBIEC61850_SRC_IEC61850_INC_PRIVATE_MMS_SV_H_ */

@ -1691,17 +1691,19 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
/* Goose control block - GO */
if (isGooseControlBlock(separator)) {
if (isGooseControlBlock(separator))
return writeAccessGooseControlBlock(self, domain, variableId, value);
}
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
/* Sampled Value control block - MS/US */
if (isSampledValueControlBlock(separator)) {
//TODO handle write access to SVCB
}
if (isSampledValueControlBlock(separator))
return LIBIEC61850_SV_writeAccessSVControlBlock(self, domain, variableId, value, connection);
#endif /* (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) */

@ -36,7 +36,9 @@
struct sMmsSampledValueControlBlock {
char* name;
bool svEna;
MmsServerConnection reservedByClient;
char* dstAddress;
@ -46,7 +48,8 @@ struct sMmsSampledValueControlBlock {
MmsVariableSpecification* mmsType;
MmsValue* mmsValue;
//MmsMapping* mmsMapping;
MmsValue* svEnaValue;
MmsValue* resvValue;
};
MmsSampledValueControlBlock
@ -88,6 +91,109 @@ lookupSVCB(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName)
return NULL;
}
static void
MmsSampledValueControlBlock_enable(MmsSampledValueControlBlock self)
{
//TODO call application callback handler
self->svEna = true;
MmsValue_setBoolean(self->svEnaValue, true);
}
static void
MmsSampledValueControlBlock_disable(MmsSampledValueControlBlock self)
{
//TODO call application callback handler
self->svEna = false;
MmsValue_setBoolean(self->svEnaValue, false);
}
static bool
MmsSampledValueControlBlock_isEnabled(MmsSampledValueControlBlock self)
{
return self->svEna;
}
MmsDataAccessError
LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
char variableId[130];
strncpy(variableId, variableIdOrig, 129);
char* separator = strchr(variableId, '$');
*separator = 0;
char* lnName = variableId;
if (lnName == NULL)
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
char* objectName = MmsMapping_getNextNameElement(separator + 1);
if (objectName == NULL)
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
char* varName = MmsMapping_getNextNameElement(objectName);
if (varName != NULL)
*(varName - 1) = 0;
else
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
MmsSampledValueControlBlock mmsSVCB = lookupSVCB(self, domain, lnName, objectName);
if (mmsSVCB == NULL)
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
if (mmsSVCB->reservedByClient != NULL) {
if (mmsSVCB->reservedByClient != connection)
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
if (strcmp(varName, "Resv") == 0) {
if (MmsValue_getType(value) != MMS_BOOLEAN)
return DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
if (MmsValue_getBoolean(value)) {
mmsSVCB->reservedByClient = connection;
MmsValue_setBoolean(mmsSVCB->resvValue, true);
}
else {
mmsSVCB->reservedByClient = NULL;
MmsValue_setBoolean(mmsSVCB->resvValue, false);
}
return DATA_ACCESS_ERROR_SUCCESS;
}
else if (strcmp(varName, "SvEna") == 0) {
if (MmsValue_getType(value) != MMS_BOOLEAN)
return DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
if (MmsValue_getBoolean(value))
MmsSampledValueControlBlock_enable(mmsSVCB);
else
MmsSampledValueControlBlock_disable(mmsSVCB);
return DATA_ACCESS_ERROR_SUCCESS;
}
else {
if (MmsSampledValueControlBlock_isEnabled(mmsSVCB))
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
else {
bool allowAccess = false;
// In 61850-9-2 mapping only Resv and SvEna are writable!
if (allowAccess)
return DATA_ACCESS_ERROR_SUCCESS;
else
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
}
}
MmsValue*
LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig)
@ -284,12 +390,18 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
namedVariable->typeSpec.structure.elements[currentSVCB] = svTypeSpec;
int currentIndex;
int currentIndex = 0;
/* SvEna */
MmsValue* svEna = MmsValue_getElement(svValues, currentIndex++);
MmsValue* resv = NULL;
if (unicast) {
/* Resv */
resv = MmsValue_getElement(svValues, currentIndex++);
}
if (unicast)
currentIndex = 2;
else
currentIndex = 1;
/* SvID */
MmsValue* svID = MmsValue_getElement(svValues, currentIndex++);
@ -353,6 +465,8 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
MmsSampledValueControlBlock mmsSvCb = MmsSampledValueControlBlock_create();
mmsSvCb->mmsValue = svValues;
mmsSvCb->svEnaValue = svEna;
mmsSvCb->resvValue = resv;
mmsSvCb->mmsType = svTypeSpec;
mmsSvCb->domain = domain;
mmsSvCb->logicalNode = logicalNode;

Loading…
Cancel
Save