Merge branch 'v1.5_develop' into v1.5

pull/383/head
Michael Zillgith 3 years ago
commit 030ae3f7b5

@ -2136,6 +2136,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedServer_getAttributeValue(IntPtr self, IntPtr dataAttribute);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedServer_getFunctionalConstrainedData(IntPtr self, IntPtr dataObject, int fc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int InternalControlPerformCheckHandler (IntPtr action, IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test, [MarshalAs(UnmanagedType.I1)] bool interlockCheck);
@ -2757,6 +2760,22 @@ namespace IEC61850
return null;
}
/// <summary>
/// Get the MmsValue object related to a functional constrained data object (FCD)
/// </summary>
/// <param name="dataObject">the data object to specify the FCD</param>
/// <param name="fc">the FC to specify the FCD</param>
/// <returns>FCDO corresponding MmsValue object cached by the server</returns>
public MmsValue GetFunctionalConstrainedData(DataObject dataObject, FunctionalConstraint fc)
{
IntPtr mmsValuePtr = IedServer_getFunctionalConstrainedData(self, dataObject.self, (int)fc);
if (mmsValuePtr != IntPtr.Zero)
return new MmsValue(mmsValuePtr);
else
return null;
}
/// <summary>
/// Enable all GOOSE control blocks.
/// </summary>

@ -24,6 +24,7 @@ print_help()
printf("-x <filename> delete file\n");
printf("-j <domainName/journalName> read journal\n");
printf("-v <variable list_name> read domain variable list\n");
printf("-z <variable list_name> get domain variable list directory\n");
printf("-y <index> array index for read access\n");
printf("-m print raw MMS messages\n");
}
@ -123,10 +124,11 @@ int main(int argc, char** argv)
int printRawMmsMessages = 0;
int deleteFile = 0;
int readVariableList = 0;
int readDataSetDirectory = 0;
int c;
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:")) != -1)
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1) {
switch (c) {
case 'm':
printRawMmsMessages = 1;
@ -167,6 +169,11 @@ int main(int argc, char** argv)
readVariableList = 1;
variableName = StringUtils_copyString(optarg);
break;
case 'z':
readDataSetDirectory = 1;
variableName = StringUtils_copyString(optarg);
break;
case 'f':
showFileList = 1;
break;
@ -192,12 +199,13 @@ int main(int argc, char** argv)
print_help();
return 0;
}
}
MmsConnection con = MmsConnection_create();
MmsError error;
/* Set maximum MMS PDU size (local detail) to 2000 byte */
/* Set maximum MMS PDU size (local detail) */
MmsConnection_setLocalDetail(con, maxPduSize);
if (printRawMmsMessages)
@ -404,6 +412,41 @@ int main(int argc, char** argv)
printf("Reading VMD scope variable list not yet supported!\n");
}
if (readDataSetDirectory) {
if (readWriteHasDomain) {
bool deletable = false;
LinkedList varListDir = MmsConnection_readNamedVariableListDirectory(con, &error, domainName, variableName, &deletable);
if (error != MMS_ERROR_NONE) {
printf("Reading variable list directory failed: (ERROR %i)\n", error);
}
else {
LinkedList varListElem = LinkedList_getNext(varListDir);
int listIdx = 0;
while (varListElem) {
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(varListElem);
if (varAccessSpec->arrayIndex)
printf("[%i] %s/%s(%i)%s\n", listIdx, varAccessSpec->domainId, varAccessSpec->itemId, varAccessSpec->arrayIndex, varAccessSpec->componentName == NULL ? "" : varAccessSpec->componentName);
else
printf("[%i] %s/%s\n", listIdx, varAccessSpec->domainId, varAccessSpec->itemId);
listIdx++;
varListElem = LinkedList_getNext(varListElem);
}
printf("Read SUCCESS\n");
}
}
else
printf("Reading VMD scope variable list not yet supported!\n");
}
if (showFileList) {
char lastName[300];
lastName[0] = 0;

@ -49,6 +49,9 @@ int main(int argc, char** argv) {
DataAttribute* temperatureValue = (DataAttribute*) ModelNode_getChild((ModelNode*) ttmp1_tmpsv, "instMag.f");
DataAttribute* temperatureTimestamp = (DataAttribute*) ModelNode_getChild((ModelNode*) ttmp1_tmpsv, "t");
LogicalNode* ggio1 = LogicalNode_create("GGIO1", lDevice1);
DataObject* ggio1_anIn1 = CDC_APC_create("AnOut1", (ModelNode*)ggio1, 0, CDC_CTL_MODEL_HAS_CANCEL | CDC_CTL_MODEL_SBO_ENHANCED, false);
DataSet* dataSet = DataSet_create("events", lln0);
DataSetEntry_create(dataSet, "TTMP1$MX$TmpSv$instMag$f", -1, NULL);

@ -911,9 +911,8 @@ IedServer_getBitStringAttributeValue(IedServer self, const DataAttribute* dataAt
LIB61850_API const char*
IedServer_getStringAttributeValue(IedServer self, const DataAttribute* dataAttribute);
/**
* \brief Get the MmsValue object related to a FunctionalConstrainedData object
* \brief Get the MmsValue object related to a functional constrained data object (FCD)
*
* Get the MmsValue from the server cache that is associated with the Functional Constrained Data (FCD)
* object that is specified by the DataObject and the given Function Constraint (FC).

@ -170,7 +170,7 @@ ReportControl_unlockNotify(ReportControl* self)
static void
purgeBuf(ReportControl* rc)
{
if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: run purgeBuf\n");
if (DEBUG_IED_SERVER) printf("IED_SERVER: RCB %s purgeBuf\n", rc->name);
/* reset trigger */
rc->triggered = false;
@ -1978,7 +1978,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
purgeBuf(rc);
if (self->rcbEventHandler) {
self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GI, NULL, DATA_ACCESS_ERROR_SUCCESS);
self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS);
}
}

