Compare commits

...

4 Commits
v1.5 ... v1.1.1

@ -1,3 +1,25 @@
Changes to version 1.1.1
------------------------
- IEC 61850 client: fixed bug in APC control handling
- IEC 61850 client: ClientReportControlBlock now accepts "$" and "." as seperator for RCB object reference
- MMS client: fixed bug in MmsConnection_connect (COTP payload buffer was not reset in case of an error during connect -> connection failed in case of reuse of MmsConnection object
- MMS client: delete named variable list service supports VMD specific lists
- SV subscriber/publisher: additional features and bug fixes
- SV: fixed data type for smpRate
- SV: fixed encoding of optional smpMod attribute
- SV receiver: Added semaphore to make subscriber list thread-safe
- .NET API: ControlObject implements IDisposable interface
- IED server: added new function IedServer_udpateDbposValue
- fixed problem with cmake include folders
- MMS client: file services -fixed encoding problem with long file names
- MMS server: ACSE authenticator passes application reference (ap-title and ae-qualifier)
- example directory cleanup
- MMS: fixed potential memory leak in asn1 code that can be caused by malformed MMS messages
- MMS client: MmsConnection_getVariableAccessAttributes support for VMD specific variables
- Java SCL parser: added support for "Val" elements for Octet64 types
Changes to version 1.1.0
------------------------

@ -12,7 +12,7 @@ ENABLE_TESTING()
set(LIB_VERSION_MAJOR "1")
set(LIB_VERSION_MINOR "1")
set(LIB_VERSION_PATCH "0")
set(LIB_VERSION_PATCH "1")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/")

@ -44,7 +44,7 @@
*
* WARNING: If set to 1 normal single- and multi-threaded server are no longer working!
*/
#define CONFIG_MMS_THREADLESS_STACK 0
#define CONFIG_MMS_THREADLESS_STACK 1
/* number of concurrent MMS client connections the server accepts, -1 for no limit */
#define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5

@ -15,7 +15,7 @@
#include "platform_endian.h"
#define LIBIEC61850_VERSION "1.1.0"
#define LIBIEC61850_VERSION "1.1.1"
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"

@ -18,7 +18,7 @@ DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libIEC61850"
PROJECT_NUMBER = 1.1
PROJECT_NUMBER = 1.1.1
PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE/SV server and client library"

@ -149,6 +149,7 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
bool hasOper = false;
bool hasTimeActivatedControl = false;
bool hasCtlNum = false;
bool isAPC = false;
MmsVariableSpecification* ctlVal = NULL;
MmsVariableSpecification* t = NULL;
@ -159,6 +160,11 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
{
hasOper = true;
ctlVal = MmsVariableSpecification_getNamedVariableRecursive(oper, "ctlVal");
if (MmsVariableSpecification_getType(ctlVal) == MMS_STRUCTURE)
isAPC = true;
MmsVariableSpecification* operTm = MmsVariableSpecification_getNamedVariableRecursive(oper, "operTm");
if (operTm)
@ -169,7 +175,6 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
if (ctlNum)
hasCtlNum = true;
ctlVal = MmsVariableSpecification_getNamedVariableRecursive(oper, "ctlVal");
t = MmsVariableSpecification_getNamedVariableRecursive(oper, "T");
}
}
@ -200,163 +205,13 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
self->hasCtlNum = hasCtlNum;
self->ctlVal = MmsValue_newDefaultValue(ctlVal);
/* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */
if (MmsVariableSpecification_getType(t) == MMS_BINARY_TIME)
self->edition = 1;
else
self->edition = 2;
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: Detected edition %i control\n", self->edition);
private_IedConnection_addControlClient(connection, self);
free_varspec:
MmsVariableSpecification_destroy(ctlVarSpec);
exit_function:
return self;
}
#if 0
ControlObjectClient
ControlObjectClient_create(const char* objectReference, IedConnection connection)
{
ControlObjectClient self = NULL;
/* request control model from server */
char domainId[65];
char itemId[129];
char* domainName = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainId);
if (domainName == NULL)
goto exit_function;
convertToMmsAndInsertFC(itemId, objectReference + strlen(domainId) + 1, "CF");
int controlObjectItemIdLen = strlen(itemId);
strncat(itemId, "$ctlModel", 64 - controlObjectItemIdLen);
MmsError mmsError;
MmsValue* ctlModel = MmsConnection_readVariable(IedConnection_getMmsConnection(connection),
&mmsError, domainId, itemId);
if (ctlModel == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ControlObjectClient_create: failed to get ctlModel from server\n");
goto exit_function;
}
int ctlModelVal = MmsValue_toUint32(ctlModel);
MmsValue_delete(ctlModel);
IedClientError error;
LinkedList dataDirectory =
IedConnection_getDataDirectory(connection, &error, objectReference);
if (dataDirectory == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ControlObjectClient_create: failed to get data directory of control object\n");
goto exit_function;
}
/* check what control elements are available */
bool hasOper = false;
LinkedList element = LinkedList_getNext(dataDirectory);
while (element != NULL) {
char* objectName = (char*) element->data;
if (strcmp(objectName, "Oper") == 0)
hasOper = true;
element = LinkedList_getNext(element);
}
LinkedList_destroy(dataDirectory);
if (hasOper == false) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: control is missing required element \"Oper\"\n");
goto exit_function;
}
/* check for time activated control and ctlNum */
bool hasTimeActivatedControl = false;
bool hasCtlNum = false;
strcpy(itemId, objectReference);
strcat(itemId, ".Oper");
dataDirectory = IedConnection_getDataDirectory(connection, &error, itemId);
if (dataDirectory == NULL)
goto exit_function;
element = LinkedList_getNext(dataDirectory);
while (element != NULL) {
char* objectName = (char*) element->data;
if (strcmp(objectName, "operTm") == 0) {
hasTimeActivatedControl = true;
}
else if (strcmp(objectName, "ctlNum") == 0) {
hasCtlNum = true;
}
element = LinkedList_getNext(element);
}
LinkedList_destroy(dataDirectory);
/* get default parameters for Oper control variable */
MmsValue* oper = IedConnection_readObject(connection, &error, itemId, IEC61850_FC_CO);
if (oper == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: reading \"Oper\" failed!\n");
goto exit_function;
}
self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient));
if (self == NULL)
goto exit_function;
self->objectReference = StringUtils_copyString(objectReference);
self->connection = connection;
self->ctlModel = (ControlModel) ctlModelVal;
self->hasTimeActivatedMode = hasTimeActivatedControl;
self->hasCtlNum = hasCtlNum;
self->ctlVal = MmsValue_getElement(oper, 0);
if (MmsValue_getType(self->ctlVal) == MMS_STRUCTURE)
if (isAPC)
self->analogValue = MmsValue_createEmptyStructure(1);
else
self->analogValue = NULL;
/* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */
MmsValue* t;
if (hasTimeActivatedControl)
t = MmsValue_getElement(oper, 4);
else
t = MmsValue_getElement(oper, 3);
if (MmsValue_getType(t) == MMS_BINARY_TIME)
if (MmsVariableSpecification_getType(t) == MMS_BINARY_TIME)
self->edition = 1;
else
self->edition = 2;
@ -364,15 +219,14 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: Detected edition %i control\n", self->edition);
MmsValue_setElement(oper, 0, NULL);
MmsValue_delete(oper);
private_IedConnection_addControlClient(connection, self);
free_varspec:
MmsVariableSpecification_destroy(ctlVarSpec);
exit_function:
return self;
}
#endif
void
ControlObjectClient_destroy(ControlObjectClient self)

