- 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:
parent
78a694c5d3
commit
375b1a9c12
19 changed files with 823 additions and 372 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue