- IEC 61850 server: optimized report buffer handling for buffered reporting (save memory and encoding time)

pull/147/head
Michael Zillgith 7 years ago
parent 719c174f81
commit e803003441

@ -1,7 +1,7 @@
/*
* reporting.h
*
* Copyright 2013, 2014 Michael Zillgith
* Copyright 2013-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -28,9 +28,9 @@ typedef struct sReportBufferEntry ReportBufferEntry;
struct sReportBufferEntry {
uint8_t entryId[8];
uint8_t flags; /* bit 0 (1 = isIntegrityReport), bit 1 (1 = isGiReport) */
uint64_t timeOfEntry;
int entryLength;
int entryLength:30;
unsigned int flags:2; /* bit 0 (1 = isIntegrityReport), bit 1 (1 = isGiReport) */
ReportBufferEntry* next;
};

@ -374,7 +374,7 @@ sendReportSegment(ReportControl* self, bool isIntegrity, bool isGI)
timeOfEntry.value.binaryTime.size = 6;
accessResultSize += MmsValue_encodeMmsData(rptId, NULL, 0, false);
accessResultSize += MmsValue_encodeMmsData(optFlds, NULL, 0, false); /* TODO optimize - this is constant */
accessResultSize += 5; /* size of OptFlds */
/* delete option fields for unrelated options (not present in unbuffered report) */
MmsValue_setBitStringBit(optFlds, 6, false); /* bufOvfl */
@ -2195,6 +2195,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
MmsValue* inclusionField = &inclusionFieldStatic;
int dataBlockSize = 0;
if (isIntegrity || isGI) {
DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas;
@ -2204,28 +2206,39 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
for (i = 0; i < inclusionBitStringSize; i++) {
assert(dataSetEntry != NULL);
bufferEntrySize += MemoryAllocator_getAlignedSize(1); /* reason-for-inclusion */
/* don't need reason for inclusion in GI or integrity report */
int encodedSize = MmsValue_encodeMmsData(dataSetEntry->value, NULL, 0, false);
bufferEntrySize += MmsValue_getSizeInMemory(dataSetEntry->value);
dataBlockSize += encodedSize;
dataSetEntry = dataSetEntry->sibling;
}
bufferEntrySize += MemoryAllocator_getAlignedSize(sizeof(int) + dataBlockSize); /* add aligned_size(LEN + DATA) */
}
else { /* other trigger reason */
bufferEntrySize += inclusionFieldSize;
int reasonForInclusionSize = 0;
int i;
for (i = 0; i < inclusionBitStringSize; i++) {
if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) {
bufferEntrySize += MemoryAllocator_getAlignedSize(1); /* reason-for-inclusion */
reasonForInclusionSize++;
assert(reportControl->bufferedDataSetValues[i] != NULL);
bufferEntrySize += MmsValue_getSizeInMemory(reportControl->bufferedDataSetValues[i]);
int encodedSize = MmsValue_encodeMmsData(reportControl->bufferedDataSetValues[i], NULL, 0, false);
dataBlockSize += encodedSize;
}
}
bufferEntrySize += MemoryAllocator_getAlignedSize(sizeof(int) + dataBlockSize + reasonForInclusionSize); /* add aligned_size (LEN + DATA + REASON) */
}
if (DEBUG_IED_SERVER)
@ -2442,49 +2455,64 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
else
entry->flags = 0;
entry->entryLength = MemoryAllocator_getAlignedSize(bufferEntrySize);
entry->entryLength = bufferEntrySize;
entryBufPos += MemoryAllocator_getAlignedSize(sizeof(ReportBufferEntry));
if (isIntegrity || isGI) {
DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas;
/* encode LEN */
memcpy(entryBufPos, (uint8_t*)(&dataBlockSize), sizeof(int));
entryBufPos += sizeof(int);
/* encode DATA */
int i;
for (i = 0; i < inclusionBitStringSize; i++) {
assert(dataSetEntry != NULL);
*entryBufPos = (uint8_t) reportControl->inclusionFlags[i];
entryBufPos += MemoryAllocator_getAlignedSize(1);
entryBufPos = MmsValue_cloneToBuffer(dataSetEntry->value, entryBufPos);
entryBufPos += MmsValue_encodeMmsData(dataSetEntry->value, entryBufPos, 0, true);
dataSetEntry = dataSetEntry->sibling;
}
}
else {
/* encode inclusion bit string */
inclusionFieldStatic.value.bitString.buf = entryBufPos;
memset(entryBufPos, 0, inclusionFieldSize);
entryBufPos += inclusionFieldSize;
/* encode LEN */
memcpy(entryBufPos, (uint8_t*)(&dataBlockSize), sizeof(int));
entryBufPos += sizeof(int);
/* encode DATA */
int i;
for (i = 0; i < inclusionBitStringSize; i++) {
if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) {
assert(reportControl->bufferedDataSetValues[i] != NULL);
/* update inclusion bit string for report entry */
MmsValue_setBitStringBit(inclusionField, i, true);
*entryBufPos = (uint8_t) reportControl->inclusionFlags[i];
entryBufPos += MemoryAllocator_getAlignedSize(1);
assert(reportControl->bufferedDataSetValues[i] != NULL);
entryBufPos = MmsValue_cloneToBuffer(reportControl->bufferedDataSetValues[i], entryBufPos);
entryBufPos += MmsValue_encodeMmsData(reportControl->bufferedDataSetValues[i], entryBufPos, 0, true);
}
MmsValue_setBitStringBit(inclusionField, i, true);
}
/* encode REASON */
for (i = 0; i < inclusionBitStringSize; i++) {
if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) {
*entryBufPos = (uint8_t) reportControl->inclusionFlags[i];
entryBufPos ++;
}
}
}
@ -2558,7 +2586,7 @@ sendNextReportEntrySegment(ReportControl* self)
MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds");
accessResultSize += MmsValue_encodeMmsData(rptId, NULL, 0, false);
accessResultSize += MmsValue_encodeMmsData(optFlds, NULL, 0, false); /* TODO optimize - this is constant */
accessResultSize += 5; /* add size of OptFlds */
MmsValue inclusionFieldStack;
@ -2579,6 +2607,12 @@ sendNextReportEntrySegment(ReportControl* self)
MmsValue_deleteAllBitStringBits(self->inclusionField);
int dataLen;
/* get LEN (length of encoded data) from report buffer */
memcpy((uint8_t*)(&dataLen), currentReportBufferPos, sizeof(int));
currentReportBufferPos += sizeof(int);
uint8_t* valuesInReportBuffer = currentReportBufferPos;
MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */
@ -2707,8 +2741,6 @@ sendNextReportEntrySegment(ReportControl* self)
dataReference[currentPos] = 0;
/* TODO optimize - 2 + string size ? */
MmsValue _dataRef;
_dataRef.type = MMS_VISIBLE_STRING;
_dataRef.value.visibleString.buf = dataReference;
@ -2717,12 +2749,16 @@ sendNextReportEntrySegment(ReportControl* self)
elementSize += MmsValue_encodeMmsData(&_dataRef, NULL, 0, false);
}
/* get size of data */
if ((report->flags > 0) || MmsValue_getBitStringBit(inclusionField, i)) {
currentReportBufferPos += MemoryAllocator_getAlignedSize(1);;
int length;
int lenSize = BerDecoder_decodeLength(currentReportBufferPos + 1, &length, 0, report->entryLength);
elementSize += MmsValue_encodeMmsData((MmsValue*) currentReportBufferPos, NULL, 0, false);
int dataElementSize = 1 + lenSize + length;
currentReportBufferPos += MmsValue_getSizeInMemory((MmsValue*) currentReportBufferPos);
elementSize += dataElementSize;
currentReportBufferPos += dataElementSize;
}
if (withReasonCode) {
@ -2888,24 +2924,28 @@ sendNextReportEntrySegment(ReportControl* self)
}
if (isInBuffer)
currentReportBufferPos += MemoryAllocator_getAlignedSize(1);
{
int length;
int lenSize = BerDecoder_decodeLength(currentReportBufferPos + 1, &length, 0, report->entryLength);
int dataElementSize = 1 + lenSize + length;
if (i >= startElementIndex) {
if ((report->flags > 0) || MmsValue_getBitStringBit(self->inclusionField, i)) {
/* encode value from report buffer entry*/
bufPos = MmsValue_encodeMmsData((MmsValue*) currentReportBufferPos, buffer, bufPos, true);
}
/* copy value from report entry to message buffer */
memcpy(buffer + bufPos, currentReportBufferPos, dataElementSize);
bufPos += dataElementSize;
}
if (isInBuffer)
currentReportBufferPos += MmsValue_getSizeInMemory((MmsValue*) currentReportBufferPos);
currentReportBufferPos += dataElementSize;
}
}
/* add reason code to report if requested */
if (withReasonCode) {
/* move to start position in report buffer */
currentReportBufferPos = valuesInReportBuffer;
currentReportBufferPos = valuesInReportBuffer + dataLen;
uint8_t bsBuf[1];
@ -2953,14 +2993,8 @@ sendNextReportEntrySegment(ReportControl* self)
if (i >= startElementIndex)
bufPos = MmsValue_encodeMmsData(&_reason, buffer, bufPos, true);
}
if ((report->flags > 0) || MmsValue_getBitStringBit(inclusionField, i)) {
currentReportBufferPos += MemoryAllocator_getAlignedSize(1);
MmsValue* dataSetElement = (MmsValue*) currentReportBufferPos;
currentReportBufferPos += MmsValue_getSizeInMemory(dataSetElement);
currentReportBufferPos++;
}
}
}

Loading…
Cancel
Save