- WIP: server side logging

pull/6/head
Michael Zillgith 9 years ago
parent a23b584d13
commit 7acd515a96

@ -30,6 +30,13 @@ typedef struct {
LogicalNode* parentLN;
LogStorage logStorage;
uint64_t newEntryId;
uint64_t newEntryTime;
uint64_t oldEntryId;
uint64_t oldEntryTime;
} LogInstance;
typedef struct {
@ -46,6 +53,11 @@ typedef struct {
MmsValue* mmsValue;
MmsVariableSpecification* mmsType;
MmsValue* oldEntr;
MmsValue* oldEntrTm;
MmsValue* newEntr;
MmsValue* newEntrTm;
LogInstance* logInstance;
bool enabled;
@ -58,6 +70,12 @@ typedef struct {
LogInstance*
LogInstance_create(LogicalNode* parentLN, const char* name);
void
LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage);
void
LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* value, uint8_t flag);
void
LogInstance_destroy(LogInstance* self);

@ -147,6 +147,9 @@ MmsMapping_setIedServer(MmsMapping* self, IedServer iedServer);
void
MmsMapping_setConnectionIndicationHandler(MmsMapping* self, IedConnectionIndicationHandler handler, void* parameter);
void
MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logStorage);
void
MmsMapping_installWriteAccessHandler(MmsMapping* self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter);

@ -41,11 +41,15 @@ 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->oldEntryId = 0;
self->oldEntryTime = 0;
self->newEntryId = 0;
self->newEntryTime = 0;
return self;
}
@ -56,6 +60,49 @@ LogInstance_destroy(LogInstance* self)
GLOBAL_FREEMEM(self);
}
void
LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* value, uint8_t flag)
{
LogStorage logStorage = self->logStorage;
if (logStorage != NULL) {
printf("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->newEntryId = entryID;
self->newEntryTime = timestamp;
}
else
printf("no log storage available!\n");
}
void
LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage)
{
self->logStorage = logStorage;
LogStorage_getOldestAndNewestEntries(logStorage, &(self->newEntryId), &(self->newEntryTime),
&(self->oldEntryId), &(self->oldEntryTime));
printf("Attached storage to log: %s\n", self->name);
printf(" oldEntryID: %llu oldEntryTm: %llu\n", self->oldEntryId, self->oldEntryTime);
printf(" newEntryID: %llu newEntryTm: %llu\n", self->newEntryId, self->newEntryTime);
}
LogControl*
LogControl_create(LogicalNode* parentLN, MmsMapping* mmsMapping)
{
@ -131,6 +178,20 @@ lookupLogControl(MmsMapping* self, MmsDomain* domain, char* lnName, char* object
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, &(logInstance->oldEntryId), 8);
MmsValue_setOctetString(self->newEntr, &(logInstance->newEntryId), 8);
}
}
MmsValue*
@ -138,6 +199,8 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain,
{
MmsValue* value = NULL;
printf("READ ACCESS LOG CB\n");
char variableId[130];
strncpy(variableId, variableIdOrig, 129);
@ -164,6 +227,9 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain,
LogControl* logControl = lookupLogControl(self, domain, lnName, objectName);
if (logControl != NULL) {
updateLogStatusInLCB(logControl);
if (varName != NULL) {
value = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName);
}
@ -210,7 +276,13 @@ createTrgOps(LogControlBlock* reportControlBlock) {
static bool
enableLogging(LogControl* logControl)
{
printf("enableLogging\n");
printf("Enable LCB %s...\n", logControl->name);
if (logControl->dataSetRef == NULL) {
printf(" no data set specified!\n");
return false;
}
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, logControl->dataSetRef);
if (dataSet == NULL) {
@ -220,11 +292,13 @@ enableLogging(LogControl* logControl)
else
logControl->dataSet = dataSet;
printf(" enabled\n");
return true;
}
static MmsVariableSpecification*
createLogControlBlock(LogControlBlock* logControlBlock,
createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
LogControl* logControl)
{
MmsVariableSpecification* lcb = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
@ -263,7 +337,14 @@ createLogControlBlock(LogControlBlock* logControlBlock,
lcb->typeSpec.structure.elements[1] = namedVariable;
if (logControlBlock->logRef != NULL) {
mmsValue->value.structure.components[1] = MmsValue_newVisibleString(logControlBlock->logRef);
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,
@ -303,6 +384,8 @@ createLogControlBlock(LogControlBlock* logControlBlock,
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");
@ -312,6 +395,8 @@ createLogControlBlock(LogControlBlock* logControlBlock,
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");
@ -322,6 +407,8 @@ createLogControlBlock(LogControlBlock* logControlBlock,
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");
@ -332,6 +419,8 @@ createLogControlBlock(LogControlBlock* logControlBlock,
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");
@ -426,9 +515,13 @@ getLogInstanceByLogRef(MmsMapping* self, const char* logRef)
return NULL;
}
#if 0
static LogInstance*
getLogInstance(MmsMapping* self, LogicalNode* logicalNode, const char* logName)
{
if (logName == NULL)
return NULL;
LinkedList logInstance = LinkedList_getNext(self->logInstances);
while (logInstance != NULL) {
@ -444,6 +537,7 @@ getLogInstance(MmsMapping* self, LogicalNode* logicalNode, const char* logName)
return NULL;
}
#endif
MmsVariableSpecification*
Logging_createLCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode,
@ -470,10 +564,13 @@ Logging_createLCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode
logControl->domain = domain;
namedVariable->typeSpec.structure.elements[currentLcb] =
createLogControlBlock(logControlBlock, logControl);
createLogControlBlock(self, logControlBlock, logControl);
//getLogInstanceByLogRef(self, logControlBlock->logRef);
logControl->logInstance = getLogInstance(self, logicalNode, logControlBlock->logRef);
//logControl->logInstance = getLogInstance(self, logicalNode, logControlBlock->logRef);
if (logControlBlock->logRef != NULL)
logControl->logInstance = getLogInstanceByLogRef(self, logControlBlock->logRef);
LinkedList_add(self->logControls, logControl);
@ -489,7 +586,7 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto
LogInstance* logInstance = getLogInstanceByLogRef(self, logRef);
if (logInstance != NULL)
logInstance->logStorage = logStorage;
LogInstance_setLogStorage(logInstance, logStorage);
//if (DEBUG_IED_SERVER)
if (logInstance == NULL)

@ -1116,13 +1116,25 @@ createMmsDomainFromIedDevice(MmsMapping* self, LogicalDevice* logicalDevice)
while (log != NULL) {
MmsDomain_addJournal(domain, log->name);
char journalName[65];
printf("log->name: %s\n", log->name);
int nameLength = strlen(log->parent->name) + strlen(log->name);
LogInstance* logInstance = LogInstance_create(log->parent, log->name);
if (nameLength > 63) {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Log name %s invalid! Resulting journal name too long! Skip log\n", log->name);
}
else {
strcpy(journalName, log->parent->name);
strcat(journalName, "$");
strcat(journalName, log->name);
LinkedList_add(self->logInstances, (void*) logInstance);
MmsDomain_addJournal(domain, journalName);
LogInstance* logInstance = LogInstance_create(log->parent, log->name);
LinkedList_add(self->logInstances, (void*) logInstance);
}
log = log->sibling;
}
@ -2586,7 +2598,7 @@ DataSet_isMemberValue(DataSet* dataSet, MmsValue* value, int* index)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
static bool
DataSet_isMemberValueWithRef(DataSet* dataSet, MmsValue* value, char* dataRef)
DataSet_isMemberValueWithRef(DataSet* dataSet, MmsValue* value, char* dataRef, const char* iedName)
{
int i = 0;
@ -2599,7 +2611,7 @@ DataSet_isMemberValueWithRef(DataSet* dataSet, MmsValue* value, char* dataRef)
if (dataSetValue != NULL) { /* prevent invalid data set members */
if (isMemberValueRecursive(dataSetValue, value)) {
if (dataRef != NULL)
sprintf(dataRef, "%s/%s", dataSetEntry->logicalDeviceName, dataSetEntry->variableName);
sprintf(dataRef, "%s%s/%s", iedName, dataSetEntry->logicalDeviceName, dataSetEntry->variableName);
return true;
}
@ -2695,30 +2707,13 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
char dataRef[130];
if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef)) {
printf("Log value - dataRef: %s flag: %i\n", dataRef, flag);
//TODO log to logInstance
if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef, self->model->name)) {
if (lc->logInstance != NULL) {
LogStorage logStorage = lc->logInstance->logStorage;
if (logStorage != NULL) {
uint64_t entryID = LogStorage_addEntry(logStorage, Hal_getTimeInMs());
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);
}
LogInstance_logSingleData(lc->logInstance, dataRef, value, flag);
}
else
printf("No log instance available!\n");
}

@ -58,6 +58,9 @@ struct sLogStorage {
bool (*getEntriesAfter) (LogStorage self, uint64_t startingTime, uint64_t entryID);
bool (*getOldestAndNewestEntries) (LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime,
uint64_t* oldEntry, uint64_t* oldEntryTime);
void (*destroy) (LogStorage self);
};
@ -78,6 +81,10 @@ LogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_t entr
void
LogStorage_setCallbacks(LogStorage self, LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* callbackParameter);
bool
LogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime,
uint64_t* oldEntry, uint64_t* oldEntryTime);
void
LogStorage_destroy(LogStorage self);

@ -91,6 +91,9 @@ MmsDomain_getName(MmsDomain* self);
void
MmsDomain_addJournal(MmsDomain* self, const char* name);
MmsJournal
MmsDomain_getJournal(MmsDomain* self, const char* name);
/**
* Delete a MmsDomain instance
*

@ -84,6 +84,24 @@ MmsDomain_addJournal(MmsDomain* self, const char* name)
LinkedList_add(self->journals, (void*) journal);
}
MmsJournal
MmsDomain_getJournal(MmsDomain* self, const char* name)
{
LinkedList journal = LinkedList_getNext(self->journals);
while (journal != NULL) {
MmsJournal mmsJournal = (MmsJournal) LinkedList_getData(journal);
if (strcmp(mmsJournal->name, name) == 0)
return mmsJournal;
journal = LinkedList_getNext(journal);
}
return NULL;
}
bool
MmsDomain_addNamedVariableList(MmsDomain* self, MmsNamedVariableList variableList)
{

@ -27,6 +27,90 @@
#if (MMS_JOURNAL_SERVICE == 1)
typedef struct sJournalVariable* JournalVariable;
struct sJournalVariable {
char* tag; /* UTF8(1..255) */
int tagSize;
uint8_t* data;
int dataSize;
JournalVariable next;
};
typedef struct {
uint8_t* entryID;
int entryIDSize;
uint64_t timestamp;
JournalVariable listOfVariables;
} JournalEntry;
struct sJournalEncoder {
uint8_t* buffer;
int maxSize;
int bufPos;
int currentEntryBufPos; /* store start buffer position of current entry in case the whole JournalEntry will become too long */
};
static bool
entryCallback(void* parameter, uint64_t timestamp, uint64_t entryID, bool moreFollow)
{
if (moreFollow)
printf("Found entry ID:%llu timestamp:%llu\n", entryID, timestamp);
return true;
}
static bool
entryDataCallback (void* parameter, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow)
{
if (moreFollow) {
printf(" EntryData: ref: %s\n", dataRef);
MmsValue* value = MmsValue_decodeMmsData(data, 0, dataSize);
char buffer[256];
MmsValue_printToBuffer(value, buffer, 256);
printf(" value: %s\n", buffer);
}
return true;
}
bool
MmsJournal_queryJournalByRange(MmsJournal self, uint64_t startTime, uint64_t endTime, ByteBuffer* response)
{
// forward request to implementation class
//TODO get handle of LogStorage
struct sJournalEncoder encoderData;
LogStorage logStorage;
LogStorage_setCallbacks(logStorage, entryCallback, entryDataCallback, &encoderData);
LogStorage_getEntries(logStorage, startTime, endTime);
/* actual encoding will happen in callback handler. When getEntries returns the data is
* already encoded in the buffer.
*/
// encoder header in response buffer
// move encoded JournalEntry data to continue the buffer header
}
static bool
parseStringWithMaxLength(char* filename, int maxLength, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response)
{
@ -268,6 +352,30 @@ mmsServer_handleReadJournalRequest(
}
//TODO check if required fields are present
//TODO check valid field combinations
/* lookup journal */
MmsServer server = connection->server;
MmsDevice* mmsDevice = MmsServer_getDevice(connection->server);
MmsDomain* mmsDomain = MmsDevice_getDomain(mmsDevice, domainId);
if (mmsDomain == NULL) {
printf("Domain %s not found\n", domainId);
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
return;
}
MmsJournal mmsJournal = MmsDomain_getJournal(mmsDomain, logName);
if (mmsJournal == NULL) {
printf("Journal %s not found\n", logName);
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
return;
}
printf("Read journal %s ...\n", mmsJournal->name);
}
#endif /* (MMS_JOURNAL_SERVICE == 1) */

@ -34,6 +34,7 @@ public class LogControl {
private String ldInst = null;
private String prefix = "";
private String lnClass = "LLN0";
private String lnInst = "";
private String logName;
private boolean logEna = true;
private boolean reasonCode = true;
@ -49,6 +50,10 @@ public class LogControl {
desc = ParserUtils.parseAttribute(logControlNode, "desc");
dataSet = ParserUtils.parseAttribute(logControlNode, "datSet");
if (dataSet != null)
if (dataSet.equals(""))
dataSet = null;
ldInst = ParserUtils.parseAttribute(logControlNode, "ldInst");
prefix = ParserUtils.parseAttribute(logControlNode, "prefix");
@ -57,11 +62,19 @@ public class LogControl {
if (lnClassString != null)
lnClass = lnClassString;
String lnInstString = ParserUtils.parseAttribute(logControlNode, "lnInst");
if (lnInstString != null)
lnInst = lnInstString;
logName = ParserUtils.parseAttribute(logControlNode, "logName");
if (logName == null)
throw new SclParserException(logControlNode, "LogControl is missing required attribute \"logName\"");
if (logName.equals(""))
logName = null;
String intgPdString = ParserUtils.parseAttribute(logControlNode, "intgPd");
if (intgPdString != null)

@ -321,7 +321,7 @@ public class StaticModelGenerator {
cOut.println(" (ModelNode*) &" + firstChildName);
cOut.println("};\n");
printLogicalNodeDefinitions(ldName, logicalDevice.getLogicalNodes());
printLogicalNodeDefinitions(ldName, logicalDevice, logicalDevice.getLogicalNodes());
}
@ -541,7 +541,7 @@ public class StaticModelGenerator {
}
}
private void printLogicalNodeDefinitions(String ldName, List<LogicalNode> logicalNodes) {
private void printLogicalNodeDefinitions(String ldName, LogicalDevice logicalDevice, List<LogicalNode> logicalNodes) {
for (int i = 0; i < logicalNodes.size(); i++) {
LogicalNode logicalNode = logicalNodes.get(i);
@ -568,7 +568,7 @@ public class StaticModelGenerator {
printReportControlBlocks(lnName, logicalNode);
printLogControlBlocks(lnName, logicalNode);
printLogControlBlocks(ldName, lnName, logicalNode, logicalDevice);
printLogs(lnName, logicalNode);
@ -1077,7 +1077,7 @@ public class StaticModelGenerator {
}
}
private void printLogControlBlocks(String lnPrefix, LogicalNode logicalNode)
private void printLogControlBlocks(String ldName, String lnPrefix, LogicalNode logicalNode, LogicalDevice logicalDevice)
{
List<LogControl> logControlBlocks = logicalNode.getLogControlBlocks();
@ -1086,7 +1086,7 @@ public class StaticModelGenerator {
int lcbNumber = 0;
for (LogControl lcb : logControlBlocks) {
printLogControlBlock(lnPrefix, lcb, lcbNumber, lcbCount);
printLogControlBlock(logicalDevice, lnPrefix, lcb, lcbNumber, lcbCount);
lcbNumber++;
}
}
@ -1157,7 +1157,7 @@ public class StaticModelGenerator {
this.logs.append(logString);
}
private void printLogControlBlock(String lnPrefix, LogControl lcb, int lcbNumber, int lcbCount)
private void printLogControlBlock(LogicalDevice logicalDevice, String lnPrefix, LogControl lcb, int lcbNumber, int lcbCount)
{
String lcbVariableName = lnPrefix + "_lcb" + lcbNumber;
@ -1172,8 +1172,21 @@ public class StaticModelGenerator {
else
lcbString += "NULL, ";
String logRef;
if (lcb.getLdInst() == null)
logRef = logicalDevice.getInst() + "/";
else
logRef = lcb.getLdInst() + "/";
if (lcb.getLnClass().equals("LLN0"))
logRef += "LLN0$";
else
logRef += lcb.getLnClass() + "$";
if (lcb.getLogName() != null)
lcbString += "\"" + lcb.getLogName() + "\", ";
lcbString += "\"" + logRef + lcb.getLogName() + "\", ";
else
lcbString += "NULL, ";

Loading…
Cancel
Save