- added access function to data set references for reports to client API C/C#

- renamed function MmsValue_createEmptyArray (fixed typo "Emtpy")
- added some missing API functions to windows DLL def files
This commit is contained in:
Michael Zillgith 2014-12-11 17:24:26 +01:00
parent 78a694c5d3
commit 375b1a9c12
19 changed files with 823 additions and 372 deletions

View file

@ -36,14 +36,20 @@ namespace IEC61850
/// <summary>
/// Control model
/// </summary>
public enum ControlModel {
CONTROL_MODEL_STATUS_ONLY = 0,
CONTROL_MODEL_DIRECT_NORMAL = 1,
CONTROL_MODEL_SBO_NORMAL = 2,
CONTROL_MODEL_DIRECT_ENHANCED = 3,
CONTROL_MODEL_SBO_ENHANCED = 4
}
/// </summary>
public enum ControlModel
{
/** status only */
STATUS_ONLY = 0,
/** direct with normal security */
DIRECT_NORMAL= 1,
/** select before operate (SBO) with normal security */
SBO_NORMAL = 2,
/** direct with enhanced security */
DIRECT_ENHANCED = 3,
/** select before operate (SBO) with enhanced security */
SBO_ENHANCED = 4
}
/// <summary>
/// Originator category
@ -144,8 +150,9 @@ namespace IEC61850
private static extern void ControlObjectClient_setCommandTerminationHandler(IntPtr self,
InternalCommandTerminationHandler handler, IntPtr handlerParameter);
public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject);
public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject);
private IedConnection iedConnection;
private IntPtr controlObject;
private CommandTerminationHandler commandTerminationHandler = null;
@ -158,8 +165,10 @@ namespace IEC61850
}
internal ControlObject (string objectReference, IntPtr connection)
{
internal ControlObject (string objectReference, IntPtr connection, IedConnection iedConnection)
{
this.iedConnection = iedConnection;
this.controlObject = ControlObjectClient_create(objectReference, connection);
if (this.controlObject == System.IntPtr.Zero)

View file

@ -250,7 +250,7 @@ namespace IEC61850
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public ControlObject CreateControlObject (string objectReference)
{
ControlObject controlObject = new ControlObject (objectReference, connection);
ControlObject controlObject = new ControlObject (objectReference, connection, this);
return controlObject;
}

View file

@ -473,6 +473,26 @@ namespace IEC61850
flagRptEna = true;
}
/// <summary>
/// Get the purgeBuf flag of the report control block
/// </summary>
/// <returns>the prugeBuf value</returns>
public bool GetPurgeBuf ()
{
return ClientReportControlBlock_getPurgeBuf(self);
}
/// <summary>
/// Set the purgeBuf flag of the report control block
/// </summary>
/// <description>This is only for buffered RCBs. If set to true the report buffer of a buffered RCB will be cleaned.</description>
/// <param name="purgeBuf">set to true to flush report buffer</param>
public void SetPurgeBuf (bool purgeBuf)
{
ClientReportControlBlock_setPurgeBuf(self, purgeBuf);
flagPurgeBuf = true;
}
/// <summary>
/// Gets the buffer time.
/// </summary>

View file

@ -116,6 +116,8 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReport_getRptId(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReport_getDataReference(IntPtr self, int elementIndex);
private IntPtr self;
@ -246,6 +248,25 @@ namespace IEC61850
return Marshal.PtrToStringAnsi (rcbRef);
}
/// <summary>
/// Gets the data reference for the specified data set element
/// </summary>
/// <returns>
/// The data reference or null if the data reference is not available
/// </returns>
/// <param name='index'>
/// index of the data set element starting with 0
/// </param>
public string GetDataReference (int index)
{
IntPtr dataRef = ClientReport_getDataReference(self, index);
if (dataRef != IntPtr.Zero)
return Marshal.PtrToStringAnsi(dataRef);
else
return null;
}
public string GetRptId ()
{
IntPtr rptId = ClientReport_getRptId(self);

View file

@ -42,7 +42,7 @@ gooseListener(GooseSubscriber subscriber, void* parameter)
int
main(int argc, char** argv)
{
MmsValue* dataSetValues = MmsValue_createEmtpyArray(4);
MmsValue* dataSetValues = MmsValue_createEmptyArray(4);
int i;
for (i = 0; i < 4; i++) {

View file

@ -321,7 +321,7 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt
if (isStructure)
dataSetValues = MmsValue_createEmptyStructure(elementIndex);
else
dataSetValues = MmsValue_createEmtpyArray(elementIndex);
dataSetValues = MmsValue_createEmptyArray(elementIndex);
elementIndex = 0;
bufPos = 0;

View file

@ -28,6 +28,7 @@
#include "iec61850_client.h"
#include "mms_client_connection.h"
#include "ied_connection_private.h"
#include "mms_mapping.h"
#include <stdio.h>
@ -39,9 +40,6 @@
#define DEBUG_IED_CLIENT 0
#endif
char*
MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer);
struct sControlObjectClient
{
ControlModel ctlModel;
@ -110,11 +108,16 @@ resetLastApplError(ControlObjectClient self)
ControlObjectClient
ControlObjectClient_create(char* objectReference, IedConnection connection)
{
ControlObjectClient self = NULL;
/* request control model from server */
char domainId[65];
char itemId[129];
char itemId[65];
MmsMapping_getMmsDomainFromObjectReference(objectReference, domainId);
char* domainName = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainId);
if (domainName == NULL)
goto exit_function;
convertToMmsAndInsertFC(itemId, objectReference + strlen(domainId) + 1, "CF");
@ -128,7 +131,8 @@ ControlObjectClient_create(char* objectReference, IedConnection connection)
if (ctlModel == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ControlObjectClient_create: failed to get ctlModel from server\n");
return NULL;
goto exit_function;
}
int ctlModelVal = MmsValue_toUint32(ctlModel);
@ -143,7 +147,8 @@ ControlObjectClient_create(char* objectReference, IedConnection connection)
if (dataDirectory == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ControlObjectClient_create: failed to get data directory of control object\n");
return NULL;
goto exit_function;
}
/* check what control elements are available */
@ -165,7 +170,8 @@ ControlObjectClient_create(char* objectReference, IedConnection connection)
if (hasOper == false) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: control is missing required element \"Oper\"\n");
return NULL;
goto exit_function;
}
/* check for time activated control */
@ -175,6 +181,9 @@ ControlObjectClient_create(char* objectReference, IedConnection connection)
strcat(itemId, ".Oper");
dataDirectory = IedConnection_getDataDirectory(connection, &error, itemId);
if (dataDirectory == NULL)
goto exit_function;
element = LinkedList_getNext(dataDirectory);
while (element != NULL) {
@ -196,11 +205,15 @@ ControlObjectClient_create(char* objectReference, IedConnection connection)
if (oper == NULL) {
if (DEBUG_IED_CLIENT)
printf("reading Oper failed!\n");
return NULL;
printf("IED_CLIENT: reading \"Oper\" failed!\n");
goto exit_function;
}
ControlObjectClient self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient));
self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient));
if (self == NULL)
goto exit_function;
self->objectReference = copyString(objectReference);
self->connection = connection;
@ -229,23 +242,27 @@ ControlObjectClient_create(char* objectReference, IedConnection connection)
private_IedConnection_addControlClient(connection, self);
exit_function:
return self;
}
void
ControlObjectClient_destroy(ControlObjectClient self)
{
GLOBAL_FREEMEM(self->objectReference);
if (self != NULL)
{
GLOBAL_FREEMEM(self->objectReference);
private_IedConnection_removeControlClient(self->connection, self);
private_IedConnection_removeControlClient(self->connection, self);
if (self->ctlVal != NULL)
MmsValue_delete(self->ctlVal);
if (self->ctlVal != NULL)
MmsValue_delete(self->ctlVal);
if (self->orIdent != NULL)
GLOBAL_FREEMEM(self->orIdent);
if (self->orIdent != NULL)
GLOBAL_FREEMEM(self->orIdent);
GLOBAL_FREEMEM(self);
GLOBAL_FREEMEM(self);
}
}
void
@ -282,7 +299,15 @@ static MmsValue*
createOriginValue(ControlObjectClient self)
{
MmsValue* origin = MmsValue_createEmptyStructure(2);
if (origin == NULL)
goto exit_function;
MmsValue* orCat = MmsValue_newIntegerFromInt16(self->orCat);
if (orCat == NULL)
goto cleanup_on_error;
MmsValue_setElement(origin, 0, orCat);
MmsValue* orIdent;
@ -290,19 +315,42 @@ createOriginValue(ControlObjectClient self)
if (self->orIdent != NULL) {
int octetStringLen = strlen(self->orIdent);
orIdent = MmsValue_newOctetString(0, octetStringLen);
if (orIdent == NULL)
goto cleanup_on_error;
MmsValue_setOctetString(orIdent, (uint8_t*) self->orIdent, octetStringLen);
}
else
orIdent = MmsValue_newOctetString(0, 0);
if (orIdent == NULL)
goto cleanup_on_error;
MmsValue_setElement(origin, 1, orIdent);
goto exit_function;
cleanup_on_error:
MmsValue_delete(origin);
origin = NULL;
exit_function:
return origin;
}
bool
ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t operTime)
{
bool success = false;
if (ctlVal == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: operate - (ctlVal == NULL)!\n");
goto exit_function;
}
resetLastApplError(self);
MmsValue* operParameters;
@ -337,6 +385,7 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
ctlTime = MmsValue_newBinaryTime(false);
MmsValue_setBinaryTime(ctlTime, timestamp);
}
MmsValue_setElement(operParameters, index++, ctlTime);
MmsValue* ctlTest = MmsValue_newBoolean(self->test);
@ -348,7 +397,7 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
MmsValue_setElement(operParameters, index++, check);
char domainId[65];
char itemId[130];
char itemId[65];
MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId);
@ -370,10 +419,14 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
if (mmsError != MMS_ERROR_NONE) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: operate failed!\n");
return false;
goto exit_function;
}
return true;
success = true;
exit_function:
return success;
}
bool
@ -382,13 +435,13 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
resetLastApplError(self);
char domainId[65];
char itemId[130];
char itemId[65];
MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId);
convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO");
strncat(itemId, "$SBOw", 129);
strncat(itemId, "$SBOw", 64);
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId);
@ -459,13 +512,13 @@ ControlObjectClient_select(ControlObjectClient self)
resetLastApplError(self);
char domainId[65];
char itemId[130];
char itemId[65];
MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId);
convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO");
strncat(itemId, "$SBO", 129);
strncat(itemId, "$SBO", 64);
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select: %s/%s\n", domainId, itemId);
@ -480,7 +533,7 @@ ControlObjectClient_select(ControlObjectClient self)
if (value == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select: read SBO failed!\n");
return false;
goto exit_function;
}
char sboReference[130];
@ -509,6 +562,7 @@ ControlObjectClient_select(ControlObjectClient self)
MmsValue_delete(value);
exit_function:
return selected;
}
@ -555,13 +609,13 @@ ControlObjectClient_cancel(ControlObjectClient self)
MmsValue_setElement(cancelParameters, index++, ctlTest);
char domainId[65];
char itemId[130];
char itemId[65];
MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId);
convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO");
strncat(itemId, "$Cancel", 129);
strncat(itemId, "$Cancel", 64);
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: cancel: %s/%s\n", domainId, itemId);
@ -611,5 +665,5 @@ void
private_ControlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self)
{
if (self->commandTerminationHandler != NULL)
self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self);
self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self);
}

View file

@ -197,7 +197,23 @@ ClientReport_hasDataReference(ClientReport self)
return self->hasDataReference;
}
const char*
ClientReport_getDataReference(ClientReport self, int elementIndex)
{
char* dataReference = NULL;
if (self->dataReferences != NULL) {
MmsValue* dataRefValue = MmsValue_getElement(self->dataReferences, elementIndex);
if (dataRefValue != NULL) {
if (MmsValue_getType(dataRefValue) == MMS_VISIBLE_STRING) {
return MmsValue_toString(dataRefValue);
}
}
}
return dataReference;
}
MmsValue*
ClientReport_getDataSetValues(ClientReport self)
@ -324,7 +340,7 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value)
}
if (matchingReport == NULL)
return;
goto exit_function;
matchingReport->hasSequenceNumber = false;
matchingReport->hasTimestamp = false;
@ -427,19 +443,38 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value)
dataSetSize);
int valueIndex = inclusionIndex + 1;
/* skip data-reference fields */
/* parse data-references if required */
if (MmsValue_getBitStringBit(optFlds, 5) == true) {
// if (matchingReport->dataReferences == NULL)
// matchingReport->dataReferences = MmsValue_createEmptyArray(dataSetSize);
if (matchingReport->dataReferences == NULL)
matchingReport->dataReferences = MmsValue_createEmptyArray(dataSetSize);
matchingReport->hasDataReference = true;
valueIndex += includedElements;
int elementIndex;
for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++) {
if (MmsValue_getBitStringBit(inclusion, elementIndex) == true) {
MmsValue* dataSetElement = MmsValue_getElement(matchingReport->dataReferences, elementIndex);
if (dataSetElement == NULL) {
dataSetElement = MmsValue_clone(MmsValue_getElement(value, valueIndex));
MmsValue_setElement(matchingReport->dataReferences, elementIndex, dataSetElement);
}
valueIndex += 1;
}
}
// valueIndex += includedElements;
}
int i;
if (matchingReport->dataSetValues == NULL) {
matchingReport->dataSetValues = MmsValue_createEmtpyArray(dataSetSize);
matchingReport->dataSetValues = MmsValue_createEmptyArray(dataSetSize);
matchingReport->reasonForInclusion = (ReasonForInclusion*)
GLOBAL_MALLOC(sizeof(ReasonForInclusion) * dataSetSize);
@ -498,8 +533,11 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value)
matchingReport->reasonForInclusion[i] = REASON_NOT_INCLUDED;
}
}
if (matchingReport->callback != NULL) {
if (matchingReport->callback != NULL)
matchingReport->callback(matchingReport->callbackParameter, matchingReport);
}
exit_function:
return;
}

View file

@ -431,9 +431,12 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, char* rcbR
ClientReportControlBlock returnRcb = updateRcb;
char domainId[65];
char itemId[129];
char itemId[65];
MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId);
char* domainName = MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId);
if (domainName == NULL)
return NULL;
strcpy(itemId, rcbReference + strlen(domainId) + 1);

View file

@ -727,9 +727,32 @@ ClientReport_getConfRev(ClientReport self);
bool
ClientReport_hasBufOvfl(ClientReport self);
/**
* \brief Indicates if the report contains data references for the reported data set members
*
* \param self the ClientReport instance
*
* \returns true if the report contains data-references, false otherwise
*/
bool
ClientReport_hasDataReference(ClientReport self);
/**
* \brief get the data-reference of the element of the report data set
*
* This function will only return a non-NULL value if the received report contains data-references.
* This can be determined by the ClientReport_hasDataReference function.
* NOTE: The returned string is allocated and hold by the ClientReport instance and is only valid until
* the ClientReport instance exists!
*
* \param self the ClientReport instance
* \param elementIndex index of the data set element (starting with 0)
*
* \param the data reference as string as provided by the report or NULL if the data reference is not available
*/
const char*
ClientReport_getDataReference(ClientReport self, int elementIndex);
/**
* \brief get the timestamp of the report
@ -1215,9 +1238,19 @@ typedef enum {
} ControlModel;
/**
* \brief Create a new client control object
*
* A client control object is used to handle all client side aspects of a controllable
* data object.
*
* \param objectReference the reference of the controllable data object
* \param connection the connection instance where the control object has to be reached
*
* \return the newly created instance or NULL if the creation failed
*/
ControlObjectClient
ControlObjectClient_create(char* dataAttributeReference, IedConnection connection);
ControlObjectClient_create(char* objectReference, IedConnection connection);
void
ControlObjectClient_destroy(ControlObjectClient self);

View file

@ -35,11 +35,13 @@
#endif
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
static void
static bool
createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariableSpecification* typeSpec, char* namePrefix)
{
MmsMapping* mapping = self->mmsMapping;
bool success = false;
if (typeSpec->type == MMS_STRUCTURE) {
int coCount = typeSpec->typeSpec.structure.elementCount;
int i;
@ -98,10 +100,19 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl
if (DEBUG_IED_SERVER)
printf("IED_SERVER: create control object LN:%s DO:%s\n", lnName, objectName);
ControlObject* controlObject = ControlObject_create(self, domain, lnName, objectName);
if (controlObject == NULL)
goto exit_function;
MmsValue* structure = MmsValue_newDefaultValue(coSpec);
if (structure == NULL) {
ControlObject_destroy(controlObject);
goto exit_function;
}
ControlObject_setMmsValue(controlObject, structure);
ControlObject_setTypeSpec(controlObject, coSpec);
@ -123,19 +134,28 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl
}
else {
strcat(objectName, coSpec->name);
createControlObjects(self, domain, lnName, coSpec, objectName);
if (createControlObjects(self, domain, lnName, coSpec, objectName) == false)
goto exit_function;
}
}
}
}
success = true;
exit_function:
return success;
}
#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */
static void
static bool
createMmsServerCache(IedServer self)
{
assert(self != NULL);
bool success = false;
int domain = 0;
for (domain = 0; domain < self->mmsDevice->domainCount; domain++) {
@ -149,7 +169,7 @@ createMmsServerCache(IedServer self)
char* lnName = logicalDevice->namedVariables[i]->name;
if (DEBUG_IED_SERVER)
printf("ied_server.c: Insert into cache %s - %s\n", logicalDevice->domainName, lnName);
printf("IED_SERVER: Insert into cache %s - %s\n", logicalDevice->domainName, lnName);
int fcCount = logicalDevice->namedVariables[i]->typeSpec.structure.elementCount;
int j;
@ -168,12 +188,18 @@ createMmsServerCache(IedServer self)
if ((strcmp(fcName, "BR") != 0) && (strcmp(fcName, "RP") != 0)
&& (strcmp(fcName, "GO") != 0))
{
{
char* variableName = createString(3, lnName, "$", fcName);
if (variableName == NULL) goto exit_function;
MmsValue* defaultValue = MmsValue_newDefaultValue(fcSpec);
if (defaultValue == NULL) {
GLOBAL_FREEMEM(variableName);
goto exit_function;
}
if (DEBUG_IED_SERVER)
printf("ied_server.c: Insert into cache %s - %s\n", logicalDevice->domainName, variableName);
@ -184,6 +210,11 @@ createMmsServerCache(IedServer self)
}
}
}
success = true;
exit_function:
return success;
}
static void

View file

@ -430,18 +430,35 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char*
{
ControlObject* self = (ControlObject*) GLOBAL_CALLOC(1, sizeof(ControlObject));
if (self == NULL)
goto exit_function;
if (DEBUG_IED_SERVER)
printf("create control object for LD: %s, LN: %s, name: %s\n", domain->domainName, lnName, name);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->stateLock = Semaphore_create(1);
if (self->stateLock == NULL) {
ControlObject_destroy(self);
self = NULL;
goto exit_function;
}
#endif
self->name = copyString(name);
if (self->name == NULL) {
ControlObject_destroy(self);
self = NULL;
goto exit_function;
}
self->lnName = lnName;
self->mmsDomain = domain;
self->iedServer = iedServer;
exit_function:
return self;
}
@ -475,10 +492,12 @@ ControlObject_destroy(ControlObject* self)
if (self->origin != NULL)
MmsValue_delete(self->origin);
free(self->name);
if (self->name != NULL)
free(self->name);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->stateLock);
if (self->stateLock != NULL)
Semaphore_destroy(self->stateLock);
#endif
free(self);
@ -762,7 +781,8 @@ getCancelParameterOrigin(MmsValue* operParameters)
static MmsValue*
getOperParameterTest(MmsValue* operParameters)
{
if (MmsValue_getType(operParameters) == MMS_STRUCTURE) {
if (MmsValue_getType(operParameters) == MMS_STRUCTURE)
{
if (MmsValue_getArraySize(operParameters) == 7)
return MmsValue_getElement(operParameters, 5);
else if (MmsValue_getArraySize(operParameters) == 6)
@ -775,7 +795,8 @@ getOperParameterTest(MmsValue* operParameters)
static MmsValue*
getOperParameterCheck(MmsValue* operParameters)
{
if (MmsValue_getType(operParameters) == MMS_STRUCTURE) {
if (MmsValue_getType(operParameters) == MMS_STRUCTURE)
{
if (MmsValue_getArraySize(operParameters) == 7)
return MmsValue_getElement(operParameters, 6);
else if (MmsValue_getArraySize(operParameters) == 6)
@ -788,7 +809,8 @@ getOperParameterCheck(MmsValue* operParameters)
static MmsValue*
getOperParameterOrigin(MmsValue* operParameters)
{
if (MmsValue_getType(operParameters) == MMS_STRUCTURE) {
if (MmsValue_getType(operParameters) == MMS_STRUCTURE)
{
if (MmsValue_getArraySize(operParameters) == 7)
return MmsValue_getElement(operParameters, 2);
else if (MmsValue_getArraySize(operParameters) == 6)
@ -803,7 +825,8 @@ getOperParameterTime(MmsValue* operParameters)
{
MmsValue* timeParameter = NULL;
if (MmsValue_getType(operParameters) == MMS_STRUCTURE) {
if (MmsValue_getType(operParameters) == MMS_STRUCTURE)
{
if (MmsValue_getArraySize(operParameters) == 7)
timeParameter = MmsValue_getElement(operParameters, 4);
else if (MmsValue_getArraySize(operParameters) == 6)
@ -820,7 +843,7 @@ getOperParameterTime(MmsValue* operParameters)
void
ControlObject_sendCommandTerminationPositive(ControlObject* self)
{
char itemId[130];
char itemId[68]; /* 64 characters + space for FC + separator + string terminator */
createStringInBuffer(itemId, 4, self->lnName, "$CO$", self->name, "$Oper");
@ -837,13 +860,16 @@ ControlObject_sendCommandTerminationPositive(ControlObject* self)
LinkedList varSpecList = LinkedList_create();
LinkedList values = LinkedList_create();
LinkedList_add(varSpecList, &varSpec);
LinkedList_add(values, self->oper);
if ((varSpecList != NULL) && (values != NULL))
{
LinkedList_add(varSpecList, &varSpec);
LinkedList_add(values, self->oper);
MmsServerConnection_sendInformationReportListOfVariables(self->mmsConnection, varSpecList, values, false);
MmsServerConnection_sendInformationReportListOfVariables(self->mmsConnection, varSpecList, values, false);
LinkedList_destroyStatic(varSpecList);
LinkedList_destroyStatic(values);
LinkedList_destroyStatic(varSpecList);
LinkedList_destroyStatic(values);
}
}
void

View file

@ -2236,10 +2236,11 @@ char*
MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer)
{
int objRefLength = strlen(objectReference);
char* domainName = NULL;
/* check for object reference size limit VISIBLESTRING129 */
if (objRefLength > 129)
return NULL;
goto exit_function;
/* check if LD name is present */
int i;
@ -2251,12 +2252,10 @@ MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* bu
/* check for LD name limit (=64 characters) */
if (i > 64)
return NULL;
goto exit_function;
if (i == objRefLength)
return NULL;
char* domainName;
goto exit_function;
if (buffer == NULL)
domainName = (char*) GLOBAL_MALLOC(i + 1);
@ -2270,6 +2269,7 @@ MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* bu
domainName[j] = 0;
exit_function:
return domainName;
}
@ -2549,6 +2549,9 @@ MmsMapping_ObjectReferenceToVariableAccessSpec(char* objectReference)
int domainIdLen = domainIdEnd - objectReference;
if (domainIdLen > 64)
return NULL;
char* fcStart = strchr(objectReference, '[');
if (fcStart == NULL) /* no FC present */

View file

@ -111,8 +111,18 @@ MmsValue_getElement(MmsValue* array, int index);
* \return a newly created empty array instance
*/
MmsValue*
MmsValue_createEmtpyArray(int size);
MmsValue_createEmptyArray(int size);
/**
* \brief Set an element of a complex type
*
* NOTE: If the element already exists it will simply be replaced by the provided new value.
* The caller is responsible to free the replaced value.
*
* \param complexValue MmsValue instance to operate on. Has to be of a type MMS_STRUCTURE or MMS_ARRAY
* \param the index of the element to set/replace
* \param elementValue the (new) value of the element
*/
void
MmsValue_setElement(MmsValue* complexValue, int index, MmsValue* elementValue);

View file

@ -43,7 +43,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
int elementCount = listSize;
if ((elementCount > 1) || createArray)
valueList = MmsValue_createEmtpyArray(elementCount);
valueList = MmsValue_createEmptyArray(elementCount);
int i = 0;

File diff suppressed because it is too large Load diff

View file

@ -215,7 +215,7 @@ alternateArrayAccess(MmsServerConnection* connection,
else
value = MmsValue_getElement(arrayValue, index);
else {
value = MmsValue_createEmtpyArray(numberOfElements);
value = MmsValue_createEmptyArray(numberOfElements);
MmsValue_setDeletable(value);

View file

@ -303,7 +303,7 @@ EXPORTS
MmsValue_cloneToBuffer @697
MmsValue_createArray @698
MmsValue_createEmptyStructure @699
MmsValue_createEmtpyArray @700
MmsValue_createEmptyArray @700
MmsValue_delete @701
MmsValue_deleteAllBitStringBits @702
MmsValue_deleteConditional @703
@ -472,3 +472,13 @@ EXPORTS
ClientReport_hasBufOvfl
ClientReport_hasDataReference
LibIEC61850_getVersionString
ClientReport_getDataReference
IedServer_getBooleanAttributeValue
IedServer_getInt32AttributeValue
IedServer_getInt64AttributeValue
IedServer_getUInt32AttributeValue
IedServer_getFloatAttributeValue
IedServer_getUTCTimeAttributeValue
IedServer_getBitStringAttributeValue
IedServer_getStringAttributeValue

View file

@ -327,7 +327,7 @@ EXPORTS
MmsValue_cloneToBuffer @697
MmsValue_createArray @698
MmsValue_createEmptyStructure @699
MmsValue_createEmtpyArray @700
MmsValue_createEmptyArray @700
MmsValue_delete @701
MmsValue_deleteAllBitStringBits @702
MmsValue_deleteConditional @703
@ -496,4 +496,13 @@ EXPORTS
ClientReport_hasBufOvfl
ClientReport_hasDataReference
LibIEC61850_getVersionString
ClientReport_getDataReference
IedServer_getBooleanAttributeValue
IedServer_getInt32AttributeValue
IedServer_getInt64AttributeValue
IedServer_getUInt32AttributeValue
IedServer_getFloatAttributeValue
IedServer_getUTCTimeAttributeValue
IedServer_getBitStringAttributeValue
IedServer_getStringAttributeValue