@ -190,8 +190,6 @@ CDA_Cancel(ModelNode* parent, DataAttributeType type, bool isTImeActivated)
return oper;
}
/************************************************
* Common Data Classes - helper functions
***********************************************/
@ -674,7 +672,7 @@ addAnalogControls(DataObject* parent, uint32_t controlOptions, bool isIntegerNot
addCommonOperateElements(oper, isTimeActivated, true);
if (controlOptions & CDC_CTL_MODEL_HAS_CANCEL) {
DataAttribute* cancel = DataAttribute_create("SBOw", (ModelNode*) parent, IEC61850_CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0);
DataAttribute* cancel = DataAttribute_create("Cancel", (ModelNode*) parent, IEC61850_CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0);
CAC_AnalogueValue_create("ctlVal", (ModelNode*) cancel, IEC61850_FC_CO, 0, isIntegerNotFloat);

@ -118,6 +118,9 @@ mmsMsg_createStringFromAsnIdentifier(Identifier_t identifier);
LIB61850_INTERNAL void
mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, int bufSize);
LIB61850_INTERNAL char*
mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, char* componentNameBuf, int nameBufPos);
LIB61850_INTERNAL void
mmsMsg_deleteAccessResultList(AccessResult_t** accessResult, int variableCount);

@ -222,8 +222,11 @@ parseNamedVariableAttributes(GetNamedVariableListAttributesResponse_t* response,
for (i = 0; i < attributesCount; i++) {
char* domainId;
char* itemId;
char* domainId = NULL;
char* itemId = NULL;
int arrayIdx = -1;
char componentNameBuffer[129];
char* componentName = NULL;
if (response->listOfVariable.list.array[i]->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) {
@ -240,7 +243,52 @@ parseNamedVariableAttributes(GetNamedVariableListAttributesResponse_t* response,
variableSpecification.choice.name.choice.domainspecific.itemId);
}
MmsVariableAccessSpecification* listEntry = MmsVariableAccessSpecification_create(domainId, itemId);
if (response->listOfVariable.list.array[i]->alternateAccess) {
AlternateAccess_t* alternateAccess = response->listOfVariable.list.array[i]->alternateAccess;
if (alternateAccess->list.count > 0) {
if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) {
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present
== AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index)
{
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
if (asnIndex) {
long indexValue;
if (asn_INTEGER2long(asnIndex, &indexValue) != -1) {
arrayIdx = (int)indexValue;
}
}
AlternateAccess_t* nestedAltAccess = alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess;
if (nestedAltAccess) {
componentName = mmsMsg_getComponentNameFromAlternateAccess(nestedAltAccess, componentNameBuffer, 0);
}
}
}
else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) {
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
if (asnIndex) {
long indexValue;
if (asn_INTEGER2long(asnIndex, &indexValue) != -1) {
arrayIdx = (int)indexValue;
}
}
}
}
}
if (componentName)
componentName = StringUtils_copyString(componentName);
MmsVariableAccessSpecification* listEntry = MmsVariableAccessSpecification_createAlternateAccess(domainId, itemId, arrayIdx, componentName);
LinkedList_add(attributes, listEntry);
}

