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/server/mms_mapping/logging.c

895 lines
25 KiB
C

/*
* logging.c
*
* Copyright 2016 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 "libiec61850_platform_includes.h"
#include "stack_config.h"
#include "mms_mapping.h"
#include "logging.h"
#include "linked_list.h"
#include "array_list.h"
#include "hal_thread.h"
#include "simple_allocator.h"
#include "mem_alloc_linked_list.h"
#include "mms_mapping_internal.h"
#include "mms_value_internal.h"
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
LogInstance*
LogInstance_create(LogicalNode* parentLN, const char* name)
{
LogInstance* self = (LogInstance*) GLOBAL_MALLOC(sizeof(LogInstance));
self->name = copyString(name);
self->parentLN = parentLN;
self->logStorage = NULL;
self->locked = false;
self->oldEntryId = 0;
self->oldEntryTime = 0;
self->newEntryId = 0;
self->newEntryTime = 0;
return self;
}
void
LogInstance_destroy(LogInstance* self)
{
GLOBAL_FREEMEM(self->name);
GLOBAL_FREEMEM(self);
}
void
LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* value, uint8_t flag)
{
LogStorage logStorage = self->logStorage;
if (logStorage != NULL) {
while (self->locked)
Thread_sleep(1);
self->locked = true;
//if (DEBUG_IED_SERVER)
printf("IED_SERVER: Log value - dataRef: %s flag: %i\n", dataRef, flag);
uint64_t timestamp = Hal_getTimeInMs();
uint64_t entryID = LogStorage_addEntry(logStorage, timestamp);
int dataSize = MmsValue_encodeMmsData(value, NULL, 0, false);
uint8_t* data = GLOBAL_MALLOC(dataSize);
MmsValue_encodeMmsData(value, data, 0, true);
LogStorage_addEntryData(logStorage, entryID, dataRef, data, dataSize, flag);
self->locked = false;
GLOBAL_FREEMEM(data);
self->newEntryId = entryID;
self->newEntryTime = timestamp;
}
else
if (DEBUG_IED_SERVER)
printf("IED_SERVER: no log storage available for logging!\n");
}
uint64_t
LogInstance_logEntryStart(LogInstance* self)
{
LogStorage logStorage = self->logStorage;
if (logStorage != NULL) {
while (self->locked)
Thread_sleep(1);
self->locked = true;
uint64_t timestamp = Hal_getTimeInMs();
uint64_t entryID = LogStorage_addEntry(logStorage, timestamp);
return entryID;
}
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: no log storage available for logging!\n");
return 0;
}
}
void
LogInstance_logEntryData(LogInstance* self, uint64_t entryID, const char* dataRef, MmsValue* value, uint8_t flag)
{
LogStorage logStorage = self->logStorage;
if (logStorage != NULL) {
int dataSize = MmsValue_encodeMmsData(value, NULL, 0, false);
uint8_t* data = GLOBAL_MALLOC(dataSize);
MmsValue_encodeMmsData(value, data, 0, true);
LogStorage_addEntryData(logStorage, entryID, dataRef, data, dataSize, flag);
self->locked = false;
GLOBAL_FREEMEM(data);
}
}
void
LogInstance_logEntryFinished(LogInstance* self, uint64_t entryID)
{
self->locked = false;
}
void
LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage)
{
self->logStorage = logStorage;
LogStorage_getOldestAndNewestEntries(logStorage, &(self->newEntryId), &(self->newEntryTime),
&(self->oldEntryId), &(self->oldEntryTime));
}
LogControl*
LogControl_create(LogicalNode* parentLN, MmsMapping* mmsMapping)
{
LogControl* self = (LogControl*) GLOBAL_MALLOC(sizeof(LogControl));
self->enabled = false;
self->dataSet = NULL;
self->triggerOps = 0;
self->logicalNode = parentLN;
self->mmsMapping = mmsMapping;
self->dataSetRef = NULL;
self->logInstance = NULL;
self->intgPd = 0;
self->nextIntegrityScan = 0;
return self;
}
void
LogControl_destroy(LogControl* self)
{
if (self != NULL) {
MmsValue_delete(self->mmsValue);
GLOBAL_FREEMEM(self->name);
if (self->dataSetRef != NULL)
GLOBAL_FREEMEM(self->dataSetRef);
GLOBAL_FREEMEM(self);
}
}
void
LogControl_setLog(LogControl* self, LogInstance* logInstance)
{
self->logInstance = logInstance;
}
static void
prepareLogControl(LogControl* logControl)
{
if (logControl->dataSetRef == NULL) {
printf(" no data set specified!\n");
return;
}
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, logControl->dataSetRef);
if (dataSet == NULL) {
printf(" data set (%s) not found!\n", logControl->dataSetRef);
return;
}
else
logControl->dataSet = dataSet;
}
static bool
enableLogging(LogControl* self)
{
if ((self->dataSet != NULL) && (self->logInstance != NULL)) {
self->enabled = true;
if ((self->triggerOps & TRG_OPT_INTEGRITY) && (self->intgPd != 0))
self->nextIntegrityScan = Hal_getTimeInMs();
else
self->nextIntegrityScan = 0;
MmsValue* enabled = MmsValue_getSubElement(self->mmsValue, self->mmsType, "LogEna");
MmsValue_setBoolean(enabled, true);
return true;
}
else
return false;
}
static LogControlBlock*
getLCBForLogicalNodeWithIndex(MmsMapping* self, LogicalNode* logicalNode, int index)
{
int lcbCount = 0;
LogControlBlock* nextLcb = self->model->lcbs;
while (nextLcb != NULL ) {
if (nextLcb->parent == logicalNode) {
if (lcbCount == index)
return nextLcb;
lcbCount++;
}
nextLcb = nextLcb->sibling;
}
return NULL ;
}
static LogControl*
lookupLogControl(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName)
{
LinkedList element = LinkedList_getNext(self->logControls);
while (element != NULL) {
LogControl* logControl = (LogControl*) element->data;
if (logControl->domain == domain) {
if (strcmp(logControl->logicalNode->name, lnName) == 0) {
if (strcmp(logControl->logControlBlock->name, objectName) == 0) {
return logControl;
}
}
}
element = LinkedList_getNext(element);
}
return NULL;
}
static LogInstance*
getLogInstanceByLogRef(MmsMapping* self, const char* logRef)
{
char refStr[130];
char* domainName;
char* lnName;
char* logName;
strncpy(refStr, logRef, 129);
domainName = refStr;
lnName = strchr(refStr, '/');
if (lnName == NULL)
return NULL;
if ((lnName - domainName) > 64)
return NULL;
lnName[0] = 0;
lnName++;
logName = strchr(lnName, '$');
if (logName == NULL)
return NULL;
logName[0] = 0;
logName++;
LinkedList instance = LinkedList_getNext(self->logInstances);
while (instance != NULL) {
LogInstance* logInstance = LinkedList_getData(instance);
if (strcmp(logInstance->name, logName) == 0) {
if (strcmp(lnName, logInstance->parentLN->name) == 0) {
LogicalDevice* ld = (LogicalDevice*) logInstance->parentLN->parent;
if (strcmp(ld->name, domainName) == 0)
return logInstance;
}
}
instance = LinkedList_getNext(instance);
}
return NULL;
}
static void
updateLogStatusInLCB(LogControl* self)
{
LogInstance* logInstance = self->logInstance;
if (logInstance != NULL) {
MmsValue_setBinaryTime(self->oldEntrTm, logInstance->oldEntryTime);
MmsValue_setBinaryTime(self->newEntrTm, logInstance->newEntryTime);
MmsValue_setOctetString(self->oldEntr, (uint8_t*) &(logInstance->oldEntryId), 8);
MmsValue_setOctetString(self->newEntr, (uint8_t*) &(logInstance->newEntryId), 8);
}
}
MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
bool updateValue = false;
char variableId[130];
strncpy(variableId, variableIdOrig, 129);
char* separator = strchr(variableId, '$');
*separator = 0;
char* lnName = variableId;
if (lnName == NULL)
return DATA_ACCESS_ERROR_INVALID_ADDRESS;
char* objectName = MmsMapping_getNextNameElement(separator + 1);
if (objectName == NULL)
return DATA_ACCESS_ERROR_INVALID_ADDRESS;
char* varName = MmsMapping_getNextNameElement(objectName);
if (varName != NULL)
*(varName - 1) = 0;
LogControl* logControl = lookupLogControl(self, domain, lnName, objectName);
if (logControl == NULL) {
return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT;
}
if (strcmp(varName, "LogEna") == 0) {
bool logEna = MmsValue_getBoolean(value);
if (logEna == false) {
logControl->enabled = false;
}
else {
if (enableLogging(logControl)) {
logControl->enabled = true;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: enabled log control %s\n", logControl->name);
}
else
return DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
}
updateValue = true;
}
else if (strcmp(varName, "LogRef") == 0) {
if (logControl->enabled == false) {
/* check if logRef is valid or NULL */
const char* logRef = MmsValue_toString(value);
if (logRef == NULL) {
logControl->logInstance = NULL;
updateValue = true;
}
else {
if (strcmp(logRef, "") == 0) {
logControl->logInstance = NULL;
updateValue = true;
}
else {
/* remove IED name from logRef */
char* iedName = self->mmsDevice->deviceName;
uint32_t iedNameLen = strlen(iedName);
if (iedNameLen < strlen(logRef)) {
if (memcmp(iedName, logRef, iedNameLen) == 0) {
logRef = logRef + iedNameLen;
}
}
LogInstance* logInstance = getLogInstanceByLogRef(self, logRef);
if (logInstance != NULL) {
logControl->logInstance = logInstance;
updateValue = true;
}
else
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
}
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else if (strcmp(varName, "DatSet") == 0) {
if (logControl->enabled == false) {
/* check if datSet is valid or NULL/empty */
const char* dataSetRef = MmsValue_toString(value);
if (strlen(dataSetRef) == 0) {
logControl->dataSet = NULL;
updateValue = true;
}
else {
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, dataSetRef);
if (dataSet == NULL) {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: data set (%s) not found!\n", logControl->dataSetRef);
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
else {
logControl->dataSet = dataSet;
updateValue = true;
}
}
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else if (strcmp(varName, "IntgPd") == 0) {
if (logControl->enabled == false) {
logControl->intgPd = MmsValue_toUint32(value);
updateValue = true;
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else if (strcmp(varName, "TrgOps") == 0) {
if (logControl->enabled == false) {
logControl->triggerOps = (MmsValue_getBitStringAsInteger(value) / 2);
updateValue = true;
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
if (updateValue) {
MmsValue* element = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName);
MmsValue_update(element, value);
return DATA_ACCESS_ERROR_SUCCESS;
}
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
MmsValue*
LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig)
{
MmsValue* value = NULL;
char variableId[130];
strncpy(variableId, variableIdOrig, 129);
char* separator = strchr(variableId, '$');
*separator = 0;
char* lnName = variableId;
if (lnName == NULL)
return NULL;
char* objectName = MmsMapping_getNextNameElement(separator + 1);
if (objectName == NULL)
return NULL;
char* varName = MmsMapping_getNextNameElement(objectName);
if (varName != NULL)
*(varName - 1) = 0;
LogControl* logControl = lookupLogControl(self, domain, lnName, objectName);
if (logControl != NULL) {
updateLogStatusInLCB(logControl);
if (varName != NULL) {
value = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName);
}
else {
value = logControl->mmsValue;
}
}
return value;
}
static char*
createDataSetReferenceForDefaultDataSet(LogControlBlock* lcb, LogControl* logControl)
{
char* dataSetReference;
char* domainName = MmsDomain_getName(logControl->domain);
char* lnName = lcb->parent->name;
dataSetReference = createString(5, domainName, "/", lnName, "$", lcb->dataSetName);
return dataSetReference;
}
static MmsValue*
createTrgOps(LogControlBlock* logControlBlock) {
MmsValue* trgOps = MmsValue_newBitString(-6);
uint8_t triggerOps = logControlBlock->trgOps;
if (triggerOps & TRG_OPT_DATA_CHANGED)
MmsValue_setBitStringBit(trgOps, 1, true);
if (triggerOps & TRG_OPT_QUALITY_CHANGED)
MmsValue_setBitStringBit(trgOps, 2, true);
if (triggerOps & TRG_OPT_DATA_UPDATE)
MmsValue_setBitStringBit(trgOps, 3, true);
if (triggerOps & TRG_OPT_INTEGRITY)
MmsValue_setBitStringBit(trgOps, 4, true);
return trgOps;
}
static MmsVariableSpecification*
createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
LogControl* logControl)
{
MmsVariableSpecification* lcb = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
lcb->name = copyString(logControlBlock->name);
lcb->type = MMS_STRUCTURE;
MmsValue* mmsValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
mmsValue->deleteValue = false;
mmsValue->type = MMS_STRUCTURE;
int structSize = 9;
mmsValue->value.structure.size = structSize;
mmsValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(structSize, sizeof(MmsValue*));
lcb->typeSpec.structure.elementCount = structSize;
lcb->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(structSize,
sizeof(MmsVariableSpecification*));
/* LogEna */
MmsVariableSpecification* namedVariable =
(MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("LogEna");
namedVariable->type = MMS_BOOLEAN;
lcb->typeSpec.structure.elements[0] = namedVariable;
mmsValue->value.structure.components[0] = MmsValue_newBoolean(logControlBlock->logEna);
/* LogRef */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("LogRef");
namedVariable->typeSpec.visibleString = -129;
namedVariable->type = MMS_VISIBLE_STRING;
lcb->typeSpec.structure.elements[1] = namedVariable;
if (logControlBlock->logRef != NULL) {
char logRef[130];
int maxLogRefLength = 129 - strlen(self->model->name);
strcpy(logRef, self->model->name);
strncat(logRef, logControlBlock->logRef, maxLogRefLength);
mmsValue->value.structure.components[1] = MmsValue_newVisibleString(logRef);
}
else {
char* logRef = createString(4, logControl->domain->domainName, "/", logControlBlock->parent->name,
"$GeneralLog");
mmsValue->value.structure.components[1] = MmsValue_newVisibleString(logRef);
GLOBAL_FREEMEM(logRef);
}
/* DatSet */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("DatSet");
namedVariable->typeSpec.visibleString = -129;
namedVariable->type = MMS_VISIBLE_STRING;
lcb->typeSpec.structure.elements[2] = namedVariable;
if (logControlBlock->dataSetName != NULL) {
char* dataSetReference = createDataSetReferenceForDefaultDataSet(logControlBlock, logControl);
logControl->dataSetRef = dataSetReference;
mmsValue->value.structure.components[2] = MmsValue_newVisibleString(dataSetReference);
}
else
mmsValue->value.structure.components[2] = MmsValue_newVisibleString("");
/* OldEntrTm */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("OldEntrTm");
namedVariable->type = MMS_BINARY_TIME;
namedVariable->typeSpec.binaryTime = 6;
lcb->typeSpec.structure.elements[3] = namedVariable;
mmsValue->value.structure.components[3] = MmsValue_newBinaryTime(false);
logControl->oldEntrTm = mmsValue->value.structure.components[3];
/* NewEntrTm */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("NewEntrTm");
namedVariable->type = MMS_BINARY_TIME;
namedVariable->typeSpec.binaryTime = 6;
lcb->typeSpec.structure.elements[4] = namedVariable;
mmsValue->value.structure.components[4] = MmsValue_newBinaryTime(false);
logControl->newEntrTm = mmsValue->value.structure.components[4];
/* OldEntr */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("OldEntr");
namedVariable->type = MMS_OCTET_STRING;
namedVariable->typeSpec.octetString = 8;
lcb->typeSpec.structure.elements[5] = namedVariable;
mmsValue->value.structure.components[5] = MmsValue_newOctetString(8, 8);
logControl->oldEntr = mmsValue->value.structure.components[5];
/* NewEntr */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("NewEntr");
namedVariable->type = MMS_OCTET_STRING;
namedVariable->typeSpec.octetString = 8;
lcb->typeSpec.structure.elements[6] = namedVariable;
mmsValue->value.structure.components[6] = MmsValue_newOctetString(8, 8);
logControl->newEntr = mmsValue->value.structure.components[6];
/* TrgOps */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("TrgOps");
namedVariable->type = MMS_BIT_STRING;
namedVariable->typeSpec.bitString = -6;
lcb->typeSpec.structure.elements[7] = namedVariable;
mmsValue->value.structure.components[7] = createTrgOps(logControlBlock);
/* IntgPd */
namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
namedVariable->name = copyString("IntgPd");
namedVariable->type = MMS_UNSIGNED;
namedVariable->typeSpec.unsignedInteger = 32;
lcb->typeSpec.structure.elements[8] = namedVariable;
mmsValue->value.structure.components[8] =
MmsValue_newUnsignedFromUint32(logControlBlock->intPeriod);
logControl->intgPd = logControlBlock->intPeriod;
logControl->mmsType = lcb;
logControl->mmsValue = mmsValue;
logControl->logControlBlock = logControlBlock;
logControl->triggerOps = logControlBlock->trgOps;
logControl->enabled = logControlBlock->logEna;
prepareLogControl(logControl);
if (logControl->enabled)
enableLogging(logControl);
return lcb;
}
MmsVariableSpecification*
Logging_createLCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode,
int lcbCount)
{
MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1,
sizeof(MmsVariableSpecification));
namedVariable->name = copyString("LG");
namedVariable->type = MMS_STRUCTURE;
namedVariable->typeSpec.structure.elementCount = lcbCount;
namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(lcbCount,
sizeof(MmsVariableSpecification*));
int currentLcb = 0;
while (currentLcb < lcbCount) {
LogControl* logControl = LogControl_create(logicalNode, self);
LogControlBlock* logControlBlock = getLCBForLogicalNodeWithIndex(self, logicalNode, currentLcb);
logControl->name = createString(3, logicalNode->name, "$LG$", logControlBlock->name);
logControl->domain = domain;
namedVariable->typeSpec.structure.elements[currentLcb] =
createLogControlBlock(self, logControlBlock, logControl);
if (logControlBlock->logRef != NULL)
logControl->logInstance = getLogInstanceByLogRef(self, logControlBlock->logRef);
LinkedList_add(self->logControls, logControl);
currentLcb++;
}
return namedVariable;
}
static void
LogControl_logAllDatasetEntries(LogControl* self, const char* iedName)
{
if (self->dataSet == NULL)
return;
if (self->logInstance != NULL) {
char dataRef[130];
LogInstance* log = self->logInstance;
uint64_t entryID = LogInstance_logEntryStart(log);
DataSetEntry* dataSetEntry = self->dataSet->fcdas;
while (dataSetEntry != NULL) {
sprintf(dataRef, "%s%s/%s", iedName, dataSetEntry->logicalDeviceName, dataSetEntry->variableName);
LogInstance_logEntryData(log, entryID, dataRef, dataSetEntry->value, TRG_OPT_INTEGRITY * 2);
dataSetEntry = dataSetEntry->sibling;
}
LogInstance_logEntryFinished(log, entryID);
}
}
void
Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs)
{
LinkedList logControlElem = LinkedList_getNext(self->logControls);
while (logControlElem != NULL) {
LogControl* logControl = (LogControl*) LinkedList_getData(logControlElem);
if (logControl->enabled) {
if (logControl->nextIntegrityScan != 0) {
if (currentTimeInMs >= logControl->nextIntegrityScan) {
//if (DEBUG_IED_SERVER)
printf("IED_SERVER: INTEGRITY SCAN for log %s\n", logControl->name);
LogControl_logAllDatasetEntries(logControl, self->mmsDevice->deviceName);
logControl->nextIntegrityScan += logControl->intgPd;
}
}
}
logControlElem = LinkedList_getNext(logControlElem);
}
}
void
MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logStorage)
{
LogInstance* logInstance = getLogInstanceByLogRef(self, logRef);
if (logInstance != NULL) {
LogInstance_setLogStorage(logInstance, logStorage);
char domainName[65];
MmsMapping_getMmsDomainFromObjectReference(logRef, domainName);
char domainNameWithIEDName[65];
strcpy(domainNameWithIEDName, self->model->name);
strcat(domainNameWithIEDName, domainName);
MmsDomain* mmsDomain = MmsDevice_getDomain(self->mmsDevice, domainNameWithIEDName);
if (mmsDomain == NULL) {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: MmsMapping_setLogStorage: domain %s not found!\n", domainNameWithIEDName);
return;
}
MmsJournal mmsJournal = NULL;
char* logName = strchr(logRef, '/');
if (logName != NULL) {
logName += 1;
mmsJournal = MmsDomain_getJournal(mmsDomain, logName);
}
if (mmsJournal != NULL)
mmsJournal->logStorage = logStorage;
else
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Failed to retrieve MMS journal for log!\n");
}
if (DEBUG_IED_SERVER)
if (logInstance == NULL)
printf("IED_SERVER: MmsMapping_setLogStorage no matching log for %s found!\n", logRef);
}
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */