diff --git a/demos/beaglebone/beagle_demo.icd b/demos/beaglebone/beagle_demo.icd index 259c21f5..df06bd57 100644 --- a/demos/beaglebone/beagle_demo.icd +++ b/demos/beaglebone/beagle_demo.icd @@ -1,24 +1,9 @@ - -
+ +
- - - Station bus - 10 - -
-

10.0.0.2

-

255.255.255.0

-

10.0.0.1

-

0001

-

00000001

-

0001

-
-
-
-
- + + @@ -30,17 +15,13 @@ - - + + - - - - @@ -63,22 +44,12 @@ - - - status-only - - - - - - status-only - - + direct-with-normal-security @@ -86,7 +57,7 @@ - sbo-with-normal-security + direct-with-normal-security @@ -96,7 +67,7 @@ - direct-with-enhanced-security + direct-with-normal-security @@ -112,20 +83,20 @@ - + - + - + @@ -167,16 +138,22 @@ + + + + + + - - + + direct-with-normal-security - + @@ -194,7 +171,7 @@ - + status-only @@ -233,31 +210,25 @@ - - - - - - + - - + - + - + @@ -265,15 +236,7 @@ - - - - - - - - - + @@ -286,15 +249,6 @@ - - - - - - - - - @@ -305,12 +259,21 @@ - + + + + + + + + + + on @@ -320,6 +283,12 @@ off + + Ok + Warning + Alarm + + unknown forward @@ -330,9 +299,6 @@ status-only direct-with-normal-security - sbo-with-normal-security - direct-with-enhanced-security - sbo-with-enhanced-security diff --git a/demos/beaglebone/static_model.c b/demos/beaglebone/static_model.c index 83951899..1010b5c6 100644 --- a/demos/beaglebone/static_model.c +++ b/demos/beaglebone/static_model.c @@ -1114,7 +1114,7 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_SBO = { NULL, 0, IEC61850_FC_CO, - IEC61850_VISIBLE_STRING_64, + IEC61850_VISIBLE_STRING_129, 0, NULL, 0}; @@ -2404,6 +2404,8 @@ ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, + + IedModel iedModel = { "beagle", &iedModel_GenericIO, @@ -2412,6 +2414,8 @@ IedModel iedModel = { NULL, NULL, NULL, + NULL, + NULL, initializeValues }; @@ -2425,11 +2429,11 @@ iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0) iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); -iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(2); +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); -iedModel_GenericIO_GGIO1_DPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); +iedModel_GenericIO_GGIO1_DPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); iedModel_GenericIO_TIM_GAPC1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); diff --git a/examples/mms_utility/mms_utility.c b/examples/mms_utility/mms_utility.c index 3e22b242..3a5c8b67 100644 --- a/examples/mms_utility/mms_utility.c +++ b/examples/mms_utility/mms_utility.c @@ -172,11 +172,11 @@ int main(int argc, char** argv) { printf(" read journal...\n"); // MmsConnection_readJournal(con, &error, domainName, name); -#if 0 +#if 1 uint64_t timestamp = Hal_getTimeInMs(); MmsValue* startTime = MmsValue_newBinaryTime(false); - MmsValue_setBinaryTime(startTime, timestamp - 60000); + MmsValue_setBinaryTime(startTime, timestamp - 6000000000); MmsValue* endTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(endTime, timestamp); @@ -184,7 +184,7 @@ int main(int argc, char** argv) { MmsConnection_readJournalTimeRange(con, &error, domainName, name, startTime, endTime); #endif -#if 1 +#if 0 uint64_t timestamp = Hal_getTimeInMs(); MmsValue* startTime = MmsValue_newBinaryTime(false); diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index 905e0978..e6516bbc 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -89,6 +89,7 @@ LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* valu printf("no log storage available!\n"); } + void LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage) { @@ -100,7 +101,6 @@ LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage) 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* @@ -585,9 +585,51 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto { LogInstance* logInstance = getLogInstanceByLogRef(self, logRef); - if (logInstance != NULL) + if (logInstance != NULL) { LogInstance_setLogStorage(logInstance, logStorage); +#if 1 + char domainName[65]; + + MmsMapping_getMmsDomainFromObjectReference(logRef, domainName); + + char domainName2[65]; + + strcpy(domainName2, self->model->name); + strcat(domainName2, domainName); + + MmsDomain* mmsDomain = MmsDevice_getDomain(self->mmsDevice, domainName2); + + if (mmsDomain == NULL) { + printf("IED_SERVER: MmsMapping_setLogStorage: domain %s not found!\n", domainName2); + } +#if 0 + char journalName[65]; + + strcpy(journalName, self->parentLN->name); + strcat(journalName, "$"); + strcat(journalName, self->name); +#endif + + printf("Connect LogStorage to MMS journal %s\n", logRef); + + MmsJournal mmsJournal = NULL; + + char* logName = strchr(logRef, '/'); + + if (logName != NULL) { + logName += 1; + mmsJournal = MmsDomain_getJournal(mmsDomain, logName); + } + + if (mmsJournal != NULL) + mmsJournal->logStorage = logStorage; + else + printf("Failed to retrieve MMS journal for log!\n"); +#endif + + } + //if (DEBUG_IED_SERVER) if (logInstance == NULL) printf("IED_SERVER: MmsMapping_setLogStorage no matching log for %s found!\n", logRef); diff --git a/src/logging/logging_api.h b/src/logging/logging_api.h index 0f3b36fd..078b9bb7 100644 --- a/src/logging/logging_api.h +++ b/src/logging/logging_api.h @@ -43,20 +43,15 @@ struct sLogStorage { void* instanceData; - LogEntryCallback entryCallback; - LogEntryDataCallback entryDataCallback; - - void* callbackParameter; - - // bool (*initializeLog) (const char* logName, int logSize); - uint64_t (*addEntry) (LogStorage self, uint64_t timestamp); bool (*addEntryData) (LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode); - bool (*getEntries) (LogStorage self, uint64_t startingTime, uint64_t endingTime); + bool (*getEntries) (LogStorage self, uint64_t startingTime, uint64_t endingTime, + LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); - bool (*getEntriesAfter) (LogStorage self, uint64_t startingTime, uint64_t entryID); + bool (*getEntriesAfter) (LogStorage self, uint64_t startingTime, uint64_t entryID, + LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); bool (*getOldestAndNewestEntries) (LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime, uint64_t* oldEntry, uint64_t* oldEntryTime); @@ -73,13 +68,12 @@ bool LogStorage_addEntryData(LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode); bool -LogStorage_getEntries(LogStorage self, uint64_t startingTime, uint64_t endingTime); +LogStorage_getEntries(LogStorage self, uint64_t startingTime, uint64_t endingTime, + LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); bool -LogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_t entryID); - -void -LogStorage_setCallbacks(LogStorage self, LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* callbackParameter); +LogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_t entryID, + LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); bool LogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime, diff --git a/src/mms/inc/mms_device_model.h b/src/mms/inc/mms_device_model.h index 404b8c8a..f4c9be1d 100644 --- a/src/mms/inc/mms_device_model.h +++ b/src/mms/inc/mms_device_model.h @@ -29,6 +29,7 @@ #include "mms_type_spec.h" #include "mms_common.h" #include "mms_named_variable_list.h" +#include "logging_api.h" #ifdef __cplusplus extern "C" { @@ -52,6 +53,7 @@ typedef struct { struct sMmsJournal { char* name; + LogStorage logStorage; }; typedef struct sMmsJournal* MmsJournal; diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index 930ed6fc..997415dc 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -1652,8 +1652,10 @@ readJournal(MmsConnection self, MmsError* mmsError, uint32_t invokeId, ByteBuff if (self->lastResponseError != MMS_ERROR_NONE) *mmsError = self->lastResponseError; else if (responseMessage != NULL) { - // if (mmsClient_parseFileOpenResponse(self, &frsmId, fileSize, lastModified) == false) - // *mmsError = MMS_ERROR_PARSING_RESPONSE; + bool moreFollows; + + if (mmsClient_parseReadJournalResponse(self, &moreFollows) == false) + *mmsError = MMS_ERROR_PARSING_RESPONSE; } releaseResponse(self); diff --git a/src/mms/iso_mms/client/mms_client_journals.c b/src/mms/iso_mms/client/mms_client_journals.c index 0099f416..ba431140 100644 --- a/src/mms/iso_mms/client/mms_client_journals.c +++ b/src/mms/iso_mms/client/mms_client_journals.c @@ -33,6 +33,364 @@ #include "conversions.h" #include "mms_value_internal.h" +typedef struct sMmsJournalEntry* MmsJournalEntry; + +typedef struct sMmsJournalVariable* MmsJournalVariable; + +struct sMmsJournalEntry { + MmsValue* entryID; /* type MMS_OCTET_STRING */ + MmsValue* occurenceTime; /* type MMS_BINARY_TIME */ + LinkedList journalVariables; +}; + +struct sMmsJournalVariable { + char* tag; + MmsValue* value; +}; + +//TODO add event-based API to parse journal entries + +static bool +parseJournalVariable(uint8_t* buffer, int bufPos, int maxLength, MmsJournalVariable journalVariable) +{ + int maxBufPos = bufPos + maxLength; + + while (bufPos < maxBufPos) { + + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if ((bufPos + length) > maxBufPos) { /* check length field for validity */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + + return false; + } + + switch (tag) { + case 0x80: /* variableTag */ + + if (journalVariable->tag == NULL) { + journalVariable->tag = (char*) GLOBAL_MALLOC(length + 1); + memcpy(journalVariable->tag, buffer + bufPos, length); + journalVariable->tag[length] = 0; + + printf(" tag: %s\n", journalVariable->tag); + } + + break; + + case 0xa1: /* valueSpec */ + + if (journalVariable->value == NULL) { + journalVariable->value = MmsValue_decodeMmsData(buffer, bufPos, length); + } + + break; + + default: + break; + + } + + bufPos += length; + } + + return true; +} + +static bool +parseJournalVariables(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEntry) +{ + int maxBufPos = bufPos + maxLength; + + while (bufPos < maxBufPos) { + + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if ((bufPos + length) > maxBufPos) { /* check length field for validity */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + + return false; + } + + MmsJournalVariable journalVariable; + + switch (tag) { + case 0x30: /* journalVariable */ + + journalVariable = (MmsJournalVariable) + GLOBAL_CALLOC(1, sizeof(struct sMmsJournalVariable)); + + parseJournalVariable(buffer, bufPos, length, journalVariable); + + LinkedList_add(journalEntry->journalVariables, (void*) journalVariable); + + break; + + default: + break; + + } + + bufPos += length; + } + + return true; +} + +static bool +parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEntry) +{ + int maxBufPos = bufPos + maxLength; + + while (bufPos < maxBufPos) { + + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if ((bufPos + length) > maxBufPos) { /* check length field for validity */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + + return false; + } + + switch (tag) { + case 0xa1: /* journalVariables */ + + journalEntry->journalVariables = LinkedList_create(); + + parseJournalVariables(buffer, bufPos, length, journalEntry); + + break; + + default: + break; + + } + + bufPos += length; + } + + return true; +} + +static bool +parseEntryContent(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEntry) +{ + int maxBufPos = bufPos + maxLength; + + while (bufPos < maxBufPos) { + + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if ((bufPos + length) > maxBufPos) { /* check length field for validity */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + + return false; + } + + switch (tag) { + case 0x80: /* occurenceTime */ + printf(" parse occurenceTime\n"); + + if (length == 6) + journalEntry->occurenceTime = MmsValue_newBinaryTime(false); + else if (length == 4) + journalEntry->occurenceTime = MmsValue_newBinaryTime(true); + else + break; + + memcpy(journalEntry->occurenceTime->value.binaryTime.buf, buffer + bufPos, length); + + break; + + case 0xa2: /* data */ + + parseData(buffer, bufPos, length, journalEntry); + + break; + + default: + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: ignore unknown tag %02x\n", tag); + break; + } + + bufPos += length; + } + + return true; +} + +static bool +parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journalEntries) +{ + int maxBufPos = bufPos + maxLength; + + MmsJournalEntry journalEntry = (MmsJournalEntry) GLOBAL_CALLOC(1, sizeof(struct sMmsJournalEntry)); + LinkedList_add(journalEntries, (void*) journalEntry); + + while (bufPos < maxBufPos) { + + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if ((bufPos + length) > maxBufPos) { /* check length field for validity */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + + return false; + } + + switch (tag) { + + case 0x80: /* entryID */ + journalEntry->entryID = MmsValue_newOctetString(length, length); + MmsValue_setOctetString(journalEntry->entryID, buffer + bufPos, length); + break; + + case 0xa1: /* originatingApplication */ + /* ignore */ + break; + + case 0xa2: /* entryContent */ + if (parseEntryContent(buffer, bufPos, length, journalEntry) == false) + return false; + + break; + + default: + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: unknown tag %02x\n", tag); + + return false; + } + + bufPos += length; + } + + return true; +} + +static bool +parseListOfJournalEntries(uint8_t* buffer, int bufPos, int maxLength, LinkedList journalEntries) +{ + int maxBufPos = bufPos + maxLength; + + + while (bufPos < maxBufPos) { + + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if ((bufPos + length) > maxBufPos) { /* check length field for validity */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + + return false; + } + + switch (tag) { + case 0x30: + printf("Parse journalEntry\n"); + if (parseJournalEntry(buffer, bufPos, length, journalEntries) == false) + return false; + break; + + default: + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: unknown tag %02x\n", tag); + + return false; + } + + bufPos += length; + } + + return true; +} + +bool +mmsClient_parseReadJournalResponse(MmsConnection self, bool* moreFollows) +{ + uint8_t* buffer = self->lastResponse->buffer; + int maxBufPos = self->lastResponse->size; + int bufPos = self->lastResponseBufPos; + int length; + + uint8_t tag = buffer[bufPos++]; + + if (tag != 0xbf) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: unknown tag %02x\n", tag); + return false; + } + + tag = buffer[bufPos++]; + + *moreFollows = false; + + if (tag != 0x41) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: unknown tag %02x\n", tag); + return false; + } + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) + return false; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos); + return false; + } + + LinkedList journalEntries = NULL; + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0xa0: /* listOfJournalEntry */ + journalEntries = LinkedList_create(); + + if (!parseListOfJournalEntries(buffer, bufPos, length, journalEntries)) + return false; + break; + + case 0x81: /* moreFollows */ + *moreFollows = BerDecoder_decodeBoolean(buffer, bufPos); + break; + + default: + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: message contains unknown tag %02x!\n", tag); + + return false; + } + + bufPos += length; + } + + return true; +} + void mmsClient_createReadJournalRequest(uint32_t invokeId, ByteBuffer* request, const char* domainId, const char* itemId) { diff --git a/src/mms/iso_mms/server/mms_domain.c b/src/mms/iso_mms/server/mms_domain.c index f8db8aed..ca54284b 100644 --- a/src/mms/iso_mms/server/mms_domain.c +++ b/src/mms/iso_mms/server/mms_domain.c @@ -76,6 +76,8 @@ MmsDomain_getName(MmsDomain* self) void MmsDomain_addJournal(MmsDomain* self, const char* name) { + printf("CREATE JOURNAL\n"); + if (self->journals == NULL) self->journals = LinkedList_create(); @@ -84,6 +86,7 @@ MmsDomain_addJournal(MmsDomain* self, const char* name) LinkedList_add(self->journals, (void*) journal); } + MmsJournal MmsDomain_getJournal(MmsDomain* self, const char* name) { @@ -93,6 +96,8 @@ MmsDomain_getJournal(MmsDomain* self, const char* name) MmsJournal mmsJournal = (MmsJournal) LinkedList_getData(journal); + printf(" MMS journal: %s (%s)\n", mmsJournal->name, name); + if (strcmp(mmsJournal->name, name) == 0) return mmsJournal; diff --git a/src/mms/iso_mms/server/mms_journal_service.c b/src/mms/iso_mms/server/mms_journal_service.c index e0a2a4e5..8e1626d8 100644 --- a/src/mms/iso_mms/server/mms_journal_service.c +++ b/src/mms/iso_mms/server/mms_journal_service.c @@ -50,19 +50,41 @@ typedef struct { } JournalEntry; +typedef struct sJournalEncoder* JournalEncoder; + 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 */ - + uint64_t currentEntryId; //TODO use a byte array for the generic MMS case! + uint64_t currentTimestamp; + bool moreFollows; }; 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); + JournalEncoder encoder = (JournalEncoder) parameter; + + if (moreFollow) { + //printf("Encode entry ID:%" PRIu64 " timestamp:%" PRIu64 "\n", entryID, timestamp); + if (encoder->moreFollows) { + printf("entryCallback return false\n"); + return false; + } + + encoder->currentEntryBufPos = encoder->bufPos; + + encoder->bufPos += 48; /* reserve space for common entry parts */ + + encoder->currentEntryId = entryID; + encoder->currentTimestamp = timestamp; + + } + else { + printf("Encoded last entry: FINISHED\n"); + } return true; } @@ -70,46 +92,87 @@ entryCallback(void* parameter, uint64_t timestamp, uint64_t entryID, bool moreFo static bool entryDataCallback (void* parameter, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow) { + JournalEncoder encoder = (JournalEncoder) parameter; + + uint8_t* buffer = encoder->buffer; + + //TODO check if entry is too long for buffer! + if (moreFollow) { - printf(" EntryData: ref: %s\n", dataRef); + int bufPos = encoder->bufPos; + + uint32_t dataRefStrLen = strlen(dataRef); + uint32_t dataRefLen = 1 + BerEncoder_determineLengthSize(dataRefStrLen) + dataRefStrLen; + + uint32_t valueSpecLen = 1 + BerEncoder_determineLengthSize(dataSize) + dataSize; + + if (bufPos > encoder->maxSize) { + encoder->moreFollows = true; + encoder->bufPos = encoder->currentEntryBufPos; /* remove last entry */ + return false; + } + + //TODO check if entry is too long for buffer! - MmsValue* value = MmsValue_decodeMmsData(data, 0, dataSize); + bufPos = BerEncoder_encodeTL(0x30, valueSpecLen + dataRefLen, buffer, bufPos); - char buffer[256]; + /* encode dataRef */ + bufPos = BerEncoder_encodeOctetString(0x80, (uint8_t*) dataRef, dataRefStrLen, buffer, bufPos); - MmsValue_printToBuffer(value, buffer, 256); + /* encode valueSpec */ + bufPos = BerEncoder_encodeOctetString(0xa1, data, dataSize, buffer, bufPos); - printf(" value: %s\n", buffer); + //TODO optionally encode reasonCode + + encoder->bufPos = bufPos; } + else { + int dataContentLen = encoder->bufPos - (encoder->currentEntryBufPos + 48); - return true; -} + int journalVariablesLen = 1 + BerEncoder_determineLengthSize(dataContentLen) + dataContentLen; + int dataLen = 1 + BerEncoder_determineLengthSize(journalVariablesLen) + journalVariablesLen; -bool -MmsJournal_queryJournalByRange(MmsJournal self, uint64_t startTime, uint64_t endTime, ByteBuffer* response) -{ - // forward request to implementation class + int dataAndTimeLen = dataLen + 8; - //TODO get handle of LogStorage + int entryContentLen = 1 + BerEncoder_determineLengthSize(dataAndTimeLen) + dataAndTimeLen; - struct sJournalEncoder encoderData; + int journalEntryContentLen = 10 /* entryIdentifier */ + + 4 /* originatingApplication */ + + entryContentLen; - LogStorage logStorage; + int headerBufPos = encoder->currentEntryBufPos; - LogStorage_setCallbacks(logStorage, entryCallback, entryDataCallback, &encoderData); + headerBufPos = BerEncoder_encodeTL(0x30, journalEntryContentLen, buffer, headerBufPos); - LogStorage_getEntries(logStorage, startTime, endTime); + headerBufPos = BerEncoder_encodeOctetString(0x80, (uint8_t*) &(encoder->currentEntryId), 8, buffer, headerBufPos); - /* actual encoding will happen in callback handler. When getEntries returns the data is - * already encoded in the buffer. - */ + headerBufPos = BerEncoder_encodeTL(0xa1, 2, buffer, headerBufPos); + headerBufPos = BerEncoder_encodeTL(0x30, 0, buffer, headerBufPos); - // encoder header in response buffer + headerBufPos = BerEncoder_encodeTL(0xa2, dataAndTimeLen, buffer, headerBufPos); - // move encoded JournalEntry data to continue the buffer header -} + MmsValue occurenceTime; + occurenceTime.type = MMS_BINARY_TIME; + occurenceTime.value.binaryTime.size = 6; + MmsValue_setBinaryTime(&occurenceTime, encoder->currentTimestamp); + headerBufPos = BerEncoder_encodeOctetString(0x80, occurenceTime.value.binaryTime.buf, 6, buffer, headerBufPos); + + headerBufPos = BerEncoder_encodeTL(0xa2, journalVariablesLen, buffer, headerBufPos); + headerBufPos = BerEncoder_encodeTL(0xa1, dataContentLen, buffer, headerBufPos); + int entryHeaderLength = headerBufPos - encoder->currentEntryBufPos; + + /* move data to entry header */ + memmove(buffer + (encoder->currentEntryBufPos + entryHeaderLength), buffer + (encoder->currentEntryBufPos + 48), + dataContentLen); + + /* prepare buffer for next entry. */ + encoder->bufPos = encoder->currentEntryBufPos + entryHeaderLength + dataContentLen; + } + + return true; +} static bool parseStringWithMaxLength(char* filename, int maxLength, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response) @@ -141,6 +204,7 @@ parseStringWithMaxLength(char* filename, int maxLength, uint8_t* buffer, int* bu return true; } +#define RESERVED_SPACE_FOR_HEADER 22 void mmsServer_handleReadJournalRequest( @@ -154,7 +218,7 @@ mmsServer_handleReadJournalRequest( char domainId[65]; char logName[65]; - char entryIdBuf[64]; /* maximum size of entry id is 64 bytes! */ + uint8_t entryIdBuf[64]; /* maximum size of entry id is 64 bytes! */ MmsValue entrySpec; entrySpec.type = MMS_OCTET_STRING; @@ -243,7 +307,7 @@ mmsServer_handleReadJournalRequest( } else { mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); - return; + return; // forward request to implementation class } bufPos += length; @@ -277,7 +341,7 @@ mmsServer_handleReadJournalRequest( } else { mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); - return; + return; // forward request to implementation class } bufPos += length; @@ -352,11 +416,15 @@ mmsServer_handleReadJournalRequest( } //TODO check if required fields are present + if (hasNames == false) { + printf("MMS_SERVER: readJournal missing journal name\n"); + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + } + //TODO check valid field combinations /* lookup journal */ - MmsServer server = connection->server; - MmsDevice* mmsDevice = MmsServer_getDevice(connection->server); MmsDomain* mmsDomain = MmsDevice_getDomain(mmsDevice, domainId); @@ -376,6 +444,86 @@ mmsServer_handleReadJournalRequest( } printf("Read journal %s ...\n", mmsJournal->name); + + struct sJournalEncoder encoder; + + encoder.buffer = response->buffer; + encoder.moreFollows = false; + encoder.maxSize = connection->maxPduSize - 3; /* reserve three bytes for moreFollows */ + encoder.bufPos = RESERVED_SPACE_FOR_HEADER; /* reserve space for header */ + + LogStorage logStorage = mmsJournal->logStorage; + + if (logStorage != NULL) { + + if (hasRangeStartSpec && hasRangeStopSpec) { + LogStorage_getEntries(logStorage, MmsValue_getBinaryTimeAsUtcMs(&rangeStart), MmsValue_getBinaryTimeAsUtcMs(&rangeStop), + entryCallback, entryDataCallback, &encoder); + } + else if (hasEntrySpec && hasTimeSpec) { + LogStorage_getEntriesAfter(logStorage, MmsValue_getBinaryTimeAsUtcMs(&rangeStart), *((uint64_t*) entryIdBuf), + entryCallback, entryDataCallback, &encoder); + } + else { + printf("MMS_SERVER: readJournal missing valid argument combination\n"); + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + } + + } + /* actual encoding will happen in callback handler. When getEntries returns the data is + * already encoded in the buffer. + */ + + /* encode message header in response buffer */ + + uint8_t* buffer = encoder.buffer; + bufPos = 0; + + int dataSize = encoder.bufPos - RESERVED_SPACE_FOR_HEADER; + + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2; + uint32_t listOfEntriesLen = 1 + BerEncoder_determineLengthSize(dataSize) + dataSize; + + uint32_t moreFollowsLen; + + if (encoder.moreFollows) + moreFollowsLen = 3; + else + moreFollowsLen = 0; + +// uint32_t readJournalLen = 2 + BerEncoder_determineLengthSize(listOfEntriesLen + moreFollowsLen) + +// (listOfEntriesLen + moreFollowsLen); + + uint32_t readJournalLen = 2 + BerEncoder_determineLengthSize(listOfEntriesLen + moreFollowsLen) + + (listOfEntriesLen + moreFollowsLen); + + uint32_t confirmedResponsePDUSize = readJournalLen + invokeIdSize; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) invokeId, buffer, bufPos); + + buffer[bufPos++] = 0xbf; + buffer[bufPos++] = 0x41; + + bufPos = BerEncoder_encodeLength(listOfEntriesLen + moreFollowsLen, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xa0, dataSize, buffer, bufPos); + + /* move encoded JournalEntry data to continue the buffer header */ + + printf("Encoded message header with %i bytes\n", bufPos); + memmove(buffer + bufPos, buffer + RESERVED_SPACE_FOR_HEADER, dataSize); + + bufPos = bufPos + dataSize; + + /* encode morefollows */ + if (encoder.moreFollows) + bufPos = BerEncoder_encodeBoolean(0x81, true, buffer, bufPos); + + response->size = bufPos; } #endif /* (MMS_JOURNAL_SERVICE == 1) */ diff --git a/tools/model_generator/modelviewer.jar b/tools/model_generator/modelviewer.jar index 27a0c016..ec5e4ba8 100644 Binary files a/tools/model_generator/modelviewer.jar and b/tools/model_generator/modelviewer.jar differ