@ -1,7 +1,7 @@
/*
* mms_common_msg.c
*
* Copyright 2013-2019 Michael Zillgith
* Copyright 2013-2022 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -489,6 +489,75 @@ mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, i
}
}
char*
mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, char* componentNameBuf, int nameBufPos)
{
if (alternateAccess->list.count == 1) {
if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) {
if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) {
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present ==
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component)
{
Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAlternateAccess.accessSelection.choice.component;
AlternateAccess_t* nextAlternateAccess = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAlternateAccess.alternateAccess;
if (nextAlternateAccess) {
if (nameBufPos + componentIdentifier.size + 1 < 65) {
memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size);
nameBufPos += componentIdentifier.size;
componentNameBuf[nameBufPos++] = '$';
return mmsMsg_getComponentNameFromAlternateAccess(nextAlternateAccess, componentNameBuf, nameBufPos);
}
else {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: component identifier name too long!\n");
}
}
else {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: next alternate access specification is missing!\n");
}
}
}
else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) {
/* final component part */
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present ==
AlternateAccessSelection__selectAccess_PR_component)
{
Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAccess.choice.component;
if (nameBufPos + componentIdentifier.size + 1 < 65) {
memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size);
nameBufPos += componentIdentifier.size;
componentNameBuf[nameBufPos++] = 0;
return componentNameBuf;
}
else {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: component identifier name too long!\n");
}
}
}
}
}
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: invalid component access specification\n");
return NULL;
}
#if (MMS_FILE_SERVICE == 1)
void

@ -284,12 +284,15 @@ parseInitRequestDetail(MmsServerConnection self, uint8_t* buffer, int bufPos, in
{
uint32_t protocolVersion = BerDecoder_decodeUint32(buffer, length, bufPos);
if (protocolVersion != 1) {
if (protocolVersion < 1) {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: invalid protocol version %u\n", protocolVersion);
return false;
}
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: proposed version number %u\n", protocolVersion);
}
break;

@ -296,75 +296,6 @@ checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier)
return true;
}
static char*
getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, char* componentNameBuf, int nameBufPos)
{
if (alternateAccess->list.count == 1) {
if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) {
if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) {
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present ==
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component)
{
Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAlternateAccess.accessSelection.choice.component;
AlternateAccess_t* nextAlternateAccess = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAlternateAccess.alternateAccess;
if (nextAlternateAccess) {
if (nameBufPos + componentIdentifier.size + 1 < 65) {
memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size);
nameBufPos += componentIdentifier.size;
componentNameBuf[nameBufPos++] = '$';
return getComponentNameFromAlternateAccess(nextAlternateAccess, componentNameBuf, nameBufPos);
}
else {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: component identifier name too long!\n");
}
}
else {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: next alternate access specification is missing!\n");
}
}
}
else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) {
/* final component part */
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present ==
AlternateAccessSelection__selectAccess_PR_component)
{
Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAccess.choice.component;
if (nameBufPos + componentIdentifier.size + 1 < 65) {
memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size);
nameBufPos += componentIdentifier.size;
componentNameBuf[nameBufPos++] = 0;
return componentNameBuf;
}
else {
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: component identifier name too long!\n");
}
}
}
}
}
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: invalid component access specification\n");
return NULL;
}
static MmsNamedVariableList
createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device,
DefineNamedVariableListRequest_t* request,
@ -426,7 +357,7 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device,
if (alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess) {
componentNameBuf[0] = 0;
componentName = getComponentNameFromAlternateAccess(
componentName = mmsMsg_getComponentNameFromAlternateAccess(
alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess,
componentNameBuf, 0);
}

Loading…
Cancel
Save