diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 1ae85fb8..6190f013 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -3,7 +3,7 @@ * * IEC 61850 server API for libiec61850. * - * Copyright 2013-2019 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -51,6 +51,9 @@ struct sIedServerConfig /** size of the report buffer associated with a buffered report control block */ int reportBufferSize; + /** size of the report buffer associated with an unbuffered report control block */ + int reportBufferSizeURCBs; + /** Base path (directory where the file service serves files */ char* fileServiceBasepath; @@ -125,6 +128,22 @@ IedServerConfig_setReportBufferSize(IedServerConfig self, int reportBufferSize); LIB61850_API int IedServerConfig_getReportBufferSize(IedServerConfig self); +/** + * \brief Set the report buffer size for unbuffered reporting + * + * \param reportBufferSize the buffer size for each unbuffered report control block + */ +LIB61850_API void +IedServerConfig_setReportBufferSizeForURCBs(IedServerConfig self, int reportBufferSize); + +/** + * \brief Gets the report buffer size for unbuffered reporting + * + * \return the buffer size for each unbuffered report control block + */ +LIB61850_API int +IedServerConfig_getReportBufferSizeForURCBs(IedServerConfig self); + /** * \brief Set the maximum number of MMS (TCP) connections the server accepts * diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h index ce780b5a..55271c85 100644 --- a/src/iec61850/inc_private/ied_server_private.h +++ b/src/iec61850/inc_private/ied_server_private.h @@ -44,7 +44,8 @@ struct sIedServer uint8_t writeAccessPolicies; #if (CONFIG_IEC61850_REPORT_SERVICE == 1) - int reportBufferSize; + int reportBufferSizeBRCBs; + int reportBufferSizeURCBs; #endif #if (CONFIG_MMS_THREADLESS_STACK != 1) diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index 1b471a81..be5a1293 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -95,7 +95,6 @@ typedef struct { /* * the following members are only required for buffered RCBs * - * TODO move to ReportBuffer structure! */ bool isBuffering; /* true if buffered RCB is buffering (datSet is set to a valid value) */ @@ -146,6 +145,10 @@ Reporting_processReportEvents(MmsMapping* self, uint64_t currentTimeInMs); LIB61850_INTERNAL void Reporting_processReportEventsAfterUnlock(MmsMapping* self); +/* send reports in report buffer */ +LIB61850_INTERNAL void +Reporting_sendReports(MmsMapping* self, MmsServerConnection connection); + LIB61850_INTERNAL void Reporting_deactivateReportsForConnection(MmsMapping* self, MmsServerConnection connection); diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 58a2afd1..9d4bbd1f 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1,7 +1,7 @@ /* * ied_server.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -431,10 +431,14 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio #endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ #if (CONFIG_IEC61850_REPORT_SERVICE == 1) - if (serverConfiguration) - self->reportBufferSize = serverConfiguration->reportBufferSize; - else - self->reportBufferSize = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; + if (serverConfiguration) { + self->reportBufferSizeBRCBs = serverConfiguration->reportBufferSize; + self->reportBufferSizeURCBs = serverConfiguration->reportBufferSizeURCBs; + } + else { + self->reportBufferSizeBRCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; + self->reportBufferSizeURCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; + } #endif self->mmsMapping = MmsMapping_create(dataModel, self); diff --git a/src/iec61850/server/impl/ied_server_config.c b/src/iec61850/server/impl/ied_server_config.c index 00b8c39a..cd84bc22 100644 --- a/src/iec61850/server/impl/ied_server_config.c +++ b/src/iec61850/server/impl/ied_server_config.c @@ -1,7 +1,7 @@ /* * ied_server_config.c * - * Copyright 2018 Michael Zillgith + * Copyright 2018-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -43,6 +43,7 @@ IedServerConfig_create() if (self) { self->reportBufferSize = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; + self->reportBufferSizeURCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; self->fileServiceBasepath = StringUtils_copyString(CONFIG_VIRTUAL_FILESTORE_BASEPATH); self->enableFileService = true; self->enableDynamicDataSetService = true; @@ -88,6 +89,18 @@ IedServerConfig_getReportBufferSize(IedServerConfig self) return self->reportBufferSize; } +void +IedServerConfig_setReportBufferSizeForURCBs(IedServerConfig self, int reportBufferSize) +{ + self->reportBufferSizeURCBs = reportBufferSize; +} + +int +IedServerConfig_getReportBufferSizeForURCBs(IedServerConfig self) +{ + return self->reportBufferSizeURCBs; +} + void IedServerConfig_setFileServiceBasePath(IedServerConfig self, const char* basepath) { diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 99644625..811e0fe6 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -24,6 +24,7 @@ #include "libiec61850_platform_includes.h" #include "mms_mapping.h" #include "mms_mapping_internal.h" +#include "mms_server_internal.h" #include "stack_config.h" #include "mms_goose.h" @@ -2389,12 +2390,15 @@ unselectControlsForConnection(MmsMapping* self, MmsServerConnection connection) } #endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ -static void /* is called by MMS server layer */ +static void /* is called by MMS server layer and runs in the connection handling thread */ mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerEvent event) { MmsMapping* self = (MmsMapping*) parameter; - if (event == MMS_SERVER_CONNECTION_CLOSED) { + if (event == MMS_SERVER_CONNECTION_TICK) { + Reporting_sendReports(self, connection); + } + else if (event == MMS_SERVER_CONNECTION_CLOSED) { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); /* call user provided handler function */ diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 1742f315..b69c3eb3 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1,7 +1,7 @@ /* * reporting.c * - * Copyright 2013-2019 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -134,9 +134,7 @@ ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize, self->server = iedServer; - if (buffered) { - self->reportBuffer = ReportBuffer_create(reportBufferSize); - } + self->reportBuffer = ReportBuffer_create(reportBufferSize); return self; } @@ -343,397 +341,6 @@ getDataSetEntryWithIndex(DataSetEntry* dataSet, int index) return NULL; } -static bool -sendReportSegment(ReportControl* self, bool isIntegrity, bool isGI) -{ - if (self->clientConnection == NULL) - return false; - - IsoConnection_lock(self->clientConnection->isoConnection); - - int maxMmsPduSize = MmsServerConnection_getMaxMmsPduSize(self->clientConnection); - int estimatedSegmentSize = 19; /* maximum size of header information (header can have 13-19 byte) */ - estimatedSegmentSize += 8; /* reserve space for more-segments-follow (3 byte) and sub-seq-num (3-5 byte) */ - - bool segmented = self->segmented; - bool moreFollows = false; - - bool hasSeqNum = false; - bool hasReportTimestamp = false; - bool hasDataSetReference = false; - bool hasConfRev = false; - - uint32_t accessResultSize = 0; - - MmsValue* rptId = ReportControl_getRCBValue(self, "RptID"); - MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds"); - MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet"); - - MmsValue timeOfEntry; - timeOfEntry.type = MMS_BINARY_TIME; - timeOfEntry.value.binaryTime.size = 6; - - accessResultSize += MmsValue_encodeMmsData(rptId, NULL, 0, false); - accessResultSize += 5; /* size of OptFlds */ - - /* delete option fields for unrelated options (not present in unbuffered report) */ - MmsValue_setBitStringBit(optFlds, 6, false); /* bufOvfl */ - MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */ - - MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum"); - - if (MmsValue_getBitStringBit(optFlds, 1)) { /* sequence number */ - hasSeqNum = true; - accessResultSize += MmsValue_encodeMmsData(sqNum, NULL, 0, false); - } - - if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */ - hasReportTimestamp = true; - MmsValue_setBinaryTime(&timeOfEntry, self->segmentedReportTimestamp); - accessResultSize += MmsValue_encodeMmsData(&timeOfEntry, NULL, 0, false); - } - - if (MmsValue_getBitStringBit(optFlds, 4)) { /* data set reference */ - hasDataSetReference = true; - accessResultSize += MmsValue_encodeMmsData(datSet, NULL, 0, false); - } - - if (MmsValue_getBitStringBit(optFlds, 8)) { /* configuration revision */ - hasConfRev = true; - accessResultSize += MmsValue_encodeMmsData(self->confRev, NULL, 0, false); - } - - MmsValue_deleteAllBitStringBits(self->inclusionField); - accessResultSize += MmsValue_encodeMmsData(self->inclusionField, NULL, 0, false); - - /* here ends the base part that is equal for all sub reports and independent of the - * number of included data points - */ - estimatedSegmentSize += accessResultSize; - - int startElementIndex = self->startIndexForNextSegment; /* get value from segmented report control info */ - - bool withDataReference = MmsValue_getBitStringBit(optFlds, 5); - bool withReasonCode = MmsValue_getBitStringBit(optFlds, 3); - - LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent; - - IedModel* iedModel = (IedModel*) ld->parent; - - int maxIndex = startElementIndex; - - char* iedName = iedModel->name; - int iedNameLength = (int) strlen(iedName); - - int i; - - MmsValue _moreFollows; - _moreFollows.type = MMS_BOOLEAN; - _moreFollows.value.boolean = false; - - MmsValue* subSeqNum = self->subSeqVal; - - for (i = startElementIndex; i < self->dataSet->elementCount; i++) { - - DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, i); - - bool includeElementInReport = false; - - if (isGI || isIntegrity) - includeElementInReport = true; - else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) - includeElementInReport = true; - - if (includeElementInReport) { - - int elementSize = 0; - - if (withDataReference) { - int currentPos = 0; - - currentPos += iedNameLength; - currentPos += (int) strlen(dataSetEntry->logicalDeviceName); - currentPos++; - currentPos += (int) strlen(dataSetEntry->variableName); - - elementSize += (1 + BerEncoder_determineLengthSize(currentPos) + currentPos); - } - - if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { - elementSize += MmsValue_encodeMmsData(self->bufferedDataSetValues[i], NULL, 0, false); - } - else { - if (dataSetEntry->value) { - elementSize += MmsValue_encodeMmsData(dataSetEntry->value, NULL, 0, false); - } - else { - MmsValue _errVal; - _errVal.type = MMS_DATA_ACCESS_ERROR; - _errVal.value.dataAccessError = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; - - elementSize += MmsValue_encodeMmsData(&_errVal, NULL, 0, false); - } - } - - if (withReasonCode) { - elementSize += 4; /* reason code size is always 4 byte */ - } - - if ((estimatedSegmentSize + elementSize) > maxMmsPduSize) { - - segmented = true; - moreFollows = true; - _moreFollows.value.boolean = true; - - if (startElementIndex == 0) - MmsValue_setUint32(subSeqNum, 0); - - if (DEBUG_IED_SERVER) - printf("IED_SERVER: element doesn't fit into MMS PDU --> another report segment is required!\n"); - break; - } - - MmsValue_setBitStringBit(self->inclusionField, i, true); - - accessResultSize += elementSize; - estimatedSegmentSize += elementSize; - } - - maxIndex++; - } - - MmsValue_setBitStringBit(optFlds, 9, segmented); /* set segmentation flag */ - - /* now calculate the exact information report segment size */ - - if (segmented) { - int segmentedSize = MmsValue_encodeMmsData(&_moreFollows, NULL, 0, false) + MmsValue_encodeMmsData(subSeqNum, NULL, 0, false); - accessResultSize += segmentedSize; - } - - uint32_t variableAccessSpecSize = 7; /* T L "RPT" */ - uint32_t listOfAccessResultSize = accessResultSize + BerEncoder_determineLengthSize(accessResultSize) + 1; - uint32_t informationReportContentSize = variableAccessSpecSize + listOfAccessResultSize; - uint32_t informationReportSize = 1 + informationReportContentSize + BerEncoder_determineLengthSize(informationReportContentSize); - uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); - - if ((int) completeMessageSize > maxMmsPduSize) { - if (DEBUG_IED_SERVER) - printf("IED_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, maxMmsPduSize); - - goto exit_function; - } - - /* encode the report message */ - - ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server->mmsServer); - - uint8_t* buffer = reportBuffer->buffer; - int bufPos = 0; - - /* encode header */ - bufPos = BerEncoder_encodeTL(0xa3, informationReportSize, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0xa0, informationReportContentSize, buffer, bufPos); - - bufPos = BerEncoder_encodeTL(0xa1, 5, buffer, bufPos); - bufPos = BerEncoder_encodeStringWithTag(0x80, "RPT", buffer, bufPos); - - bufPos = BerEncoder_encodeTL(0xa0, accessResultSize, buffer, bufPos); - - /* encode access-results */ - - bufPos = MmsValue_encodeMmsData(rptId, buffer, bufPos, true); - bufPos = MmsValue_encodeMmsData(optFlds, buffer, bufPos, true); - - if (hasSeqNum) - bufPos = MmsValue_encodeMmsData(sqNum, buffer, bufPos, true); - - if (hasReportTimestamp) - bufPos = MmsValue_encodeMmsData(&timeOfEntry, buffer, bufPos, true); - - if (hasDataSetReference) - bufPos = MmsValue_encodeMmsData(datSet, buffer, bufPos, true); - - if (hasConfRev) - bufPos = MmsValue_encodeMmsData(self->confRev, buffer, bufPos, true); - - if (segmented) { - bufPos = MmsValue_encodeMmsData(subSeqNum, buffer, bufPos, true); - bufPos = MmsValue_encodeMmsData(&_moreFollows, buffer, bufPos, true); - } - - bufPos = MmsValue_encodeMmsData(self->inclusionField, buffer, bufPos, true); - - /* encode data references if selected */ - if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */ - DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, startElementIndex); - - for (i = startElementIndex; i < maxIndex; i++) { - assert(dataSetEntry->value != NULL); - - bool addReferenceForEntry = false; - - if (isGI || isIntegrity) - addReferenceForEntry = true; - else - if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) - addReferenceForEntry = true; - - if (addReferenceForEntry) { - - char dataReference[130]; - int currentPos = 0; - - int j; - - for (j = 0; j < iedNameLength; j++) { - dataReference[currentPos++] = iedName[j]; - } - - int ldNameLength = (int) strlen(dataSetEntry->logicalDeviceName); - for (j = 0; j < ldNameLength; j++) { - dataReference[currentPos] = dataSetEntry->logicalDeviceName[j]; - currentPos++; - } - - dataReference[currentPos++] = '/'; - - for (j = 0; j < (int) strlen(dataSetEntry->variableName); j++) { - dataReference[currentPos++] = dataSetEntry->variableName[j]; - } - - dataReference[currentPos] = 0; - - MmsValue _dataRef; - _dataRef.type = MMS_VISIBLE_STRING; - _dataRef.value.visibleString.buf = dataReference; - _dataRef.value.visibleString.size = currentPos; - - bufPos = MmsValue_encodeMmsData(&_dataRef, buffer, bufPos, true); - } - - dataSetEntry = dataSetEntry->sibling; - } - } - - /* encode data set value elements */ - DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, startElementIndex); - - for (i = startElementIndex; i < maxIndex; i++) { - - if (isGI || isIntegrity) { - /* encode value from data set */ - - if (dataSetEntry->value) { - bufPos = MmsValue_encodeMmsData(dataSetEntry->value, buffer, bufPos, true); - } - else { - MmsValue _errVal; - _errVal.type = MMS_DATA_ACCESS_ERROR; - _errVal.value.dataAccessError = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; - - bufPos = MmsValue_encodeMmsData(&_errVal, buffer, bufPos, true); - } - } - else { - if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { - /* encode value from the event buffer */ - bufPos = MmsValue_encodeMmsData(self->bufferedDataSetValues[i], buffer, bufPos, true); - } - } - - dataSetEntry = dataSetEntry->sibling; - } - - /* add reason code to report if requested */ - if (withReasonCode) { - - uint8_t bsBuf[1]; - - MmsValue _reason; - _reason.type = MMS_BIT_STRING; - _reason.value.bitString.size = 6; - _reason.value.bitString.buf = bsBuf; - - for (i = startElementIndex; i < maxIndex; i++) { - - if (isGI || isIntegrity) { - bsBuf[0] = 0; /* clear all bits */ - - if (isGI) - MmsValue_setBitStringBit(&_reason, 5, true); - - if (isIntegrity) - MmsValue_setBitStringBit(&_reason, 4, true); - - bufPos = MmsValue_encodeMmsData(&_reason, buffer, bufPos, true); - } - else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { - bsBuf[0] = 0; /* clear all bits */ - - if (self->inclusionFlags[i] == REPORT_CONTROL_QUALITY_CHANGED) - MmsValue_setBitStringBit(&_reason, 2, true); - else if (self->inclusionFlags[i] == REPORT_CONTROL_VALUE_CHANGED) - MmsValue_setBitStringBit(&_reason, 1, true); - else if (self->inclusionFlags[i] == REPORT_CONTROL_VALUE_UPDATE) - MmsValue_setBitStringBit(&_reason, 3, true); - - bufPos = MmsValue_encodeMmsData(&_reason, buffer, bufPos, true); - } - } - } - - /* clear inclusion flags */ - for (i = startElementIndex; i < maxIndex; i++) - self->inclusionFlags[i] = REPORT_CONTROL_NONE; - - reportBuffer->size = bufPos; - - MmsServerConnection_sendMessage(self->clientConnection, reportBuffer); - - MmsServer_releaseTransmitBuffer(self->server->mmsServer); - - IsoConnection_unlock(self->clientConnection->isoConnection); - - if (moreFollows == false) { - /* reset sub sequence number */ - segmented = false; - self->startIndexForNextSegment = 0; - } - else { - /* increase sub sequence number */ - uint32_t subSeqNumVal = MmsValue_toUint32(subSeqNum); - subSeqNumVal++; - MmsValue_setUint32(subSeqNum, subSeqNumVal); - - self->startIndexForNextSegment = maxIndex; - } - - if (segmented == false) { - /* Increase sequence number */ - self->sqNum++; - - /* Unbuffered reporting --> sqNum is 8 bit only!!! */ - if (self->sqNum == 256) - self->sqNum = 0; - - MmsValue_setUint16(sqNum, self->sqNum); - } - -exit_function: - self->segmented = segmented; - return moreFollows; -} - -static void -sendReport(ReportControl* self, bool isIntegrity, bool isGI, uint64_t currentTime) -{ - updateTimeOfEntry(self, currentTime); - self->segmentedReportTimestamp = currentTime; - - while (sendReportSegment(self, isIntegrity, isGI)); -} - static void createDataSetValuesShadowBuffer(ReportControl* rc) { @@ -1432,7 +1039,7 @@ Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain, int currentReport = 0; while (currentReport < reportsCount) { - ReportControl* rc = ReportControl_create(true, logicalNode, self->iedServer->reportBufferSize, self->iedServer); + ReportControl* rc = ReportControl_create(true, logicalNode, self->iedServer->reportBufferSizeBRCBs, self->iedServer); rc->domain = domain; @@ -1469,7 +1076,7 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain, int currentReport = 0; while (currentReport < reportsCount) { - ReportControl* rc = ReportControl_create(false, logicalNode, self->iedServer->reportBufferSize, self->iedServer); + ReportControl* rc = ReportControl_create(false, logicalNode, self->iedServer->reportBufferSizeURCBs, self->iedServer); rc->domain = domain; @@ -1833,7 +1440,8 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (rc->dataSet) clearInclusionFlags(rc); - rc->triggered = false; + /* clear report buffer */ + purgeBuf(rc); } rc->enabled = false; @@ -2108,6 +1716,9 @@ Reporting_deactivateReportsForConnection(MmsMapping* self, MmsServerConnection c if (rc->resvTms != -1) updateOwner(rc, NULL); + + /* delete buffer content */ + purgeBuf(rc); } else { if (rc->resvTms == 0) @@ -2227,6 +1838,9 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ reportControl->name, (unsigned) reportControl->sqNum, reportControl->enabled, reportControl->isBuffering, reportControl->buffered, isIntegrity, isGI); + bool isBuffered = reportControl->buffered; + bool overflow = false; + updateTimeOfEntry(reportControl, Hal_getTimeInMs()); int inclusionBitStringSize = MmsValue_getBitStringSize(reportControl->inclusionField); @@ -2312,13 +1926,16 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ goto exit_function; } - if (isGI) removeAllGIReportsFromReportBuffer(buffer); + if (isBuffered) { + /* remove old buffered GI reports */ + if (isGI) removeAllGIReportsFromReportBuffer(buffer); + } uint8_t* entryBufPos = NULL; uint8_t* entryStartPos; if (DEBUG_IED_SERVER) - printf("IED_SERVER: number of buffered reports:%i\n", buffer->reportsCount); + printf("IED_SERVER: number of reports in report buffer: %i\n", buffer->reportsCount); if (buffer->lastEnqueuedReport == NULL) { /* buffer is empty - we start at the beginning of the memory block */ entryBufPos = buffer->memoryBlock; @@ -2379,6 +1996,7 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (buffer->nextToTransmit == buffer->oldestReport) { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; + overflow = true; } #if (DEBUG_IED_SERVER == 1) @@ -2414,6 +2032,7 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (buffer->nextToTransmit == buffer->oldestReport) { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; + overflow = true; } #if (DEBUG_IED_SERVER == 1) @@ -2436,6 +2055,7 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (buffer->nextToTransmit == buffer->oldestReport) { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; + overflow = true; } #if (DEBUG_IED_SERVER == 1) @@ -2459,6 +2079,7 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (buffer->nextToTransmit == buffer->oldestReport) { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; + overflow = true; } #if (DEBUG_IED_SERVER == 1) @@ -2484,29 +2105,33 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ ReportBufferEntry* entry = (ReportBufferEntry*) entryBufPos; - /* ENTRY_ID is set to system time in ms! */ - uint64_t entryId = timeOfEntry; + if (isBuffered) { + /* ENTRY_ID is set to system time in ms! */ + uint64_t entryId = timeOfEntry; - if (entryId <= reportControl->lastEntryId) - entryId = reportControl->lastEntryId + 1; + if (entryId <= reportControl->lastEntryId) + entryId = reportControl->lastEntryId + 1; - entry->timeOfEntry = entryId; + entry->timeOfEntry = entryId; -#if (ORDER_LITTLE_ENDIAN == 1) - memcpyReverseByteOrder(entry->entryId, (uint8_t*) &entryId, 8); -#else - memcpy (entry->entryId, (uint8_t*) &entryId, 8); -#endif + #if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(entry->entryId, (uint8_t*) &entryId, 8); + #else + memcpy (entry->entryId, (uint8_t*) &entryId, 8); + #endif -#if (DEBUG_IED_SERVER == 1) - printf("IED_SERVER: ENCODE REPORT WITH ID: "); - printReportId(entry); - printf(" at pos %p\n", entryStartPos); -#endif + #if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: ENCODE REPORT WITH ID: "); + printReportId(entry); + printf(" at pos %p\n", entryStartPos); + #endif + + if (reportControl->enabled == false) { + MmsValue* entryIdValue = MmsValue_getElement(reportControl->rcbValues, 11); + MmsValue_setOctetString(entryIdValue, (uint8_t*) entry->entryId, 8); + } - if (reportControl->enabled == false) { - MmsValue* entryIdValue = MmsValue_getElement(reportControl->rcbValues, 11); - MmsValue_setOctetString(entryIdValue, (uint8_t*) entry->entryId, 8); + reportControl->lastEntryId = entryId; } if (isIntegrity) @@ -2600,10 +2225,12 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (buffer->oldestReport == NULL) buffer->oldestReport = buffer->lastEnqueuedReport; - reportControl->lastEntryId = entryId; - exit_function: + if (overflow) { + /* TODO call user callback handler */ + } + Semaphore_post(buffer->lock); return; @@ -2615,12 +2242,11 @@ sendNextReportEntrySegment(ReportControl* self) if (self->clientConnection == NULL) return false; - int maxMmsPduSize = MmsServerConnection_getMaxMmsPduSize(self->clientConnection); + bool isBuffered = self->buffered; - Semaphore_wait(self->reportBuffer->lock); + int maxMmsPduSize = MmsServerConnection_getMaxMmsPduSize(self->clientConnection); if (self->reportBuffer->nextToTransmit == NULL) { - Semaphore_post(self->reportBuffer->lock); return false; } @@ -2643,20 +2269,29 @@ sendNextReportEntrySegment(ReportControl* self) #if (DEBUG_IED_SERVER == 1) printf("IED_SERVER: SEND NEXT REPORT: "); - printReportId(report); + if (isBuffered) + printReportId(report); printf(" size: %i\n", report->entryLength); #endif - MmsValue* entryIdValue = MmsValue_getElement(self->rcbValues, 11); - MmsValue_setOctetString(entryIdValue, (uint8_t*) report->entryId, 8); + if (isBuffered) { + MmsValue* entryIdValue = MmsValue_getElement(self->rcbValues, 11); + MmsValue_setOctetString(entryIdValue, (uint8_t*) report->entryId, 8); + } MmsValue* rptId = ReportControl_getRCBValue(self, "RptID"); MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds"); + if (isBuffered == false) { + /* delete option fields for unrelated options (not present in unbuffered report) */ + MmsValue_setBitStringBit(optFlds, 6, false); /* bufOvfl */ + MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */ + } + accessResultSize += MmsValue_encodeMmsData(rptId, NULL, 0, false); accessResultSize += 5; /* add size of OptFlds */ - MmsValue inclusionFieldStack; + MmsValue _inclusionField; uint8_t* currentReportBufferPos = (uint8_t*) report + sizeof(ReportBufferEntry); @@ -2664,11 +2299,11 @@ sendNextReportEntrySegment(ReportControl* self) if (report->flags == 0) { - inclusionField = &inclusionFieldStack; + inclusionField = &_inclusionField; - inclusionFieldStack.type = MMS_BIT_STRING; - inclusionFieldStack.value.bitString.size = MmsValue_getBitStringSize(self->inclusionField); - inclusionFieldStack.value.bitString.buf = currentReportBufferPos; + _inclusionField.type = MMS_BIT_STRING; + _inclusionField.value.bitString.size = MmsValue_getBitStringSize(self->inclusionField); + _inclusionField.value.bitString.buf = currentReportBufferPos; currentReportBufferPos += MemoryAllocator_getAlignedSize(MmsValue_getBitStringByteSize(inclusionField)); } @@ -2716,30 +2351,34 @@ sendNextReportEntrySegment(ReportControl* self) MmsValue _bufOvfl; MmsValue* bufOvfl = NULL; - if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */ - hasBufOvfl = true; + if (isBuffered) { + if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */ + hasBufOvfl = true; - bufOvfl = &_bufOvfl; + bufOvfl = &_bufOvfl; - _bufOvfl.type = MMS_BOOLEAN; - _bufOvfl.value.boolean = self->reportBuffer->isOverflow; + _bufOvfl.type = MMS_BOOLEAN; + _bufOvfl.value.boolean = self->reportBuffer->isOverflow; - accessResultSize += MmsValue_encodeMmsData(bufOvfl, NULL, 0, false); + accessResultSize += MmsValue_encodeMmsData(bufOvfl, NULL, 0, false); + } } MmsValue _entryId; MmsValue* entryId = NULL; - if (MmsValue_getBitStringBit(optFlds, 7)) { /* entryID */ - hasEntryId = true; - entryId = &_entryId; + if (isBuffered) { + if (MmsValue_getBitStringBit(optFlds, 7)) { /* entryID */ + hasEntryId = true; + entryId = &_entryId; - entryId->type = MMS_OCTET_STRING; - entryId->value.octetString.buf = report->entryId; - entryId->value.octetString.size = 8; - entryId->value.octetString.maxSize = 8; + entryId->type = MMS_OCTET_STRING; + entryId->value.octetString.buf = report->entryId; + entryId->value.octetString.size = 8; + entryId->value.octetString.maxSize = 8; - accessResultSize += MmsValue_encodeMmsData(entryId, NULL, 0, false); + accessResultSize += MmsValue_encodeMmsData(entryId, NULL, 0, false); + } } if (MmsValue_getBitStringBit(optFlds, 8)) { @@ -2763,7 +2402,7 @@ sendNextReportEntrySegment(ReportControl* self) IedModel* iedModel = (IedModel*) ld->parent; - int maxIndex = startElementIndex; + int maxIndex = 0; char* iedName = iedModel->name; int iedNameLength = (int) strlen(iedName); @@ -2776,49 +2415,92 @@ sendNextReportEntrySegment(ReportControl* self) MmsValue* subSeqNum = self->subSeqVal; - for (i = startElementIndex; i < self->dataSet->elementCount; i++) { - - DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, i); + for (i = 0; i < self->dataSet->elementCount; i++) { if ((report->flags > 0) || MmsValue_getBitStringBit(inclusionField, i)) { int elementSize = 0; - if (withDataReference) { + if (i >= startElementIndex) { - char dataReference[130]; - int currentPos = 0; + if (withDataReference) { - int j; + DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, i); - for (j = 0; j < iedNameLength; j++) { - dataReference[currentPos++] = iedName[j]; + char dataReference[130]; + int currentPos = 0; + + int j; + + for (j = 0; j < iedNameLength; j++) { + dataReference[currentPos++] = iedName[j]; + } + + int ldNameLength = (int) strlen(dataSetEntry->logicalDeviceName); + for (j = 0; j < ldNameLength; j++) { + dataReference[currentPos] = dataSetEntry->logicalDeviceName[j]; + currentPos++; + } + + dataReference[currentPos++] = '/'; + + for (j = 0; j < (int) strlen(dataSetEntry->variableName); j++) { + dataReference[currentPos++] = dataSetEntry->variableName[j]; + } + + dataReference[currentPos] = 0; + + MmsValue _dataRef; + _dataRef.type = MMS_VISIBLE_STRING; + _dataRef.value.visibleString.buf = dataReference; + _dataRef.value.visibleString.size = currentPos; + + elementSize += MmsValue_encodeMmsData(&_dataRef, NULL, 0, false); } - int ldNameLength = (int) strlen(dataSetEntry->logicalDeviceName); - for (j = 0; j < ldNameLength; j++) { - dataReference[currentPos] = dataSetEntry->logicalDeviceName[j]; - currentPos++; + /* get size of data */ + { + int length; + + int lenSize = BerDecoder_decodeLength(currentReportBufferPos + 1, &length, 0, report->entryLength); + + if (lenSize < 0) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: internal error in report buffer\n"); + + return false; + } + + int dataElementSize = 1 + lenSize + length; + + elementSize += dataElementSize; + currentReportBufferPos += dataElementSize; } - dataReference[currentPos++] = '/'; - for (j = 0; j < (int) strlen(dataSetEntry->variableName); j++) { - dataReference[currentPos++] = dataSetEntry->variableName[j]; + if (withReasonCode) { + elementSize += 4; /* reason code size is always 4 byte */ } - dataReference[currentPos] = 0; + if ((estimatedSegmentSize + elementSize) > maxMmsPduSize) { - MmsValue _dataRef; - _dataRef.type = MMS_VISIBLE_STRING; - _dataRef.value.visibleString.buf = dataReference; - _dataRef.value.visibleString.size = currentPos; + segmented = true; + moreFollows = true; + _moreFollows.value.boolean = true; - elementSize += MmsValue_encodeMmsData(&_dataRef, NULL, 0, false); - } + if (startElementIndex == 0) + MmsValue_setUint32(subSeqNum, 0); + + break; + } + + MmsValue_setBitStringBit(self->inclusionField, i, true); - /* get size of data */ - if ((report->flags > 0) || MmsValue_getBitStringBit(inclusionField, i)) { + accessResultSize += elementSize; + estimatedSegmentSize += elementSize; + } + else { + /* move element pointer in report buffer to skip elements that were already sent in former segments */ int length; int lenSize = BerDecoder_decodeLength(currentReportBufferPos + 1, &length, 0, report->entryLength); @@ -2832,31 +2514,8 @@ sendNextReportEntrySegment(ReportControl* self) int dataElementSize = 1 + lenSize + length; - elementSize += dataElementSize; currentReportBufferPos += dataElementSize; } - - if (withReasonCode) { - elementSize += 4; /* reason code size is always 4 byte */ - } - - - if ((estimatedSegmentSize + elementSize) > maxMmsPduSize) { - - segmented = true; - moreFollows = true; - _moreFollows.value.boolean = true; - - if (startElementIndex == 0) - MmsValue_setUint32(subSeqNum, 0); - - break; - } - - MmsValue_setBitStringBit(self->inclusionField, i, true); - - accessResultSize += elementSize; - estimatedSegmentSize += elementSize; } maxIndex++; @@ -3119,6 +2778,12 @@ sendNextReportEntrySegment(ReportControl* self) /* Increase sequence number */ self->sqNum++; + if (isBuffered == false) { + /* Unbuffered reporting --> sqNum is 8 bit only!!! */ + if (self->sqNum == 256) + self->sqNum = 0; + } + MmsValue_setUint16(sqNum, self->sqNum); if (self->reportBuffer->isOverflow) @@ -3127,14 +2792,27 @@ sendNextReportEntrySegment(ReportControl* self) exit_function: self->segmented = segmented; - Semaphore_post(self->reportBuffer->lock); return moreFollows; } static void sendNextReportEntry(ReportControl* self) { - while (sendNextReportEntrySegment(self)); + Semaphore_wait(self->reportBuffer->lock); + + int messageCount = 0; + + while (self->reportBuffer->nextToTransmit) { + messageCount++; + while (sendNextReportEntrySegment(self)) { + messageCount++; + } + + if (messageCount > 100) + break; + } + + Semaphore_post(self->reportBuffer->lock); } void @@ -3164,19 +2842,11 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) /* send current events in event buffer before GI report */ if (rc->triggered) { - rc->triggered = false; - - if (rc->buffered) - enqueueReport(rc, false, false, currentTimeInMs); - else - sendReport(rc, false, false, currentTimeInMs); + enqueueReport(rc, false, false, currentTimeInMs); } - if (rc->buffered) - enqueueReport(rc, false, true, currentTimeInMs); - else - sendReport(rc, false, true, currentTimeInMs); + enqueueReport(rc, false, true, currentTimeInMs); rc->gi = false; @@ -3191,20 +2861,13 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) /* send current events in event buffer before integrity report */ if (rc->triggered) { - if (rc->buffered) - enqueueReport(rc, false, false, currentTimeInMs); - else - sendReport(rc, false, false, currentTimeInMs); - + enqueueReport(rc, false, false, currentTimeInMs); rc->triggered = false; } rc->nextIntgReportTime = currentTimeInMs + rc->intgPd; - if (rc->buffered) - enqueueReport(rc, true, false, currentTimeInMs); - else - sendReport(rc, true, false, currentTimeInMs); + enqueueReport(rc, true, false, currentTimeInMs); rc->triggered = false; } @@ -3214,20 +2877,12 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) if (rc->triggered) { if (currentTimeInMs >= rc->reportTime) { - if (rc->buffered) - enqueueReport(rc, false, false, currentTimeInMs); - else - sendReport(rc, false, false, currentTimeInMs); + enqueueReport(rc, false, false, currentTimeInMs); rc->triggered = false; } } - - if (rc->buffered && rc->enabled) - sendNextReportEntry(rc); } - - } void @@ -3249,6 +2904,32 @@ Reporting_processReportEvents(MmsMapping* self, uint64_t currentTimeInMs) } } +/* + * To be called only by connection thread! + */ +void +Reporting_sendReports(MmsMapping* self, MmsServerConnection connection) +{ + LinkedList element = LinkedList_getNext(self->reportControls); + + while (element) { + ReportControl* rc = (ReportControl*) LinkedList_getData(element); + + if (rc->clientConnection == connection) { + + ReportControl_lockNotify(rc); + + if (rc->enabled) { + sendNextReportEntry(rc); + } + + ReportControl_unlockNotify(rc); + } + + element = LinkedList_getNext(element); + } +} + static inline void copySingleValueToReportBuffer(ReportControl* self, int dataSetEntryIndex) { diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index af7df95a..6e9ee633 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -37,7 +37,9 @@ extern "C" { #include "iso_connection_parameters.h" typedef enum { - MMS_SERVER_NEW_CONNECTION, MMS_SERVER_CONNECTION_CLOSED + MMS_SERVER_NEW_CONNECTION, + MMS_SERVER_CONNECTION_CLOSED, + MMS_SERVER_CONNECTION_TICK } MmsServerEvent; typedef struct sMmsServer* MmsServer; diff --git a/src/mms/inc_private/iso_server.h b/src/mms/inc_private/iso_server.h index df89a0ed..e75cb30b 100644 --- a/src/mms/inc_private/iso_server.h +++ b/src/mms/inc_private/iso_server.h @@ -66,6 +66,9 @@ typedef void typedef void (*MessageReceivedHandler)(void* parameter, ByteBuffer* message, ByteBuffer* response); +typedef void +(*UserLayerTickHandler)(void* parameter); + LIB61850_INTERNAL char* IsoConnection_getPeerAddress(IsoConnection self); @@ -82,7 +85,8 @@ LIB61850_INTERNAL void IsoConnection_unlock(IsoConnection self); LIB61850_INTERNAL void -IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler, +IsoConnection_installListener(IsoConnection self, MessageReceivedHandler rcvdHandler, + UserLayerTickHandler tickHandler, void* parameter); LIB61850_INTERNAL void* diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 4aa6f494..085614f3 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -219,6 +219,9 @@ MmsServer_reserveTransmitBuffer(MmsServer self); LIB61850_INTERNAL void MmsServer_releaseTransmitBuffer(MmsServer self); +LIB61850_INTERNAL void +MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection); + /* write_out function required for ASN.1 encoding */ LIB61850_INTERNAL int mmsServer_write_out(const void *buffer, size_t size, void *app_key); diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index 0bf12e07..0cdd5da2 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -1401,7 +1401,7 @@ connectionHandlingThread(void* parameter) while (self->connectionThreadRunning) { if (MmsConnection_tick(self)) - Thread_sleep(10); + Thread_sleep(1); } return NULL; diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c index 4e965060..e73eb271 100644 --- a/src/mms/iso_mms/server/mms_file_service.c +++ b/src/mms/iso_mms/server/mms_file_service.c @@ -516,7 +516,6 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task) { /* send ObtainFileError */ - IsoConnection_lock(task->connection->isoConnection); ByteBuffer* response = MmsServer_reserveTransmitBuffer(self); @@ -545,7 +544,6 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task) case MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_DESTINATION: { /* send ObtainFileError */ - IsoConnection_lock(task->connection->isoConnection); ByteBuffer* response = MmsServer_reserveTransmitBuffer(self); diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index b21499af..792381a0 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -504,6 +504,14 @@ MmsServer_handleBackgroundTasks(MmsServer self) #endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */ } +void +MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection) +{ + if (self->connectionHandler) { + self->connectionHandler(self->connectionHandlerParameter, connection, MMS_SERVER_CONNECTION_TICK); + } +} + void MmsServer_stopListeningThreadless(MmsServer self) { diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c index 8c746bf2..2db82867 100644 --- a/src/mms/iso_mms/server/mms_server_connection.c +++ b/src/mms/iso_mms/server/mms_server_connection.c @@ -696,7 +696,7 @@ MmsServerConnection_parseMessage(MmsServerConnection self, ByteBuffer* message, return; } -static void /* will be called by IsoConnection */ +static void /* is called by IsoConnection */ messageReceived(void* parameter, ByteBuffer* message, ByteBuffer* response) { MmsServerConnection self = (MmsServerConnection) parameter; @@ -704,6 +704,14 @@ messageReceived(void* parameter, ByteBuffer* message, ByteBuffer* response) MmsServerConnection_parseMessage(self, message, response); } +static void /* is called by IsoConnection */ +connectionTickHandler(void* parameter) +{ + MmsServerConnection self = (MmsServerConnection) parameter; + + MmsServer_callConnectionHandler(self->server, self); +} + /********************************************************************************************** * MMS server connection public API functions *********************************************************************************************/ @@ -733,7 +741,9 @@ MmsServerConnection_init(MmsServerConnection connection, MmsServer server, IsoCo self->lastRequestInvokeId = 0; #endif - IsoConnection_installListener(isoCon, messageReceived, (void*) self); + IsoConnection_installListener(isoCon, messageReceived, + (UserLayerTickHandler) connectionTickHandler, + (void*) self); return self; } diff --git a/src/mms/iso_server/iso_connection.c b/src/mms/iso_server/iso_connection.c index 6173ce72..cc91823f 100644 --- a/src/mms/iso_server/iso_connection.c +++ b/src/mms/iso_server/iso_connection.c @@ -64,7 +64,8 @@ struct sIsoConnection ByteBuffer cotpWriteBuffer; MessageReceivedHandler msgRcvdHandler; - void* msgRcvdHandlerParameter; + UserLayerTickHandler tickHandler; + void* handlerParameter; /* context parameter for msgRcvdHandler */ IsoServer isoServer; @@ -141,6 +142,11 @@ IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles) void IsoConnection_handleTcpConnection(IsoConnection self) { + /* call tick handler */ + if (self->tickHandler) { + self->tickHandler(self->handlerParameter); + } + #if (CONFIG_MMS_SINGLE_THREADED == 0) if (IsoServer_waitReady(self->isoServer, 10) < 1) goto exit_function; @@ -217,7 +223,7 @@ IsoConnection_handleTcpConnection(IsoConnection self) ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); if (self->msgRcvdHandler != NULL) { - self->msgRcvdHandler(self->msgRcvdHandlerParameter, + self->msgRcvdHandler(self->handlerParameter, &mmsRequest, &mmsResponseBuffer); } @@ -304,7 +310,7 @@ IsoConnection_handleTcpConnection(IsoConnection self) if (self->msgRcvdHandler != NULL) { - self->msgRcvdHandler(self->msgRcvdHandlerParameter, + self->msgRcvdHandler(self->handlerParameter, mmsRequest, &mmsResponseBuffer); } @@ -470,7 +476,8 @@ IsoConnection_create(Socket socket, IsoServer isoServer) self->receiveBuffer = (uint8_t*) GLOBAL_MALLOC(RECEIVE_BUF_SIZE); self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(SEND_BUF_SIZE); self->msgRcvdHandler = NULL; - self->msgRcvdHandlerParameter = NULL; + self->tickHandler = NULL; + self->handlerParameter = NULL; self->isoServer = isoServer; self->state = ISO_CON_STATE_RUNNING; self->clientAddress = Socket_getPeerAddress(self->socket); @@ -637,11 +644,13 @@ IsoConnection_close(IsoConnection self) } void -IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler, +IsoConnection_installListener(IsoConnection self, MessageReceivedHandler rcvdHandler, + UserLayerTickHandler tickHandler, void* parameter) { - self->msgRcvdHandler = handler; - self->msgRcvdHandlerParameter = parameter; + self->msgRcvdHandler = rcvdHandler; + self->tickHandler = tickHandler; + self->handlerParameter = parameter; } void*