@ -32,12 +32,19 @@
#include "libiec61850_platform_includes.h"
static bool
isBufferedRcb(const char* objectReference)
isBufferedRcb(const char* objectReference, bool* isValid)
{
const char* separator = strchr(objectReference, '.');
if (separator == NULL)
separator = strchr(objectReference, '$');
if (separator == NULL) {
*isValid = false;
return false;
}
*isValid = true;
if (*(separator + 1) == 'B')
return true;
@ -48,12 +55,24 @@ isBufferedRcb(const char* objectReference)
ClientReportControlBlock
ClientReportControlBlock_create(const char* objectReference)
{
ClientReportControlBlock self = (ClientReportControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock));
bool isReferenceValid;
bool isBuffered;
isBuffered = isBufferedRcb(objectReference, &isReferenceValid);
if (isReferenceValid == false) {
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: RCB reference invalid\n");
return NULL;
}
//TODO check validity of object reference?!
ClientReportControlBlock self = (ClientReportControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock));
if (self) {
self->objectReference = StringUtils_copyString(objectReference);
self->isBuffered = isBufferedRcb(objectReference);
self->isBuffered = isBuffered;
}
return self;
}

@ -1015,9 +1015,7 @@ MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress)
int i;
for (i = 0; i < self->value.structure.size; i++) {
newValue->value.structure.components[i] = (MmsValue*) destinationAddress;
//memcpy(&(newValue->value.structure.components[i]), &(destinationAddress), sizeof (MmsValue*));
memcpy(&(newValue->value.structure.components[i]), &(destinationAddress), sizeof (MmsValue*));
destinationAddress = MmsValue_cloneToBuffer(self->value.structure.components[i], destinationAddress);
}
}

Loading…
Cancel
Save