You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libiec61850/src/iec61850/client/client_sv_control.c

354 lines
9.0 KiB
C

/*
* client_sv_control.c
*
* Copyright 2015-2022 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
#include "iec61850_client.h"
#include "stack_config.h"
#include "ied_connection_private.h"
#include "libiec61850_platform_includes.h"
struct sClientSVControlBlock {
IedConnection connection;
bool isMulticast;
char* reference;
IedClientError lastError;
};
ClientSVControlBlock
ClientSVControlBlock_create(IedConnection connection, const char* reference)
{
bool isMulticast = false;
/* Check if CB exists and if it is a unicast or mulitcast CB */
IedClientError error;
MmsValue* value = IedConnection_readObject(connection, &error, reference, IEC61850_FC_MS);
if ((error == IED_ERROR_OK) && (MmsValue_getType(value) != MMS_DATA_ACCESS_ERROR)) {
isMulticast = true;
MmsValue_delete(value);
}
else {
MmsValue_delete(value);
value = IedConnection_readObject(connection, &error, reference, IEC61850_FC_US);
if ((error == IED_ERROR_OK) && (MmsValue_getType(value) != MMS_DATA_ACCESS_ERROR))
MmsValue_delete(value);
else {
MmsValue_delete(value);
return NULL;
}
}
ClientSVControlBlock self = (ClientSVControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientSVControlBlock));
if (self) {
self->connection = connection;
self->reference = StringUtils_copyString(reference);
self->isMulticast = isMulticast;
}
return self;
}
void
ClientSVControlBlock_destroy(ClientSVControlBlock self)
{
if (self) {
GLOBAL_FREEMEM(self->reference);
GLOBAL_FREEMEM(self);
}
}
IedClientError
ClientSVControlBlock_getLastComError(ClientSVControlBlock self)
{
return self->lastError;
}
bool
ClientSVControlBlock_isMulticast(ClientSVControlBlock self)
{
return self->isMulticast;
}
static bool
setBooleanVariable(ClientSVControlBlock self, const char* varName, bool value)
{
char refBuf[130];
StringUtils_concatString(refBuf, 130, self->reference, ".");
StringUtils_appendString(refBuf, 130, varName);
self->lastError = IED_ERROR_OK;
if (self->isMulticast)
IedConnection_writeBooleanValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_MS, value);
else
IedConnection_writeBooleanValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_US, value);
if (self->lastError == IED_ERROR_OK)
return true;
else
return false;
}
bool
ClientSVControlBlock_setSvEna(ClientSVControlBlock self, bool value)
{
return setBooleanVariable(self, "SvEna", value);
}
bool
ClientSVControlBlock_setResv(ClientSVControlBlock self, bool value)
{
if (self->isMulticast == false)
return setBooleanVariable(self, "SvEna", value);
else
return false;
}
static bool
readBooleanVariable(ClientSVControlBlock self, const char* varName)
{
char refBuf[130];
StringUtils_concatString(refBuf, 130, self->reference, ".");
StringUtils_appendString(refBuf, 130, varName);
self->lastError = IED_ERROR_OK;
bool retVal;
if (self->isMulticast)
retVal = IedConnection_readBooleanValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_MS);
else
retVal = IedConnection_readBooleanValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_US);
return retVal;
}
bool
ClientSVControlBlock_getSvEna(ClientSVControlBlock self)
{
return readBooleanVariable(self, "SvEna");
}
bool
ClientSVControlBlock_getResv(ClientSVControlBlock self)
{
return readBooleanVariable(self, "Resv");
}
static char*
readStringVariable(ClientSVControlBlock self, const char* varName)
{
char refBuf[130];
StringUtils_concatString(refBuf, 130, self->reference, ".");
StringUtils_appendString(refBuf, 130, varName);
self->lastError = IED_ERROR_OK;
char* retVal;
if (self->isMulticast)
retVal = IedConnection_readStringValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_MS);
else
retVal = IedConnection_readStringValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_US);
return retVal;
}
char*
ClientSVControlBlock_getMsvID(ClientSVControlBlock self)
{
return readStringVariable(self, "MsvID");
}
char*
ClientSVControlBlock_getDatSet(ClientSVControlBlock self)
{
return readStringVariable(self, "DatSet");
}
static uint32_t
readUIntVariable(ClientSVControlBlock self, const char* varName)
{
char refBuf[130];
StringUtils_concatString(refBuf, 130, self->reference, ".");
StringUtils_appendString(refBuf, 130, varName);
self->lastError = IED_ERROR_OK;
uint32_t retVal;
if (self->isMulticast)
retVal = IedConnection_readUnsigned32Value(self->connection, &(self->lastError), refBuf, IEC61850_FC_MS);
else
retVal = IedConnection_readUnsigned32Value(self->connection, &(self->lastError), refBuf, IEC61850_FC_US);
return retVal;
}
uint32_t
ClientSVControlBlock_getConfRev(ClientSVControlBlock self)
{
return readUIntVariable(self, "ConfRev");
}
uint16_t
ClientSVControlBlock_getSmpRate(ClientSVControlBlock self)
{
return readUIntVariable(self, "SmpRate");
}
int
ClientSVControlBlock_getOptFlds(ClientSVControlBlock self)
{
char refBuf[130];
StringUtils_concatString(refBuf, 130, self->reference, ".OptFlds");
self->lastError = IED_ERROR_OK;
MmsValue* optFlds;
if (self->isMulticast)
optFlds = IedConnection_readObject(self->connection, &(self->lastError), refBuf, IEC61850_FC_MS);
else
optFlds = IedConnection_readObject(self->connection, &(self->lastError), refBuf, IEC61850_FC_US);
if (optFlds == NULL)
return 0;
int retVal = 0;
if (MmsValue_getType(optFlds) == MMS_BIT_STRING)
retVal = MmsValue_getBitStringAsInteger(optFlds);
MmsValue_delete(optFlds);
return retVal;
}
uint8_t
ClientSVControlBlock_getSmpMod(ClientSVControlBlock self)
{
return readUIntVariable(self, "SmpMod");
}
int
ClientSVControlBlock_getNoASDU(ClientSVControlBlock self)
{
return readUIntVariable(self, "noASDU");
}
PhyComAddress
ClientSVControlBlock_getDstAddress(ClientSVControlBlock self)
{
char refBuf[130];
StringUtils_concatString(refBuf, 130, self->reference, ".DstAddress");
self->lastError = IED_ERROR_OK;
MmsValue* dstAddrValue;
if (self->isMulticast)
dstAddrValue = IedConnection_readObject(self->connection, &(self->lastError), refBuf, IEC61850_FC_MS);
else
dstAddrValue = IedConnection_readObject(self->connection, &(self->lastError), refBuf, IEC61850_FC_US);
PhyComAddress retVal;
memset(&retVal, 0, sizeof(retVal));
if (dstAddrValue == NULL) goto exit_error;
if (MmsValue_getType(dstAddrValue) != MMS_STRUCTURE) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong type\n");
goto exit_cleanup;
}
if (MmsValue_getArraySize(dstAddrValue) != 4) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong type\n");
goto exit_cleanup;
}
MmsValue* addr = MmsValue_getElement(dstAddrValue, 0);
if (MmsValue_getType(addr) != MMS_OCTET_STRING) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong type\n");
goto exit_cleanup;
}
if (MmsValue_getOctetStringSize(addr) != 6) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong size\n");
goto exit_cleanup;
}
const uint8_t* addrBuf = MmsValue_getOctetStringBuffer(addr);
memcpy(&(retVal.dstAddress), addrBuf, 6);
MmsValue* prio = MmsValue_getElement(dstAddrValue, 1);
if (MmsValue_getType(prio) != MMS_UNSIGNED) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - prio has wrong type\n");
goto exit_cleanup;
}
retVal.vlanPriority = MmsValue_toUint32(prio);
MmsValue* vid = MmsValue_getElement(dstAddrValue, 2);
if (MmsValue_getType(vid) != MMS_UNSIGNED) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - vid has wrong type\n");
goto exit_cleanup;
}
retVal.vlanId = MmsValue_toUint32(vid);
MmsValue* appID = MmsValue_getElement(dstAddrValue, 3);
if (MmsValue_getType(appID) != MMS_UNSIGNED) {
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - appID has wrong type\n");
goto exit_cleanup;
}
retVal.appId = MmsValue_toUint32(appID);
exit_cleanup:
MmsValue_delete(dstAddrValue);
exit_error:
return retVal;
}