libiec61850/src/iec61850/server/model/dynamic_model.c

884 lines
20 KiB
C

/*
* dynamic_model.c
*
* Copyright 2014-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 "iec61850_server.h"
#include "libiec61850_platform_includes.h"
#include "stack_config.h"
static void
iedModel_emptyVariableInitializer(void)
{
return;
}
void
IedModel_setIedNameForDynamicModel(IedModel* self, const char* name)
{
if (self->name != NULL)
GLOBAL_FREEMEM(self->name);
self->name = copyString(name);
}
IedModel*
IedModel_create(const char* name/*, MemoryAllocator allocator*/)
{
IedModel* self = (IedModel*) GLOBAL_CALLOC(1, sizeof(IedModel));
if (name)
self->name = copyString(name);
else
self->name = NULL;
self->rcbs = NULL;
self->dataSets = NULL;
self->gseCBs = NULL;
self->sgcbs = NULL;
self->lcbs = NULL;
self->logs = NULL;
self->initializer = iedModel_emptyVariableInitializer;
return self;
}
static void
IedModel_addDataSet(IedModel* self, DataSet* dataSet)
{
if (self->dataSets == NULL)
self->dataSets = dataSet;
else {
DataSet* lastDataSet = self->dataSets;
while (lastDataSet != NULL) {
if (lastDataSet->sibling == NULL) {
lastDataSet->sibling = dataSet;
break;
}
lastDataSet = lastDataSet->sibling;
}
}
}
static void
IedModel_addLogicalDevice(IedModel* self, LogicalDevice* lDevice)
{
if (self->firstChild == NULL)
self->firstChild = lDevice;
else {
LogicalDevice* sibling = self->firstChild;
while (sibling->sibling != NULL)
sibling = (LogicalDevice*) sibling->sibling;
sibling->sibling = (ModelNode*) lDevice;
}
}
static void
IedModel_addLog(IedModel* self, Log* log)
{
if (self->logs == NULL)
self->logs = log;
else {
Log* lastLog = self->logs;
while (lastLog->sibling != NULL)
lastLog = lastLog->sibling;
lastLog->sibling = log;
}
}
static void
IedModel_addLogControlBlock(IedModel* self, LogControlBlock* lcb)
{
if (self->lcbs == NULL)
self->lcbs = lcb;
else {
LogControlBlock* lastLcb = self->lcbs;
while (lastLcb->sibling != NULL)
lastLcb = lastLcb->sibling;
lastLcb->sibling = lcb;
}
}
static void
IedModel_addReportControlBlock(IedModel* self, ReportControlBlock* rcb)
{
if (self->rcbs == NULL)
self->rcbs = rcb;
else {
ReportControlBlock* lastRcb = self->rcbs;
while (lastRcb->sibling != NULL)
lastRcb = lastRcb->sibling;
lastRcb->sibling = rcb;
}
}
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
static void
IedModel_addSettingGroupControlBlock(IedModel* self, SettingGroupControlBlock* sgcb)
{
if (self->sgcbs == NULL)
self->sgcbs = sgcb;
else {
SettingGroupControlBlock* lastSgcb = self->sgcbs;
while (lastSgcb->sibling != NULL)
lastSgcb = lastSgcb->sibling;
lastSgcb->sibling = sgcb;
}
}
#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */
static void
IedModel_addGSEControlBlock(IedModel* self, GSEControlBlock* gcb)
{
if (self->gseCBs == NULL)
self->gseCBs = gcb;
else {
GSEControlBlock* lastGcb = self->gseCBs;
while (lastGcb->sibling != NULL)
lastGcb = lastGcb->sibling;
lastGcb->sibling = gcb;
}
}
LogicalDevice*
LogicalDevice_create(const char* name, IedModel* parent)
{
LogicalDevice* self = (LogicalDevice*) GLOBAL_CALLOC(1, sizeof(LogicalDevice));
self->name = copyString(name);
self->modelType = LogicalDeviceModelType;
self->parent = (ModelNode*) parent;
self->sibling = NULL;
IedModel_addLogicalDevice(parent, self);
return self;
}
static LogicalNode*
LogicalDevice_getLastLogicalNode(LogicalDevice* self)
{
LogicalNode* lastNode = (LogicalNode*) self->firstChild;
LogicalNode* nextNode = lastNode;
while (nextNode != NULL) {
lastNode = nextNode;
nextNode = (LogicalNode*) nextNode->sibling;
}
return lastNode;
}
static void
LogicalDevice_addLogicalNode(LogicalDevice* self, LogicalNode* lNode)
{
if (self->firstChild == NULL)
self->firstChild = (ModelNode*) lNode;
else {
LogicalNode* lastNode = LogicalDevice_getLastLogicalNode(self);
lastNode->sibling = (ModelNode*) lNode;
}
}
LogicalNode*
LogicalNode_create(const char* name, LogicalDevice* parent)
{
LogicalNode* self = (LogicalNode*) GLOBAL_MALLOC(sizeof(LogicalNode));
self->name = copyString(name);
self->parent = (ModelNode*) parent;
self->modelType = LogicalNodeModelType;
self->firstChild = NULL;
self->sibling = NULL;
LogicalDevice_addLogicalNode(parent, self);
return self;
}
static DataObject*
LogicalNode_getLastDataObject(LogicalNode* self)
{
DataObject* lastNode = (DataObject*) self->firstChild;
DataObject* nextNode = lastNode;
while (nextNode != NULL) {
lastNode = nextNode;
nextNode = (DataObject*) nextNode->sibling;
}
return lastNode;
}
static void
LogicalNode_addDataObject(LogicalNode* self, DataObject* dataObject)
{
if (self->firstChild == NULL)
self->firstChild = (ModelNode*) dataObject;
else {
DataObject* lastDataObject = LogicalNode_getLastDataObject(self);
lastDataObject->sibling = (ModelNode*) dataObject;
}
}
static void
LogicalNode_addLog(LogicalNode* self, Log* log)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addLog(model, log);
}
Log*
Log_create(const char* name, LogicalNode* parent)
{
Log* self = (Log*) GLOBAL_MALLOC(sizeof(Log));
self->name = copyString(name);
self->parent = parent;
self->sibling = NULL;
LogicalNode_addLog(parent, self);
return self;
}
static void
LogicalNode_addLogControlBlock(LogicalNode* self, LogControlBlock* lcb)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addLogControlBlock(model, lcb);
}
LogControlBlock*
LogControlBlock_create(const char* name, LogicalNode* parent, char* dataSetName, char* logRef, uint8_t trgOps,
uint32_t intPeriod, bool logEna, bool reasonCode)
{
LogControlBlock* self = (LogControlBlock*) GLOBAL_MALLOC(sizeof(LogControlBlock));
self->name = copyString(name);
self->parent = parent;
self->sibling = NULL;
if (dataSetName)
self->dataSetName = copyString(dataSetName);
else
self->dataSetName = NULL;
if (logRef)
self->logRef = copyString(logRef);
else
self->logRef = NULL;
self->trgOps = trgOps;
self->intPeriod = intPeriod;
self->logEna = logEna;
self->reasonCode = reasonCode;
LogicalNode_addLogControlBlock(parent, self);
return self;
}
static void
LogicalNode_addReportControlBlock(LogicalNode* self, ReportControlBlock* rcb)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addReportControlBlock(model, rcb);
}
ReportControlBlock*
ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bool isBuffered, char*
dataSetName, uint32_t confRef, uint8_t trgOps, uint8_t options, uint32_t bufTm, uint32_t intgPd)
{
ReportControlBlock* self = (ReportControlBlock*) GLOBAL_MALLOC(sizeof(ReportControlBlock));
self->name = copyString(name);
self->parent = parent;
if (rptId)
self->rptId = copyString(rptId);
else
self->rptId = NULL;
self->buffered = isBuffered;
if (dataSetName)
self->dataSetName = copyString(dataSetName);
else
self->dataSetName = NULL;
self->confRef = confRef;
self->trgOps = trgOps;
self->options = options;
self->bufferTime = bufTm;
self->intPeriod = intgPd;
self->sibling = NULL;
LogicalNode_addReportControlBlock(parent, self);
return self;
}
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
static void
LogicalNode_addSettingGroupControlBlock(LogicalNode* self, SettingGroupControlBlock* sgcb)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addSettingGroupControlBlock(model, sgcb);
}
SettingGroupControlBlock*
SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numOfSGs)
{
assert(actSG <= numOfSGs); /* actSG starting with 1 */
assert(strcmp(parent->name, "LLN0") == 0);
SettingGroupControlBlock* self = (SettingGroupControlBlock*) GLOBAL_MALLOC(sizeof(SettingGroupControlBlock));
self->parent = parent;
self->actSG = actSG;
self->numOfSGs = numOfSGs;
self->sibling = NULL;
self->editSG = 0;
LogicalNode_addSettingGroupControlBlock(parent, self);
return self;
}
#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */
static void
LogicalNode_addGSEControlBlock(LogicalNode* self, GSEControlBlock* gcb)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addGSEControlBlock(model, gcb);
}
GSEControlBlock*
GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char* dataSet, uint32_t confRef, bool fixedOffs,
int minTime, int maxTime)
{
GSEControlBlock* self = (GSEControlBlock*) GLOBAL_MALLOC(sizeof(GSEControlBlock));
self->name = copyString(name);
self->parent = parent;
if (appId)
self->appId = copyString(appId);
else
self->appId = NULL;
if (dataSet)
self->dataSetName = copyString(dataSet);
else
self->dataSetName = NULL;
self->confRev = confRef;
self->fixedOffs = fixedOffs;
self->minTime = minTime;
self->maxTime = maxTime;
self->address = NULL;
self->sibling = NULL;
if (parent != NULL)
LogicalNode_addGSEControlBlock(parent, self);
return self;
}
SVControlBlock*
SVControlBlock_create(const char* name, LogicalNode* parent, char* svID, char* dataSet, uint32_t confRev, uint8_t smpMod,
uint16_t smpRate, uint8_t optFlds, bool isUnicast)
{
SVControlBlock* self = (SVControlBlock*) GLOBAL_MALLOC(sizeof(SVControlBlock));
self->name = copyString(name);
self->parent = parent;
self->svId = copyString(svID); /* Is there a default value? */
if (dataSet)
self->dataSetName = copyString(dataSet);
else
self->dataSetName = NULL;
self->confRev = confRev;
self->smpMod = smpMod;
self->smpRate = smpRate;
self->optFlds = optFlds;
self->isUnicast = isUnicast;
return self;
}
void
SVControlBlock_addPhyComAddress(SVControlBlock* self, PhyComAddress* phyComAddress)
{
self->dstAddress = phyComAddress;
}
void
GSEControlBlock_addPhyComAddress(GSEControlBlock* self, PhyComAddress* phyComAddress)
{
self->address = phyComAddress;
}
PhyComAddress*
PhyComAddress_create(uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[])
{
PhyComAddress* self = (PhyComAddress*) GLOBAL_MALLOC(sizeof(PhyComAddress));
self->vlanPriority = vlanPriority;
self->vlanId = vlanId;
self->appId = appId;
memcpy(self->dstAddress, dstAddress, 6);
return self;
}
static ModelNode*
DataObject_getLastChild(DataObject* self)
{
ModelNode* lastNode = self->firstChild;
ModelNode* nextNode = lastNode;
while (nextNode != NULL) {
lastNode = nextNode;
nextNode = (ModelNode*) nextNode->sibling;
}
return lastNode;
}
static void
DataObject_addChild(DataObject* self, ModelNode* child)
{
if (self->firstChild == NULL)
self->firstChild = child;
else {
ModelNode* lastChild = DataObject_getLastChild(self);
lastChild->sibling = child;
}
}
DataObject*
DataObject_create(const char* name, ModelNode* parent, int arrayElements)
{
DataObject* self = (DataObject*) GLOBAL_MALLOC(sizeof(DataObject));
self->name = copyString(name);
self->modelType = DataObjectModelType;
self->elementCount = arrayElements;
self->firstChild = NULL;
self->parent = parent;
self->sibling = NULL;
if (parent->modelType == LogicalNodeModelType)
LogicalNode_addDataObject((LogicalNode*) parent, self);
else if (parent->modelType == DataObjectModelType)
DataObject_addChild((DataObject*) parent, (ModelNode*) self);
return self;
}
static ModelNode*
DataAttribute_getLastChild(DataAttribute* self)
{
ModelNode* lastNode = self->firstChild;
ModelNode* nextNode = lastNode;
while (nextNode != NULL) {
lastNode = nextNode;
nextNode = (ModelNode*) nextNode->sibling;
}
return lastNode;
}
static void
DataAttribute_addChild(DataAttribute* self, ModelNode* child)
{
if (self->firstChild == NULL)
self->firstChild = child;
else {
ModelNode* lastChild = DataAttribute_getLastChild(self);
lastChild->sibling = child;
}
}
DataAttribute*
DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type, FunctionalConstraint fc,
uint8_t triggerOptions, int arrayElements, uint32_t sAddr)
{
DataAttribute* self = (DataAttribute*) GLOBAL_MALLOC(sizeof(DataAttribute));
self->name = copyString(name);
self->elementCount = arrayElements;
self->modelType = DataAttributeModelType;
self->type = type;
self->fc = fc;
self->firstChild = NULL;
self->mmsValue = NULL;
self->parent = parent;
self->sibling = NULL;
self->triggerOptions = triggerOptions;
self->sAddr = sAddr;
if (parent->modelType == DataObjectModelType)
DataObject_addChild((DataObject*) parent, (ModelNode*) self);
else if (parent->modelType == DataAttributeModelType)
DataAttribute_addChild((DataAttribute*) parent, (ModelNode*) self);
return self;
}
DataSet*
DataSet_create(const char* name, LogicalNode* parent)
{
DataSet* self = (DataSet*) GLOBAL_MALLOC(sizeof(DataSet));
LogicalDevice* ld = (LogicalDevice*) parent->parent;
self->name = createString(3, parent->name, "$", name);
self->elementCount = 0;
self->sibling = NULL;
self->logicalDeviceName = ld->name;
self->fcdas = NULL;
IedModel_addDataSet((IedModel*) ld->parent, self);
return self;
}
int
DataSet_getSize(DataSet* self)
{
return self->elementCount;
}
DataSetEntry*
DataSet_getFirstEntry(DataSet* self)
{
return self->fcdas;
}
DataSetEntry*
DataSetEntry_getNext(DataSetEntry* self)
{
return self->sibling;
}
static void
DataSet_addEntry(DataSet* self, DataSetEntry* newEntry)
{
self->elementCount++;
if (self->fcdas == NULL)
self->fcdas = newEntry;
else {
DataSetEntry* lastEntry = self->fcdas;
while (lastEntry != NULL) {
if (lastEntry->sibling == NULL) {
lastEntry->sibling = newEntry;
break;
}
lastEntry = lastEntry->sibling;
}
}
}
DataSetEntry*
DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const char* component)
{
DataSetEntry* self = (DataSetEntry*) GLOBAL_MALLOC(sizeof(DataSetEntry));
char variableName[130];
strncpy(variableName, variable, 129);
char* separator = strchr(variableName, '/');
if (separator != NULL) {
*separator = 0;
self->variableName = copyString(separator + 1);
self->logicalDeviceName = copyString(variableName);
self->isLDNameDynamicallyAllocated = true;
}
else {
self->variableName = copyString(variable);
self->logicalDeviceName = dataSet->logicalDeviceName;
self->isLDNameDynamicallyAllocated = false;
}
if (component != NULL)
self->componentName = copyString(component);
else
self->componentName = NULL;
self->index = index;
self->sibling = NULL;
DataSet_addEntry(dataSet, self);
return self;
}
static void
ModelNode_destroy(ModelNode* modelNode)
{
GLOBAL_FREEMEM(modelNode->name);
ModelNode* currentChild = modelNode->firstChild;
while (currentChild != NULL) {
ModelNode* nextChild = currentChild->sibling;
ModelNode_destroy(currentChild);
currentChild = nextChild;
}
if (modelNode->modelType == DataAttributeModelType) {
DataAttribute* dataAttribute = (DataAttribute*) modelNode;
if (dataAttribute->mmsValue != NULL) {
MmsValue_delete(dataAttribute->mmsValue);
dataAttribute->mmsValue = NULL;
}
}
GLOBAL_FREEMEM(modelNode);
}
void
IedModel_destroy(IedModel* model)
{
// delete all model nodes and dynamically created strings
/* delete all logical devices */
LogicalDevice* ld = model->firstChild;
while (ld != NULL) {
GLOBAL_FREEMEM (ld->name);
LogicalNode* ln = (LogicalNode*) ld->firstChild;
while (ln != NULL) {
GLOBAL_FREEMEM(ln->name);
/* delete all data objects */
DataObject* currentDataObject = (DataObject*) ln->firstChild;
while (currentDataObject != NULL) {
DataObject* nextDataObject = (DataObject*) currentDataObject->sibling;
ModelNode_destroy((ModelNode*) currentDataObject);
currentDataObject = nextDataObject;
}
LogicalNode* currentLn = ln;
ln = (LogicalNode*) ln->sibling;
GLOBAL_FREEMEM(currentLn);
}
LogicalDevice* currentLd = ld;
ld = (LogicalDevice*) ld->sibling;
GLOBAL_FREEMEM(currentLd);
}
/* delete all data sets */
DataSet* dataSet = model->dataSets;
while (dataSet != NULL) {
DataSet* nextDataSet = dataSet->sibling;
GLOBAL_FREEMEM(dataSet->name);
DataSetEntry* dse = dataSet->fcdas;
while (dse != NULL) {
DataSetEntry* nextDse = dse->sibling;
if (dse->componentName != NULL)
GLOBAL_FREEMEM(dse->componentName);
GLOBAL_FREEMEM(dse->variableName);
if (dse->isLDNameDynamicallyAllocated)
GLOBAL_FREEMEM(dse->logicalDeviceName);
GLOBAL_FREEMEM(dse);
dse = nextDse;
}
GLOBAL_FREEMEM(dataSet);
dataSet = nextDataSet;
}
/* delete all RCBs */
ReportControlBlock* rcb = model->rcbs;
while (rcb != NULL) {
ReportControlBlock* nextRcb = rcb->sibling;
GLOBAL_FREEMEM(rcb->name);
if (rcb->rptId)
GLOBAL_FREEMEM(rcb->rptId);
if (rcb->dataSetName)
GLOBAL_FREEMEM(rcb->dataSetName);
GLOBAL_FREEMEM(rcb);
rcb = nextRcb;
}
/* delete all GoCBs */
GSEControlBlock* gcb = model->gseCBs;
while (gcb != NULL) {
GSEControlBlock* nextGcb = gcb->sibling;
GLOBAL_FREEMEM(gcb->name);
GLOBAL_FREEMEM(gcb->appId);
GLOBAL_FREEMEM(gcb->dataSetName);
if (gcb->address)
GLOBAL_FREEMEM(gcb->address);
GLOBAL_FREEMEM(gcb);
gcb = nextGcb;
}
/* delete setting controls */
SettingGroupControlBlock* sgcb = model->sgcbs;
while (sgcb != NULL) {
SettingGroupControlBlock* nextSgcb = sgcb->sibling;
GLOBAL_FREEMEM(sgcb);
sgcb = nextSgcb;
}
/* delete all LCBs */
LogControlBlock* lcb = model->lcbs;
while (lcb != NULL) {
LogControlBlock* nextLcb = lcb->sibling;
if (lcb->name)
GLOBAL_FREEMEM(lcb->name);
if (lcb->dataSetName)
GLOBAL_FREEMEM(lcb->dataSetName);
if (lcb->logRef)
GLOBAL_FREEMEM(lcb->logRef);
GLOBAL_FREEMEM(lcb);
lcb = nextLcb;
}
/* delete all LOGs */
Log* log = model->logs;
while (log != NULL) {
Log* nextLog = log->sibling;
if (log->name)
GLOBAL_FREEMEM(log->name);
GLOBAL_FREEMEM(log);
log = nextLog;
}
/* delete generic model parts */
if (model->name)
GLOBAL_FREEMEM(model->name);
GLOBAL_FREEMEM(model);
}