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

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