mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
Json_pubsub: add encoding/decoding for networkmessage and datasetmessage
This commit is contained in:
parent
1dbd3d9dac
commit
067d4c357f
@ -3,6 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
|
||||
* Copyright (c) 2018 Fraunhofer IOSB (Author: Lukas Meling)
|
||||
*/
|
||||
|
||||
#include "ua_types_encoding_binary.h"
|
||||
@ -748,10 +749,21 @@ UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_Server *server, UA_DataSetMess
|
||||
if(!dataSetMessage->data.keyFrameData.dataSetFields)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
|
||||
/* json keys */
|
||||
dataSetMessage->data.keyFrameData.fieldNames = (UA_String *)
|
||||
UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_STRING]);
|
||||
if(!dataSetMessage->data.keyFrameData.fieldNames)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
|
||||
/* Loop over the fields */
|
||||
size_t counter = 0;
|
||||
UA_DataSetField *dsf;
|
||||
LIST_FOREACH(dsf, ¤tDataSet->fields, listEntry) {
|
||||
|
||||
/* for json store the fieldNameAlias in */
|
||||
UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
|
||||
&dataSetMessage->data.keyFrameData.fieldNames[counter]);
|
||||
|
||||
/* Sample the value */
|
||||
UA_DataValue *dfv = &dataSetMessage->data.keyFrameData.dataSetFields[counter];
|
||||
UA_PubSubDataSetField_sampleValue(server, dsf, dfv);
|
||||
@ -796,9 +808,20 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_Server *server,
|
||||
dataSetMessage->header.dataSetMessageValid = true;
|
||||
dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATADELTAFRAME;
|
||||
|
||||
/* json keys, TODO: add to delete Members*/
|
||||
dataSetMessage->data.deltaFrameData.fieldNames = (UA_String *)
|
||||
UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_STRING]);
|
||||
if(!dataSetMessage->data.deltaFrameData.fieldNames)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
|
||||
UA_DataSetField *dsf;
|
||||
size_t counter = 0;
|
||||
LIST_FOREACH(dsf, ¤tDataSet->fields, listEntry) {
|
||||
|
||||
/* for json store the fieldNameAlias in */
|
||||
UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
|
||||
&dataSetMessage->data.deltaFrameData.fieldNames[counter]);
|
||||
|
||||
/* Sample the value */
|
||||
UA_DataValue value;
|
||||
UA_DataValue_init(&value);
|
||||
@ -876,6 +899,14 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da
|
||||
/* Reset the message */
|
||||
memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));
|
||||
|
||||
//TODO:
|
||||
//dataSetMessage->header.dataSetWriterId = dataSetWriter->config.dataSetWriterId;
|
||||
|
||||
UA_UInt16 messageType = 0;
|
||||
|
||||
UA_JsonDataSetWriterMessageDataType *jsonDataSetWriterMessageDataType = NULL;
|
||||
//UA_JsonDataSetWriterMessageDataType defaultJsonConfiguration;
|
||||
|
||||
/* Currently is only UADP supported. The configuration Flags are included
|
||||
* inside the std. defined UA_UadpDataSetWriterMessageDataType */
|
||||
UA_UadpDataSetWriterMessageDataType defaultUadpConfiguration;
|
||||
@ -885,6 +916,13 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da
|
||||
(dataSetWriter->config.messageSettings.content.decoded.type == &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE])) {
|
||||
dataSetWriterMessageDataType = (UA_UadpDataSetWriterMessageDataType *)
|
||||
dataSetWriter->config.messageSettings.content.decoded.data;
|
||||
messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE;
|
||||
} else if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
|
||||
dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
|
||||
(dataSetWriter->config.messageSettings.content.decoded.type == &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE])) {
|
||||
jsonDataSetWriterMessageDataType = (UA_JsonDataSetWriterMessageDataType *)
|
||||
dataSetWriter->config.messageSettings.content.decoded.data;
|
||||
messageType = UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE;
|
||||
} else {
|
||||
/* create default flag configuration if no
|
||||
* UadpDataSetWriterMessageDataType was passed in */
|
||||
@ -893,8 +931,12 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da
|
||||
(UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP | UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION |
|
||||
UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION);
|
||||
dataSetWriterMessageDataType = &defaultUadpConfiguration;
|
||||
messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE;
|
||||
}
|
||||
|
||||
if(messageType == UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE){
|
||||
|
||||
|
||||
/* Sanity-test the configuration */
|
||||
if(dataSetWriterMessageDataType->networkMessageNumber != 0 ||
|
||||
dataSetWriterMessageDataType->dataSetOffset != 0 ||
|
||||
@ -918,41 +960,79 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da
|
||||
dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
|
||||
}
|
||||
|
||||
/* Std: 'The DataSetMessageContentMask defines the flags for the content of the DataSetMessage header.' */
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION){
|
||||
dataSetMessage->header.configVersionMajorVersionEnabled = UA_TRUE;
|
||||
dataSetMessage->header.configVersionMajorVersion =
|
||||
currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
|
||||
}
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION){
|
||||
dataSetMessage->header.configVersionMinorVersionEnabled = UA_TRUE;
|
||||
dataSetMessage->header.configVersionMinorVersion =
|
||||
currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
|
||||
}
|
||||
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
|
||||
dataSetMessage->header.dataSetMessageSequenceNrEnabled = UA_TRUE;
|
||||
dataSetMessage->header.dataSetMessageSequenceNr =
|
||||
dataSetWriter->actualDataSetMessageSequenceCount;
|
||||
}
|
||||
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
|
||||
dataSetMessage->header.timestampEnabled = UA_TRUE;
|
||||
dataSetMessage->header.timestamp = UA_DateTime_now();
|
||||
}
|
||||
/* TODO: Picoseconds resolution not supported atm */
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) {
|
||||
dataSetMessage->header.picoSecondsIncluded = UA_FALSE;
|
||||
}
|
||||
/* Std: 'The DataSetMessageContentMask defines the flags for the content of the DataSetMessage header.' */
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION){
|
||||
dataSetMessage->header.configVersionMajorVersionEnabled = UA_TRUE;
|
||||
dataSetMessage->header.configVersionMajorVersion =
|
||||
currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
|
||||
}
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION){
|
||||
dataSetMessage->header.configVersionMinorVersionEnabled = UA_TRUE;
|
||||
dataSetMessage->header.configVersionMinorVersion =
|
||||
currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
|
||||
}
|
||||
|
||||
/* TODO: Statuscode not supported yet */
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_STATUS){
|
||||
dataSetMessage->header.statusEnabled = UA_FALSE;
|
||||
}
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
|
||||
dataSetMessage->header.dataSetMessageSequenceNrEnabled = UA_TRUE;
|
||||
dataSetMessage->header.dataSetMessageSequenceNr =
|
||||
dataSetWriter->actualDataSetMessageSequenceCount;
|
||||
}
|
||||
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
|
||||
dataSetMessage->header.timestampEnabled = UA_TRUE;
|
||||
dataSetMessage->header.timestamp = UA_DateTime_now();
|
||||
}
|
||||
/* TODO: Picoseconds resolution not supported atm */
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) {
|
||||
dataSetMessage->header.picoSecondsIncluded = UA_FALSE;
|
||||
}
|
||||
|
||||
/* TODO: Statuscode not supported yet */
|
||||
if(dataSetWriterMessageDataType->dataSetMessageContentMask & UA_UADPDATASETMESSAGECONTENTMASK_STATUS){
|
||||
dataSetMessage->header.statusEnabled = UA_FALSE;
|
||||
}
|
||||
|
||||
}else if(messageType == UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE){
|
||||
/*UA_JSONDATASETMESSAGECONTENTMASK_DATASETWRITERID:
|
||||
* "This value is mandatory", Part 14: 7.2.3.3 Table 92 */
|
||||
|
||||
/* Std: 'The DataSetMessageContentMask defines the flags for the content of the DataSetMessage header.' */
|
||||
if(jsonDataSetWriterMessageDataType->dataSetMessageContentMask & UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION){
|
||||
dataSetMessage->header.configVersionMajorVersionEnabled = UA_TRUE;
|
||||
dataSetMessage->header.configVersionMajorVersion =
|
||||
currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
|
||||
}
|
||||
if(jsonDataSetWriterMessageDataType->dataSetMessageContentMask & UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION){
|
||||
dataSetMessage->header.configVersionMinorVersionEnabled = UA_TRUE;
|
||||
dataSetMessage->header.configVersionMinorVersion =
|
||||
currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
|
||||
}
|
||||
|
||||
if(jsonDataSetWriterMessageDataType->dataSetMessageContentMask & UA_JSONDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
|
||||
dataSetMessage->header.dataSetMessageSequenceNrEnabled = UA_TRUE;
|
||||
dataSetMessage->header.dataSetMessageSequenceNr =
|
||||
dataSetWriter->actualDataSetMessageSequenceCount;
|
||||
}
|
||||
|
||||
if(jsonDataSetWriterMessageDataType->dataSetMessageContentMask & UA_JSONDATASETMESSAGECONTENTMASK_TIMESTAMP) {
|
||||
dataSetMessage->header.timestampEnabled = UA_TRUE;
|
||||
dataSetMessage->header.timestamp = UA_DateTime_now();
|
||||
}
|
||||
|
||||
/* TODO: Statuscode not supported yet */
|
||||
if(jsonDataSetWriterMessageDataType->dataSetMessageContentMask & UA_JSONDATASETMESSAGECONTENTMASK_STATUS){
|
||||
dataSetMessage->header.statusEnabled = UA_FALSE;
|
||||
}
|
||||
}
|
||||
/* Set the sequence count. Automatically rolls over to zero */
|
||||
dataSetWriter->actualDataSetMessageSequenceCount++;
|
||||
|
||||
/* TODO: remove. Hack for not generating deltaframes for json
|
||||
* Spec does not define deltaframes for json encoding
|
||||
*/
|
||||
if(messageType != UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE){
|
||||
#ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
|
||||
/* Check if the PublishedDataSet version has changed -> if yes flush the lastValue store and send a KeyFrame */
|
||||
if(dataSetWriter->connectedDataSetVersion.majorVersion != currentDataSet->dataSetMetaData.configurationVersion.majorVersion ||
|
||||
@ -988,6 +1068,7 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da
|
||||
|
||||
dataSetWriter->deltaFrameCounter = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
@ -1005,7 +1086,8 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
|
||||
if(writerGroup->writersCount <= 0)
|
||||
return;
|
||||
|
||||
if(writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) {
|
||||
if(writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP &&
|
||||
writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_JSON) {
|
||||
UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Unknown encoding type.");
|
||||
return;
|
||||
}
|
||||
@ -1125,23 +1207,54 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
|
||||
nmStore->payload.dataSetPayload.sizes = &dsmSizes[currentDSMPosition];
|
||||
nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = &dsWriterIds[currentDSMPosition];
|
||||
}
|
||||
//send the prepared messages
|
||||
UA_ByteString buf;
|
||||
size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nmStore[i]);
|
||||
if(UA_ByteString_allocBuffer(&buf, msgSize) == UA_STATUSCODE_GOOD) {
|
||||
UA_Byte *bufPos = buf.data;
|
||||
memset(bufPos, 0, msgSize);
|
||||
const UA_Byte *bufEnd = &(buf.data[buf.length]);
|
||||
if(UA_NetworkMessage_encodeBinary(&nmStore[i], &bufPos, bufEnd) != UA_STATUSCODE_GOOD){
|
||||
UA_ByteString_deleteMembers(&buf);
|
||||
return;
|
||||
};
|
||||
connection->channel->send(connection->channel, &writerGroup->config.transportSettings, &buf);
|
||||
|
||||
UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, writerGroup->linkedConnection);
|
||||
if(!connection){
|
||||
UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Publish failed. PubSubConnection invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//DataSet Array mit MetaData übergeben?
|
||||
|
||||
//fieldNamesPerWriter
|
||||
if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON){
|
||||
UA_ByteString buf;
|
||||
size_t msgSize = 2000; //WIP, TODO: get Json buffer size!
|
||||
if(UA_ByteString_allocBuffer(&buf, msgSize) == UA_STATUSCODE_GOOD) {
|
||||
UA_Byte *bufPos = buf.data;
|
||||
memset(bufPos, 0, msgSize);
|
||||
const UA_Byte *bufEnd = &(buf.data[buf.length]);
|
||||
if(UA_NetworkMessage_encodeJson(&nmStore[i], &bufPos, bufEnd, UA_TRUE) != UA_STATUSCODE_GOOD){
|
||||
UA_ByteString_deleteMembers(&buf);
|
||||
return;
|
||||
};
|
||||
|
||||
size_t len = strlen((char*)buf.data);
|
||||
buf.length = len;
|
||||
|
||||
connection->channel->send(connection->channel, &writerGroup->config.transportSettings, &buf);
|
||||
}
|
||||
UA_ByteString_deleteMembers(&buf);
|
||||
}else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
|
||||
//send the prepared messages
|
||||
UA_ByteString buf;
|
||||
size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nmStore[i]);
|
||||
if(UA_ByteString_allocBuffer(&buf, msgSize) == UA_STATUSCODE_GOOD) {
|
||||
UA_Byte *bufPos = buf.data;
|
||||
memset(bufPos, 0, msgSize);
|
||||
const UA_Byte *bufEnd = &(buf.data[buf.length]);
|
||||
if(UA_NetworkMessage_encodeBinary(&nmStore[i], &bufPos, bufEnd) != UA_STATUSCODE_GOOD){
|
||||
UA_ByteString_deleteMembers(&buf);
|
||||
return;
|
||||
};
|
||||
connection->channel->send(connection->channel, &writerGroup->config.transportSettings, &buf);
|
||||
}
|
||||
UA_ByteString_deleteMembers(&buf);
|
||||
}
|
||||
|
||||
//The stack allocated sizes and dataSetWriterIds field must be set to NULL to prevent invalid free.
|
||||
nmStore[i].payload.dataSetPayload.sizes = NULL;
|
||||
nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = NULL;
|
||||
UA_ByteString_deleteMembers(&buf);
|
||||
UA_NetworkMessage_deleteMembers(&nmStore[i]);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "ua_types_generated.h"
|
||||
#include "ua_types_generated_encoding_binary.h"
|
||||
#include "ua_types_generated_handling.h"
|
||||
#include "ua_log_stdout.h"
|
||||
#include "ua_types_encoding_json.h"
|
||||
|
||||
#ifdef UA_ENABLE_PUBSUB /* conditional compilation */
|
||||
|
||||
@ -810,6 +812,14 @@ UA_NetworkMessage_deleteMembers(UA_NetworkMessage* p) {
|
||||
if(p->securityHeader.securityFooterEnabled && (p->securityHeader.securityFooterSize > 0))
|
||||
UA_ByteString_deleteMembers(&p->securityFooter);
|
||||
|
||||
if(p->messageIdEnabled){
|
||||
UA_String_deleteMembers(&p->messageId);
|
||||
}
|
||||
|
||||
if(p->publisherIdEnabled && p->publisherIdType == UA_PUBLISHERDATATYPE_STRING){
|
||||
UA_String_deleteMembers(&p->publisherId.publisherIdString);
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(UA_NetworkMessage));
|
||||
}
|
||||
|
||||
@ -1264,6 +1274,12 @@ void UA_DataSetMessage_free(const UA_DataSetMessage* p) {
|
||||
if(p->data.keyFrameData.dataSetFields != NULL)
|
||||
UA_Array_delete(p->data.keyFrameData.dataSetFields, p->data.keyFrameData.fieldCount,
|
||||
&UA_TYPES[UA_TYPES_DATAVALUE]);
|
||||
|
||||
/* Json keys */
|
||||
if(p->data.keyFrameData.fieldNames != NULL){
|
||||
UA_Array_delete(p->data.keyFrameData.fieldNames, p->data.keyFrameData.fieldCount,
|
||||
&UA_TYPES[UA_TYPES_STRING]);
|
||||
}
|
||||
} else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
|
||||
if(p->data.deltaFrameData.deltaFrameFields != NULL) {
|
||||
for(UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) {
|
||||
@ -1274,8 +1290,825 @@ void UA_DataSetMessage_free(const UA_DataSetMessage* p) {
|
||||
}
|
||||
}
|
||||
UA_free(p->data.deltaFrameData.deltaFrameFields);
|
||||
|
||||
UA_Array_delete(p->data.deltaFrameData.fieldNames, p->data.deltaFrameData.fieldCount,
|
||||
&UA_TYPES[UA_TYPES_STRING]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----Json------ */
|
||||
|
||||
static UA_StatusCode
|
||||
UA_DataSetMessage_encodeJson(const UA_DataSetMessage* src, UA_UInt16 dataSetWriterId, UA_Byte **bufPos,
|
||||
const UA_Byte *bufEnd, UA_Boolean useReversible) {
|
||||
CtxJson ctx;
|
||||
ctx.pos = *bufPos;
|
||||
ctx.end = bufEnd;
|
||||
ctx.depth = 0;
|
||||
|
||||
status rv = UA_STATUSCODE_GOOD;
|
||||
|
||||
encodingJsonStartObject(&ctx);
|
||||
|
||||
/* DataSetWriterId */
|
||||
rv = writeKey(&ctx, "DataSetWriterId", UA_FALSE);
|
||||
rv = UA_encodeJson(&dataSetWriterId, &UA_TYPES[UA_TYPES_UINT16], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
|
||||
|
||||
/* DataSetMessageSequenceNr */
|
||||
if(src->header.dataSetMessageSequenceNrEnabled) {
|
||||
rv = writeKey(&ctx, "SequenceNumber", UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->header.dataSetMessageSequenceNr), &UA_TYPES[UA_TYPES_UINT16], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/* MetaDataVersion */
|
||||
if(src->header.configVersionMajorVersionEnabled || src->header.configVersionMinorVersionEnabled) {
|
||||
rv = writeKey(&ctx, "MetaDataVersion", UA_TRUE);
|
||||
UA_ConfigurationVersionDataType cvd;
|
||||
cvd.majorVersion = src->header.configVersionMajorVersion;
|
||||
cvd.minorVersion = src->header.configVersionMinorVersion;
|
||||
rv = UA_encodeJson(&cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Timestamp */
|
||||
if(src->header.timestampEnabled) {
|
||||
rv = writeKey(&ctx, "Timestamp", UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->header.timestamp), &UA_TYPES[UA_TYPES_DATETIME], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Status */
|
||||
if(src->header.statusEnabled) {
|
||||
rv = writeKey(&ctx, "Status", UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->header.status), &UA_TYPES[UA_TYPES_STATUSCODE], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = writeKey(&ctx, "Payload", UA_TRUE);
|
||||
encodingJsonStartObject(&ctx); //Payload
|
||||
|
||||
/* TODO: currently no difference between delta and key frames. Own dataSetMessageType for json?*/
|
||||
if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
|
||||
|
||||
if(src->data.keyFrameData.fieldNames == NULL){
|
||||
return UA_STATUSCODE_BADENCODINGERROR;
|
||||
}
|
||||
|
||||
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
|
||||
|
||||
for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
writeKey_UA_String(&ctx, &src->data.keyFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->data.keyFrameData.dataSetFields[i].value),
|
||||
&UA_TYPES[UA_TYPES_VARIANT], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, ctx.useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
|
||||
for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
writeKey_UA_String(&ctx, &src->data.keyFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->data.keyFrameData.dataSetFields[i]), &UA_TYPES[UA_TYPES_DATAVALUE], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}else if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME){
|
||||
|
||||
if(src->data.deltaFrameData.fieldNames == NULL){
|
||||
return UA_STATUSCODE_BADENCODINGERROR;
|
||||
}
|
||||
|
||||
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
|
||||
for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) {
|
||||
writeKey_UA_String(&ctx, &src->data.deltaFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue.value), &UA_TYPES[UA_TYPES_VARIANT], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
|
||||
for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) {
|
||||
writeKey_UA_String(&ctx, &src->data.deltaFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = UA_encodeJson(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue), &UA_TYPES[UA_TYPES_DATAVALUE], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
encodingJsonEndObject(&ctx); /* Payload */
|
||||
|
||||
encodingJsonEndObject(&ctx); /* DataSetMessage */
|
||||
|
||||
*bufPos = ctx.pos;
|
||||
bufEnd = ctx.end;
|
||||
return rv;
|
||||
}
|
||||
|
||||
UA_StatusCode
|
||||
UA_NetworkMessage_encodeJson(const UA_NetworkMessage* src, UA_Byte **bufPos,
|
||||
const UA_Byte *bufEnd, UA_Boolean useReversible) {
|
||||
|
||||
status rv = UA_STATUSCODE_GOOD;
|
||||
if(src->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
|
||||
CtxJson ctx;
|
||||
ctx.pos = *bufPos;
|
||||
ctx.end = bufEnd;
|
||||
ctx.depth = 0;
|
||||
encodingJsonStartObject(&ctx);
|
||||
|
||||
/* MessageId */
|
||||
rv = writeKey(&ctx, "MessageId", UA_FALSE);
|
||||
UA_Guid guid = UA_Guid_random();
|
||||
rv = UA_encodeJson(&guid, &UA_TYPES[UA_TYPES_GUID], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
|
||||
/* MessageType */
|
||||
rv = writeKey(&ctx, "MessageType", UA_TRUE);
|
||||
UA_String s = UA_STRING("ua-data");
|
||||
rv = UA_encodeJson(&s, &UA_TYPES[UA_TYPES_STRING], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
|
||||
/* PublisherId */
|
||||
if(src->publisherIdEnabled) {
|
||||
|
||||
rv = writeKey(&ctx, "PublisherId", UA_TRUE);
|
||||
|
||||
switch (src->publisherIdType) {
|
||||
case UA_PUBLISHERDATATYPE_BYTE:
|
||||
rv = UA_encodeJson(&src->publisherId.publisherIdByte, &UA_TYPES[UA_TYPES_BYTE], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_UINT16:
|
||||
rv = UA_encodeJson(&src->publisherId.publisherIdUInt16, &UA_TYPES[UA_TYPES_UINT16], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_UINT32:
|
||||
rv = UA_encodeJson(&src->publisherId.publisherIdUInt32, &UA_TYPES[UA_TYPES_UINT32], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_UINT64:
|
||||
rv = UA_encodeJson(&src->publisherId.publisherIdUInt64, &UA_TYPES[UA_TYPES_UINT64], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_STRING:
|
||||
rv = UA_encodeJson(&src->publisherId.publisherIdString, &UA_TYPES[UA_TYPES_STRING], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = UA_STATUSCODE_BADINTERNALERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
|
||||
|
||||
/* DataSetClassId */
|
||||
if(src->dataSetClassIdEnabled) {
|
||||
rv = writeKey(&ctx, "DataSetClassId", UA_TRUE);
|
||||
rv = UA_encodeJson(&src->dataSetClassId, &UA_TYPES[UA_TYPES_GUID], &ctx.pos, &ctx.end, NULL, 0, NULL, 0, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/* Payload: DataSetMessages */
|
||||
UA_Byte count = src->payloadHeader.dataSetPayloadHeader.count;
|
||||
if(count > 0){
|
||||
|
||||
UA_UInt16 *dataSetWriterIds = src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds;
|
||||
if(!dataSetWriterIds){
|
||||
return UA_STATUSCODE_BADENCODINGERROR;
|
||||
}
|
||||
|
||||
UA_Boolean commaNeeded = UA_FALSE;
|
||||
rv = writeKey(&ctx, "Messages", UA_TRUE);
|
||||
encodingJsonStartArray(&ctx);
|
||||
for (UA_UInt16 i = 0; i < count; i++) {
|
||||
writeComma(&ctx, commaNeeded);
|
||||
commaNeeded = UA_TRUE;
|
||||
rv = UA_DataSetMessage_encodeJson(&(src->payload.dataSetPayload.dataSetMessages[i]), dataSetWriterIds[i], &ctx.pos, ctx.end, useReversible);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
|
||||
encodingJsonEndArray(&ctx);
|
||||
}
|
||||
|
||||
encodingJsonEndObject(&ctx);
|
||||
*bufPos = ctx.pos;
|
||||
bufEnd = ctx.end;
|
||||
|
||||
} else {
|
||||
rv = UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static status MetaDataVersion_decodeJsonInternal(void* cvd, const UA_DataType *type, CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken){
|
||||
return decodeJsonInternal(cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE], ctx, parseCtx, UA_TRUE);
|
||||
}
|
||||
|
||||
const char * UA_DECODEKEY_DS_TYPE = ("Type");
|
||||
|
||||
static status DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken){
|
||||
UA_DataSetMessage* dsm = (UA_DataSetMessage*)dsmP;
|
||||
dsm->header.dataSetMessageValid = UA_TRUE;
|
||||
if(isJsonNull(ctx, parseCtx)){
|
||||
(*parseCtx->index)++;
|
||||
//TODO: set size, etc.
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
size_t length = (size_t)parseCtx->tokenArray[*parseCtx->index].size;
|
||||
//UA_Variant *var = (UA_Variant*)UA_calloc(length, sizeof(UA_Variant));
|
||||
//dsm->data.keyFrameData
|
||||
UA_String *fieldNames = (UA_String*)UA_calloc(length, sizeof(UA_String));
|
||||
//parseCtx->fieldNames = fieldNames;
|
||||
//parseCtx->fieldNamesCount = length;
|
||||
dsm->data.keyFrameData.fieldNames = fieldNames;
|
||||
|
||||
//UA_KeyValuePair *keyValuePairs = (UA_KeyValuePair*)UA_Array_new(dsm->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
|
||||
|
||||
dsm->data.keyFrameData.fieldCount = (UA_UInt16)length;
|
||||
|
||||
dsm->data.keyFrameData.dataSetFields =
|
||||
(UA_DataValue *)UA_Array_new(dsm->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
|
||||
|
||||
|
||||
status ret = UA_STATUSCODE_GOOD;
|
||||
(*parseCtx->index)++; // We go to first Object key!
|
||||
for(size_t i = 0; i < length; ++i) {
|
||||
|
||||
ret = getDecodeSignature(UA_TYPES_STRING)(&fieldNames[i], type, ctx, parseCtx, UA_TRUE);
|
||||
//ret = getDecodeSignature(UA_TYPES_STRING)(&keyValuePairs[i].key.name, type, ctx, parseCtx, UA_TRUE);
|
||||
if(ret != UA_STATUSCODE_GOOD){
|
||||
//TODO: handle error, free mem
|
||||
}
|
||||
|
||||
//Is field a variant or datavalue?
|
||||
UA_Boolean isVariant = UA_TRUE;
|
||||
size_t searchResultBody = 0;
|
||||
lookAheadForKey(UA_DECODEKEY_DS_TYPE, ctx, parseCtx, &searchResultBody);
|
||||
if(searchResultBody == 0){
|
||||
isVariant = UA_FALSE;
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
|
||||
}else{
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
|
||||
}
|
||||
|
||||
UA_DataValue_init(&dsm->data.keyFrameData.dataSetFields[i]);
|
||||
|
||||
if(isVariant){
|
||||
ret = getDecodeSignature(UA_TYPES_VARIANT)(&dsm->data.keyFrameData.dataSetFields[i].value, type, ctx, parseCtx, UA_TRUE);
|
||||
dsm->data.keyFrameData.dataSetFields[i].hasValue = UA_TRUE;
|
||||
}else{
|
||||
ret = getDecodeSignature(UA_TYPES_DATAVALUE)(&dsm->data.keyFrameData.dataSetFields[i], type, ctx, parseCtx, UA_TRUE);
|
||||
dsm->data.keyFrameData.dataSetFields[i].hasValue = UA_TRUE;
|
||||
}
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD){
|
||||
//TODO: handle error, free mem
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char * UA_DECODEKEY_DATASETWRITERID = ("DataSetWriterId");
|
||||
const char * UA_DECODEKEY_SEQUENCENUMBER = ("SequenceNumber");
|
||||
const char * UA_DECODEKEY_METADATAVERSION = ("MetaDataVersion");
|
||||
const char * UA_DECODEKEY_TIMESTAMP = ("Timestamp");
|
||||
const char * UA_DECODEKEY_DSM_STATUS = ("Status");
|
||||
const char * UA_DECODEKEY_PAYLOAD = ("Payload");
|
||||
|
||||
|
||||
static status
|
||||
DatasetMessage_Payload_decodeJsonInternal(UA_DataSetMessage* dsm, const UA_DataType *type, CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken) {
|
||||
UA_ConfigurationVersionDataType cvd;
|
||||
UA_UInt16 dataSetWriterId; //TODO: Where to store?
|
||||
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
|
||||
|
||||
const char* fieldNames[6] = {
|
||||
UA_DECODEKEY_DATASETWRITERID,
|
||||
UA_DECODEKEY_SEQUENCENUMBER,
|
||||
UA_DECODEKEY_METADATAVERSION,
|
||||
UA_DECODEKEY_TIMESTAMP,
|
||||
UA_DECODEKEY_DSM_STATUS,
|
||||
UA_DECODEKEY_PAYLOAD};
|
||||
UA_Boolean found[6] = {UA_FALSE, UA_FALSE, UA_FALSE, UA_FALSE, UA_FALSE, UA_FALSE};
|
||||
void *fieldPointer[6] = {
|
||||
&dataSetWriterId,
|
||||
&dsm->header.dataSetMessageSequenceNr,
|
||||
&cvd,
|
||||
&dsm->header.timestamp,
|
||||
&dsm->header.status,
|
||||
dsm};
|
||||
decodeJsonSignature functions[] = {
|
||||
getDecodeSignature(UA_TYPES_UINT16),
|
||||
getDecodeSignature(UA_TYPES_UINT16),
|
||||
&MetaDataVersion_decodeJsonInternal,
|
||||
getDecodeSignature(UA_TYPES_DATETIME),
|
||||
getDecodeSignature(UA_TYPES_UINT16),
|
||||
&DataSetPayload_decodeJsonInternal
|
||||
};
|
||||
|
||||
DecodeContext decodeCtx = {fieldNames, fieldPointer, functions, found, 6};
|
||||
status ret = decodeFields(ctx, parseCtx, &decodeCtx, NULL);
|
||||
|
||||
if(!found[0]){
|
||||
/* no dataSetwriterid. Is mandatory. Abort. */
|
||||
ret = UA_STATUSCODE_BADDECODINGERROR;
|
||||
goto cleanup;
|
||||
}else{
|
||||
if(parseCtx->custom != NULL){
|
||||
UA_UInt16* dataSetWriterIdsArray = (UA_UInt16*)parseCtx->custom;
|
||||
|
||||
if(*parseCtx->currentCustomIndex < parseCtx->numCustom){
|
||||
dataSetWriterIdsArray[*parseCtx->currentCustomIndex] = dataSetWriterId;
|
||||
(*parseCtx->currentCustomIndex)++;
|
||||
}else{
|
||||
ret = UA_STATUSCODE_BADDECODINGERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
}else{
|
||||
ret = UA_STATUSCODE_BADDECODINGERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
dsm->header.dataSetMessageSequenceNrEnabled = found[1];
|
||||
dsm->header.configVersionMajorVersion = cvd.majorVersion;
|
||||
dsm->header.configVersionMinorVersion = cvd.minorVersion;
|
||||
dsm->header.configVersionMajorVersionEnabled = found[2];
|
||||
dsm->header.configVersionMinorVersionEnabled = found[2];
|
||||
dsm->header.timestampEnabled = found[3];
|
||||
dsm->header.statusEnabled = found[4];
|
||||
if(!found[5]){
|
||||
//No payload found
|
||||
ret = UA_STATUSCODE_BADDECODINGERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
|
||||
dsm->header.picoSecondsIncluded = UA_FALSE;
|
||||
dsm->header.dataSetMessageValid = UA_TRUE;
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
|
||||
|
||||
cleanup:
|
||||
//UA_ConfigurationVersionDataType_delete(cvd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static status
|
||||
DatasetMessage_Array_decodeJsonInternal(void *UA_RESTRICT dst, const UA_DataType *type, CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken) {
|
||||
/* Array! */
|
||||
if(getJsmnType(parseCtx) != JSMN_ARRAY){
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}
|
||||
status ret;
|
||||
|
||||
size_t length = (size_t)parseCtx->tokenArray[*parseCtx->index].size;
|
||||
|
||||
/* Return early for empty arrays */
|
||||
if(length == 0) {
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
UA_DataSetMessage *dsm = (UA_DataSetMessage*)UA_calloc(length, sizeof(UA_DataSetMessage));
|
||||
if(dsm == NULL)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
|
||||
memcpy(dst, &dsm, sizeof(void*)); //Copy new Pointer do dest
|
||||
|
||||
|
||||
(*parseCtx->index)++; // We go to first Array member!
|
||||
|
||||
/* Decode array members */
|
||||
for(size_t i = 0; i < length; ++i) {
|
||||
//ret = decodeJsonJumpTable[decode_index]((void*)dsm[i], type, ctx, parseCtx, UA_TRUE);
|
||||
|
||||
ret = DatasetMessage_Payload_decodeJsonInternal(&dsm[i], NULL, ctx, parseCtx, UA_TRUE);
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD){
|
||||
//TODO: handle error, free mem
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char * UA_DECODEKEY_MESSAGES = ("Messages");
|
||||
const char * UA_DECODEKEY_MESSAGETYPE = ("MessageType");
|
||||
const char * UA_DECODEKEY_MESSAGEID = ("MessageId");
|
||||
const char * UA_DECODEKEY_PUBLISHERID = ("PublisherId");
|
||||
const char * UA_DECODEKEY_DATASETCLASSID = ("DataSetClassId");
|
||||
|
||||
static status NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson *ctx, ParseCtx *parseCtx){
|
||||
|
||||
memset(dst, 0, sizeof(UA_NetworkMessage));
|
||||
|
||||
dst->chunkMessage = UA_FALSE;
|
||||
dst->groupHeaderEnabled = UA_FALSE;
|
||||
dst->payloadHeaderEnabled = UA_FALSE;
|
||||
dst->picosecondsEnabled = UA_FALSE;
|
||||
dst->promotedFieldsEnabled = UA_FALSE;
|
||||
|
||||
/* Look forward for publisheId, if present check if type if primitve (Number) or String. */
|
||||
u8 publishIdTypeIndex = UA_TYPES_STRING;
|
||||
{
|
||||
size_t searchResultPublishIdType = 0;
|
||||
lookAheadForKey(UA_DECODEKEY_MESSAGES, ctx, parseCtx, &searchResultPublishIdType);
|
||||
if(searchResultPublishIdType != 0){
|
||||
jsmntok_t publishIdToken = parseCtx->tokenArray[searchResultPublishIdType];
|
||||
//size_t sizeOfPublishId = (size_t)(parseCtx->tokenArray[searchResultPublishIdType].end
|
||||
// - parseCtx->tokenArray[searchResultPublishIdType].start);
|
||||
if(publishIdToken.type == JSMN_PRIMITIVE){
|
||||
publishIdTypeIndex = UA_TYPES_UINT64;
|
||||
dst->publisherIdType = UA_PUBLISHERDATATYPE_UINT64; //store in biggest possible
|
||||
}else if(publishIdToken.type == JSMN_STRING){
|
||||
//String
|
||||
publishIdTypeIndex = UA_TYPES_STRING;
|
||||
dst->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
|
||||
/*if(sizeOfPublishId == 36){
|
||||
char *buf = (char*)(ctx->pos + parseCtx->tokenArray[*parseCtx->index].start);
|
||||
// 8 13 18 23 should be -
|
||||
if(buf[8] == '-' && buf[13] == '-' && buf[18] == '-' && buf[23] == '-'){
|
||||
publishIdTypeIndex = UA_TYPES_GUID;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t messageCount = 0;
|
||||
{
|
||||
//Is Messages an Array? How big?
|
||||
size_t searchResultMessages = 0;
|
||||
lookAheadForKey(UA_DECODEKEY_MESSAGES, ctx, parseCtx, &searchResultMessages);
|
||||
if(searchResultMessages != 0){
|
||||
jsmntok_t bodyToken = parseCtx->tokenArray[searchResultMessages];
|
||||
if(bodyToken.type == JSMN_ARRAY){
|
||||
messageCount = (size_t)parseCtx->tokenArray[searchResultMessages].size;
|
||||
}
|
||||
}else{
|
||||
//DataSetmessages are in a Array!
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
//Set up custom context for the dataSetwriterId
|
||||
size_t currentCustomIndex = 0;
|
||||
parseCtx->custom = (void*)UA_calloc(messageCount, sizeof(UA_UInt16));
|
||||
parseCtx->currentCustomIndex = ¤tCustomIndex;
|
||||
parseCtx->numCustom = messageCount;
|
||||
|
||||
/* MessageType */
|
||||
UA_Boolean isUaData = UA_TRUE;
|
||||
size_t searchResultMessageType = 0;
|
||||
lookAheadForKey(UA_DECODEKEY_MESSAGETYPE, ctx, parseCtx, &searchResultMessageType);
|
||||
if(searchResultMessageType == 0){
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}else{
|
||||
size_t size = (size_t)(parseCtx->tokenArray[searchResultMessageType].end - parseCtx->tokenArray[searchResultMessageType].start);
|
||||
char* msgType = (char*)(ctx->pos + parseCtx->tokenArray[searchResultMessageType].start);
|
||||
if(size == 7){ //ua-data
|
||||
if(strncmp(msgType, "ua-data", size) != 0){
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}else{
|
||||
isUaData = UA_TRUE;
|
||||
}
|
||||
}else if(size == 11){ //ua-metadata
|
||||
if(strncmp(msgType, "ua-metadata", size) != 0){
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}else{
|
||||
isUaData = UA_FALSE;
|
||||
}
|
||||
}else{
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(isUaData){
|
||||
/* Network Message */
|
||||
status ret = UA_STATUSCODE_GOOD;
|
||||
|
||||
UA_String messageType;
|
||||
const char* fieldNames[5] = {UA_DECODEKEY_MESSAGEID,
|
||||
UA_DECODEKEY_MESSAGETYPE,
|
||||
UA_DECODEKEY_PUBLISHERID,
|
||||
UA_DECODEKEY_DATASETCLASSID,
|
||||
UA_DECODEKEY_MESSAGES};
|
||||
UA_Boolean found[5] = {UA_FALSE, UA_FALSE, UA_FALSE, UA_FALSE, UA_FALSE};
|
||||
void *fieldPointer[5] = {&dst->messageId, &messageType, &dst->publisherId.publisherIdString, &dst->dataSetClassId, &dst->payload.dataSetPayload.dataSetMessages};
|
||||
|
||||
//Store publisherId in correct union
|
||||
if(publishIdTypeIndex == UA_TYPES_UINT64)
|
||||
fieldPointer[2] = &dst->publisherId.publisherIdUInt64;
|
||||
|
||||
decodeJsonSignature functions[5] = {
|
||||
getDecodeSignature(UA_TYPES_STRING),
|
||||
NULL,
|
||||
getDecodeSignature(publishIdTypeIndex),
|
||||
getDecodeSignature(UA_TYPES_GUID),
|
||||
&DatasetMessage_Array_decodeJsonInternal
|
||||
};
|
||||
DecodeContext decodeCtx = {fieldNames, fieldPointer, functions, found, 5};
|
||||
|
||||
ret = decodeFields(ctx, parseCtx, &decodeCtx, NULL);
|
||||
|
||||
dst->messageIdEnabled = found[0];
|
||||
dst->publisherIdEnabled = found[2];
|
||||
if(dst->publisherIdEnabled){
|
||||
dst->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
|
||||
}
|
||||
dst->dataSetClassIdEnabled = found[3];
|
||||
dst->payloadHeaderEnabled = UA_TRUE;
|
||||
dst->payloadHeader.dataSetPayloadHeader.count = (UA_Byte)messageCount;
|
||||
|
||||
|
||||
//Set the dataSetWriterIds. They are filled in the dataSet decoding.
|
||||
dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = (UA_UInt16*)parseCtx->custom;
|
||||
return ret;
|
||||
}else{
|
||||
//TODO: MetaData
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, UA_ByteString *src){
|
||||
/* Set up the context */
|
||||
CtxJson ctx;
|
||||
ParseCtx parseCtx;
|
||||
memset(&parseCtx, 0, sizeof(ParseCtx));
|
||||
|
||||
parseCtx.tokenArray = (jsmntok_t*)malloc(sizeof(jsmntok_t) * TOKENCOUNT);
|
||||
memset(parseCtx.tokenArray, 0, sizeof(jsmntok_t) * TOKENCOUNT);
|
||||
|
||||
status ret = UA_STATUSCODE_GOOD;
|
||||
|
||||
UA_UInt16 tokenIndex = 0;
|
||||
ret = tokenize(&parseCtx, &ctx, src, &tokenIndex);
|
||||
if(ret != UA_STATUSCODE_GOOD){
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = NetworkMessage_decodeJsonInternal(dst, &ctx, &parseCtx);
|
||||
free(parseCtx.tokenArray);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Calc size */
|
||||
static status
|
||||
UA_DataSetMessage_calcSizeJson(const UA_DataSetMessage* src, UA_UInt16 dataSetWriterId, CtxJson *ctx) {
|
||||
|
||||
status rv = UA_STATUSCODE_GOOD;
|
||||
|
||||
//encodingJsonStartObject(&ctx);
|
||||
ctx->pos++;
|
||||
|
||||
/* DataSetWriterId */
|
||||
rv = calcWriteKey(ctx, "DataSetWriterId", UA_FALSE);
|
||||
rv = calcJsonInternal(&dataSetWriterId, &UA_TYPES[UA_TYPES_UINT16], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
|
||||
|
||||
/* DataSetMessageSequenceNr */
|
||||
if(src->header.dataSetMessageSequenceNrEnabled) {
|
||||
rv = calcWriteKey(ctx, "SequenceNumber", UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->header.dataSetMessageSequenceNr), &UA_TYPES[UA_TYPES_UINT16],ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* MetaDataVersion */
|
||||
if(src->header.configVersionMajorVersionEnabled || src->header.configVersionMinorVersionEnabled) {
|
||||
rv = calcWriteKey(ctx, "MetaDataVersion", UA_TRUE);
|
||||
UA_ConfigurationVersionDataType cvd;
|
||||
cvd.majorVersion = src->header.configVersionMajorVersion;
|
||||
cvd.minorVersion = src->header.configVersionMinorVersion;
|
||||
rv = calcJsonInternal(&cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Timestamp */
|
||||
if(src->header.timestampEnabled) {
|
||||
rv = calcWriteKey(ctx, "Timestamp", UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->header.timestamp), &UA_TYPES[UA_TYPES_DATETIME], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Status */
|
||||
if(src->header.statusEnabled) {
|
||||
rv = calcWriteKey(ctx, "Status", UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->header.status), &UA_TYPES[UA_TYPES_STATUSCODE], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = calcWriteKey(ctx, "Payload", UA_TRUE);
|
||||
//encodingJsonStartObject(&ctx); //Payload
|
||||
ctx->pos++;
|
||||
|
||||
/* TODO: currently no difference between delta and key frames. Own dataSetMessageType for json?*/
|
||||
if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
|
||||
|
||||
if(src->data.keyFrameData.fieldNames == NULL){
|
||||
return UA_STATUSCODE_BADENCODINGERROR;
|
||||
}
|
||||
|
||||
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
|
||||
|
||||
for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
calcWriteKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->data.keyFrameData.dataSetFields[i].value),
|
||||
&UA_TYPES[UA_TYPES_VARIANT], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
|
||||
for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
calcWriteKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->data.keyFrameData.dataSetFields[i]), &UA_TYPES[UA_TYPES_DATAVALUE], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}else if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME){
|
||||
|
||||
if(src->data.deltaFrameData.fieldNames == NULL){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
|
||||
for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) {
|
||||
calcWriteKey_UA_String(ctx, &src->data.deltaFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue.value), &UA_TYPES[UA_TYPES_VARIANT], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
|
||||
for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) {
|
||||
calcWriteKey_UA_String(ctx, &src->data.deltaFrameData.fieldNames[i], i==0?UA_FALSE: UA_TRUE);
|
||||
rv = calcJsonInternal(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue), &UA_TYPES[UA_TYPES_DATAVALUE], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//encodingJsonEndObject(&ctx); /* Payload */
|
||||
ctx->pos++;
|
||||
|
||||
//encodingJsonEndObject(&ctx); /* DataSetMessage */
|
||||
ctx->pos++;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static status
|
||||
UA_NetworkMessage_calcSizeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx) {
|
||||
|
||||
status rv = UA_STATUSCODE_GOOD;
|
||||
if(src->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
|
||||
|
||||
//encodingJsonStartObject(&ctx);
|
||||
ctx->pos++;
|
||||
|
||||
/* MessageId */
|
||||
rv = calcWriteKey(ctx, "MessageId", UA_FALSE);
|
||||
UA_Guid guid = UA_Guid_random();
|
||||
rv = calcJsonInternal(&guid, &UA_TYPES[UA_TYPES_GUID], ctx);
|
||||
|
||||
/* MessageType */
|
||||
rv = calcWriteKey(ctx, "MessageType", UA_TRUE);
|
||||
UA_String s = UA_STRING("ua-data");
|
||||
rv = calcJsonInternal(&s, &UA_TYPES[UA_TYPES_STRING], ctx);
|
||||
|
||||
/* PublisherId */
|
||||
if(src->publisherIdEnabled) {
|
||||
|
||||
rv = calcWriteKey(ctx, "PublisherId", UA_TRUE);
|
||||
|
||||
switch (src->publisherIdType) {
|
||||
case UA_PUBLISHERDATATYPE_BYTE:
|
||||
rv = calcJsonInternal(&src->publisherId.publisherIdByte, &UA_TYPES[UA_TYPES_BYTE], ctx);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_UINT16:
|
||||
rv = calcJsonInternal(&src->publisherId.publisherIdUInt16, &UA_TYPES[UA_TYPES_UINT16], ctx);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_UINT32:
|
||||
rv = calcJsonInternal(&src->publisherId.publisherIdUInt32, &UA_TYPES[UA_TYPES_UINT32], ctx);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_UINT64:
|
||||
rv = calcJsonInternal(&src->publisherId.publisherIdUInt64, &UA_TYPES[UA_TYPES_UINT64], ctx);
|
||||
break;
|
||||
|
||||
case UA_PUBLISHERDATATYPE_STRING:
|
||||
rv = calcJsonInternal(&src->publisherId.publisherIdString, &UA_TYPES[UA_TYPES_STRING], ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
|
||||
|
||||
/* DataSetClassId */
|
||||
if(src->dataSetClassIdEnabled) {
|
||||
rv = calcWriteKey(ctx, "DataSetClassId", UA_TRUE);
|
||||
rv = calcJsonInternal(&src->dataSetClassId, &UA_TYPES[UA_TYPES_GUID], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Payload: DataSetMessages */
|
||||
UA_Byte count = src->payloadHeader.dataSetPayloadHeader.count;
|
||||
if(count > 0){
|
||||
|
||||
UA_UInt16 *dataSetWriterIds = src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds;
|
||||
if(!dataSetWriterIds){
|
||||
return 0;
|
||||
}
|
||||
|
||||
UA_Boolean commaNeeded = UA_FALSE;
|
||||
rv = calcWriteKey(ctx, "Messages", UA_TRUE);
|
||||
//encodingJsonStartArray(&ctx);
|
||||
ctx->pos++;
|
||||
for (UA_UInt16 i = 0; i < count; i++) {
|
||||
calcWriteComma(ctx, commaNeeded);
|
||||
commaNeeded = UA_TRUE;
|
||||
rv = UA_DataSetMessage_calcSizeJson(&(src->payload.dataSetPayload.dataSetMessages[i]), dataSetWriterIds[i], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//encodingJsonEndArray(&ctx);
|
||||
ctx->pos++;
|
||||
}
|
||||
|
||||
//encodingJsonEndObject(&ctx);
|
||||
ctx->pos++;
|
||||
|
||||
return rv;
|
||||
} else {
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage* src, UA_Boolean useReversible){
|
||||
|
||||
CtxJson ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.pos = 0;
|
||||
ctx.depth = 0;
|
||||
ctx.useReversible = useReversible;
|
||||
//ctx.namespaces = namespaces;
|
||||
//ctx.namespacesSize = namespaceSize;
|
||||
//ctx.serverUris = serverUris;
|
||||
//ctx.serverUrisSize = serverUriSize;
|
||||
|
||||
status rv = UA_STATUSCODE_GOOD;
|
||||
|
||||
UA_NetworkMessage_calcSizeJson_internal(src, &ctx);
|
||||
|
||||
if(rv != UA_STATUSCODE_GOOD){
|
||||
return 0;
|
||||
}else{
|
||||
return (size_t)ctx.pos;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* UA_ENABLE_PUBSUB */
|
||||
|
@ -3,6 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
|
||||
* Copyright (c) 2018 Fraunhofer IOSB (Author: Lukas Meling)
|
||||
*/
|
||||
|
||||
#ifndef UA_PUBSUB_NETWORKMESSAGE_H_
|
||||
@ -71,6 +72,8 @@ UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p);
|
||||
typedef struct {
|
||||
UA_UInt16 fieldCount;
|
||||
UA_DataValue* dataSetFields;
|
||||
/* Json keys for the dataSetFields: TODO: own dataSetMessageType for json? */
|
||||
UA_String* fieldNames;
|
||||
} UA_DataSetMessage_DataKeyFrameData;
|
||||
|
||||
typedef struct {
|
||||
@ -81,6 +84,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
UA_UInt16 fieldCount;
|
||||
UA_DataSetMessage_DeltaFrameField* deltaFrameFields;
|
||||
/* Json keys for the dataSetFields: TODO: own dataSetMessageType for json? */
|
||||
UA_String* fieldNames;
|
||||
} UA_DataSetMessage_DataDeltaFrameData;
|
||||
|
||||
typedef struct {
|
||||
@ -156,6 +161,8 @@ typedef struct {
|
||||
* ^^^^^^^^^^^^^^^^^ */
|
||||
typedef struct {
|
||||
UA_Byte version;
|
||||
UA_Boolean messageIdEnabled;
|
||||
UA_String messageId; //For Json NetworkMessage
|
||||
UA_Boolean publisherIdEnabled;
|
||||
UA_Boolean groupHeaderEnabled;
|
||||
UA_Boolean payloadHeaderEnabled;
|
||||
@ -215,6 +222,16 @@ UA_NetworkMessage_deleteMembers(UA_NetworkMessage* p);
|
||||
void
|
||||
UA_NetworkMessage_delete(UA_NetworkMessage* p);
|
||||
|
||||
/* Json */
|
||||
UA_StatusCode
|
||||
UA_NetworkMessage_encodeJson(const UA_NetworkMessage* src,
|
||||
UA_Byte **bufPos, const UA_Byte *bufEnd, UA_Boolean useReversible);
|
||||
|
||||
UA_StatusCode UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, UA_ByteString *src);
|
||||
|
||||
size_t
|
||||
UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage* src, UA_Boolean useReversible);
|
||||
|
||||
_UA_END_DECLS
|
||||
|
||||
#endif /* UA_PUBSUB_NETWORKMESSAGE_H_ */
|
||||
|
@ -73,7 +73,6 @@ extern const decodeJsonSignature decodeJsonJumpTable[UA_BUILTIN_TYPES_COUNT + 1]
|
||||
|
||||
/* Forward declarations */
|
||||
static status encodeJsonInternal(const void *src, const UA_DataType *type, CtxJson *ctx);
|
||||
static status calcJsonInternal(const void *src, const UA_DataType *type, CtxJson *ctx);
|
||||
UA_String UA_DateTime_toJSON(UA_DateTime t);
|
||||
ENCODE_JSON(ByteString);
|
||||
|
||||
@ -1336,7 +1335,7 @@ const calcSizeJsonSignature calcJsonJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
|
||||
(calcSizeJsonSignature) calcJsonInternal,
|
||||
};
|
||||
|
||||
static status
|
||||
status
|
||||
calcJsonInternal(const void *src, const UA_DataType *type, CtxJson *ctx) {
|
||||
if(!type || !ctx){
|
||||
return UA_STATUSCODE_BADENCODINGERROR;
|
||||
|
@ -87,12 +87,19 @@ status encodingCalcJsonStartArray(CtxJson *ctx);
|
||||
size_t encodingCalcJsonEndArray(CtxJson *ctx);
|
||||
status calcWriteComma(CtxJson *ctx, UA_Boolean commaNeeded);
|
||||
status calcWriteNull(CtxJson *ctx);
|
||||
status calcJsonInternal(const void *src, const UA_DataType *type, CtxJson *ctx);
|
||||
|
||||
|
||||
typedef struct {
|
||||
jsmntok_t *tokenArray;
|
||||
UA_Int32 tokenCount;
|
||||
UA_UInt16 *index;
|
||||
|
||||
/* Additonal data for special cases such as networkmessage/datasetmessage
|
||||
* Currently only used for dataSetWriterIds*/
|
||||
size_t numCustom;
|
||||
void * custom;
|
||||
size_t* currentCustomIndex;
|
||||
} ParseCtx;
|
||||
|
||||
typedef status(*encodeJsonSignature)(const void *UA_RESTRICT src, const UA_DataType *type,
|
||||
|
@ -105,10 +105,9 @@ if(UA_ENABLE_JSON_ENCODING)
|
||||
add_test_valgrind(types_builtin_json ${TESTS_BINARY_DIR}/check_types_builtin_json)
|
||||
|
||||
if(UA_ENABLE_PUBSUB)
|
||||
#later batch
|
||||
#add_executable(check_pubsub_encoding_json pubsub/check_pubsub_encoding_json.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-testplugins>)
|
||||
#target_link_libraries(check_pubsub_encoding_json ${LIBS})
|
||||
#add_test_valgrind(pubsub_encoding_json ${TESTS_BINARY_DIR}/check_pubsub_encoding_json)
|
||||
add_executable(check_pubsub_encoding_json pubsub/check_pubsub_encoding_json.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-testplugins>)
|
||||
target_link_libraries(check_pubsub_encoding_json ${LIBS})
|
||||
add_test_valgrind(pubsub_encoding_json ${TESTS_BINARY_DIR}/check_pubsub_encoding_json)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
318
tests/pubsub/check_pubsub_encoding_json.c
Normal file
318
tests/pubsub/check_pubsub_encoding_json.c
Normal file
@ -0,0 +1,318 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) 2018 Fraunhofer IOSB (Author: Lukas Meling)
|
||||
*/
|
||||
|
||||
#include "ua_types.h"
|
||||
#include "ua_client.h"
|
||||
#include "ua_util.h"
|
||||
#include "ua_pubsub_networkmessage.h"
|
||||
#include "check.h"
|
||||
|
||||
START_TEST(UA_PubSub_EnDecode) {
|
||||
UA_NetworkMessage m;
|
||||
memset(&m, 0, sizeof(UA_NetworkMessage));
|
||||
m.version = 1;
|
||||
m.networkMessageType = UA_NETWORKMESSAGE_DATASET;
|
||||
m.payloadHeaderEnabled = true;
|
||||
m.payloadHeader.dataSetPayloadHeader.count = 2;
|
||||
UA_UInt16 dsWriter1 = 4;
|
||||
UA_UInt16 dsWriter2 = 7;
|
||||
m.payloadHeader.dataSetPayloadHeader.dataSetWriterIds = (UA_UInt16 *)UA_Array_new(m.payloadHeader.dataSetPayloadHeader.count, &UA_TYPES[UA_TYPES_UINT16]);
|
||||
m.payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0] = dsWriter1;
|
||||
m.payloadHeader.dataSetPayloadHeader.dataSetWriterIds[1] = dsWriter2;
|
||||
|
||||
size_t memsize = m.payloadHeader.dataSetPayloadHeader.count * sizeof(UA_DataSetMessage);
|
||||
m.payload.dataSetPayload.dataSetMessages = (UA_DataSetMessage*)UA_malloc(memsize);
|
||||
memset(m.payload.dataSetPayload.dataSetMessages, 0, memsize);
|
||||
|
||||
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid = true;
|
||||
m.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding = UA_FIELDENCODING_VARIANT;
|
||||
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
|
||||
UA_UInt16 fieldCountDS1 = 1;
|
||||
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount = fieldCountDS1;
|
||||
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields =
|
||||
(UA_DataValue*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
|
||||
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0]);
|
||||
|
||||
/* Set fieldnames */
|
||||
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames =
|
||||
(UA_String*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_STRING]);
|
||||
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0] = UA_STRING_ALLOC("Field1");
|
||||
|
||||
UA_UInt32 iv = 27;
|
||||
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value, &iv, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue = true;
|
||||
|
||||
m.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageValid = true;
|
||||
m.payload.dataSetPayload.dataSetMessages[1].header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
|
||||
m.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageType = UA_DATASETMESSAGE_DATADELTAFRAME;
|
||||
UA_UInt16 fieldCountDS2 = 2;
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldCount = fieldCountDS2;
|
||||
memsize = sizeof(UA_DataSetMessage_DeltaFrameField) * m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldCount;
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)UA_malloc(memsize);
|
||||
/* Set fieldnames */
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldNames =
|
||||
(UA_String*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldCount, &UA_TYPES[UA_TYPES_STRING]);
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldNames[0] = UA_STRING_ALLOC("Field2.1");
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldNames[1] = UA_STRING_ALLOC("Field2.2");
|
||||
|
||||
|
||||
UA_Guid gv = UA_Guid_random();
|
||||
UA_UInt16 fieldIndex1 = 2;
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldIndex = fieldIndex1;
|
||||
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue);
|
||||
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue.value, &gv, &UA_TYPES[UA_TYPES_GUID]);
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue.hasValue = true;
|
||||
|
||||
UA_UInt16 fieldIndex2 = 5;
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[1].fieldIndex = fieldIndex2;
|
||||
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[1].fieldValue);
|
||||
UA_Int64 iv64 = 152478978534;
|
||||
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[1].fieldValue.value, &iv64, &UA_TYPES[UA_TYPES_INT64]);
|
||||
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[1].fieldValue.hasValue = true;
|
||||
|
||||
UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
|
||||
UA_ByteString buffer;
|
||||
size_t msgSize = 1000;
|
||||
rv = UA_ByteString_allocBuffer(&buffer, msgSize);
|
||||
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
|
||||
|
||||
UA_Byte *bufPos = buffer.data;
|
||||
memset(bufPos, 0, msgSize);
|
||||
const UA_Byte *bufEnd = &(buffer.data[buffer.length]);
|
||||
|
||||
size_t size = UA_NetworkMessage_calcSizeJson(&m, UA_TRUE);
|
||||
ck_assert(size == 318);
|
||||
|
||||
rv = UA_NetworkMessage_encodeJson(&m, &bufPos, bufEnd, UA_TRUE);
|
||||
*bufPos = 0;
|
||||
// then
|
||||
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
|
||||
|
||||
UA_NetworkMessage m2;
|
||||
memset(&m2, 0, sizeof(UA_NetworkMessage));
|
||||
rv = UA_NetworkMessage_decodeJson(&m2, &buffer);
|
||||
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
|
||||
ck_assert(m.networkMessageType == m2.networkMessageType);
|
||||
ck_assert(m.timestampEnabled == m2.timestampEnabled);
|
||||
ck_assert(m.dataSetClassIdEnabled == m2.dataSetClassIdEnabled);
|
||||
ck_assert(m.groupHeaderEnabled == m2.groupHeaderEnabled);
|
||||
ck_assert(m.picosecondsEnabled == m2.picosecondsEnabled);
|
||||
ck_assert(m.promotedFieldsEnabled == m2.promotedFieldsEnabled);
|
||||
ck_assert(m.publisherIdEnabled == m2.publisherIdEnabled);
|
||||
ck_assert(m.securityEnabled == m2.securityEnabled);
|
||||
ck_assert(m.chunkMessage == m2.chunkMessage);
|
||||
ck_assert(m.payloadHeaderEnabled == m2.payloadHeaderEnabled);
|
||||
ck_assert_uint_eq(m2.payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0], dsWriter1);
|
||||
ck_assert_uint_eq(m2.payloadHeader.dataSetPayloadHeader.dataSetWriterIds[1], dsWriter2);
|
||||
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid == m2.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid);
|
||||
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding == m2.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding);
|
||||
ck_assert_int_eq(m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, fieldCountDS1);
|
||||
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue == m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue);
|
||||
ck_assert_uint_eq((uintptr_t)m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.type, (uintptr_t)&UA_TYPES[UA_TYPES_UINT32]);
|
||||
ck_assert_uint_eq(*(UA_UInt32 *)m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.data, iv);
|
||||
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasSourceTimestamp == m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasSourceTimestamp);
|
||||
|
||||
ck_assert(m.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageValid == m2.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageValid);
|
||||
ck_assert(m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue.hasSourceTimestamp == m2.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue.hasSourceTimestamp);
|
||||
UA_ByteString_deleteMembers(&buffer);
|
||||
UA_NetworkMessage_deleteMembers(&m);
|
||||
UA_NetworkMessage_deleteMembers(&m2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(UA_NetworkMessage_oneMessage_twoFields_json_decode) {
|
||||
// given
|
||||
UA_NetworkMessage out;
|
||||
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\",\"MessageType\":\"ua-data\",\"Messages\":[{\"DataSetWriterId\":62541,\"MetaDataVersion\":{\"MajorVersion\":1478393530,\"MinorVersion\":12345},\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"Type\":5,\"Body\":42},\"Server localtime\":{\"Type\":13,\"Body\":\"2018-06-05T05:58:36.000Z\"}}}]}");
|
||||
// when
|
||||
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&out, &buf);
|
||||
// then
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
//NetworkMessage
|
||||
ck_assert_int_eq(out.chunkMessage, false);
|
||||
ck_assert_int_eq(out.dataSetClassIdEnabled, false);
|
||||
ck_assert_int_eq(out.groupHeaderEnabled, false);
|
||||
ck_assert_int_eq(out.networkMessageType, UA_NETWORKMESSAGE_DATASET);
|
||||
ck_assert_int_eq(out.picosecondsEnabled, false);
|
||||
ck_assert_int_eq(out.promotedFieldsEnabled, false);
|
||||
ck_assert_int_eq(out.securityEnabled, false);
|
||||
ck_assert_int_eq(out.timestampEnabled, false);
|
||||
ck_assert_int_eq(out.publisherIdEnabled, false);
|
||||
|
||||
ck_assert_int_eq(out.payloadHeaderEnabled, true);
|
||||
ck_assert_int_eq(out.payloadHeader.dataSetPayloadHeader.count, 1);
|
||||
ck_assert_int_eq(out.payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0], 62541);
|
||||
|
||||
//dataSetMessage
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNrEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNr, 4711);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageType, UA_DATASETMESSAGE_DATAKEYFRAME);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding, UA_FIELDENCODING_VARIANT);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.picoSecondsIncluded, false);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMinorVersionEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersionEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMinorVersion, 12345);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersion, 1478393530);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNr, 4711);
|
||||
//ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetWriterId, 62541);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue, 1);
|
||||
ck_assert_int_eq(*((UA_UInt16*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.data), 42);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].hasValue, 1);
|
||||
UA_DateTime *dt = (UA_DateTime*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].value.data;
|
||||
UA_DateTimeStruct dts = UA_DateTime_toStruct(*dt);
|
||||
ck_assert_int_eq(dts.year, 2018);
|
||||
ck_assert_int_eq(dts.month, 6);
|
||||
ck_assert_int_eq(dts.day, 5);
|
||||
ck_assert_int_eq(dts.hour, 5);
|
||||
ck_assert_int_eq(dts.min, 58);
|
||||
ck_assert_int_eq(dts.sec, 36);
|
||||
ck_assert_int_eq(dts.milliSec, 0);
|
||||
ck_assert_int_eq(dts.microSec, 0);
|
||||
ck_assert_int_eq(dts.nanoSec, 0);
|
||||
|
||||
UA_NetworkMessage_deleteMembers(&out);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(UA_NetworkMessage_json_decode) {
|
||||
// given
|
||||
UA_NetworkMessage out;
|
||||
memset(&out,0,sizeof(UA_NetworkMessage));
|
||||
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\",\"MessageType\":\"ua-data\",\"Messages\":[{\"MetaDataVersion\":{\"MajorVersion\": 47, \"MinorVersion\": 47},\"DataSetWriterId\":62541,\"Status\":22,\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"Type\":5,\"Body\":42},\"Server localtime\":{\"Type\":1,\"Body\":true}}}]}");
|
||||
// when
|
||||
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&out, &buf);
|
||||
// then
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
//NetworkMessage
|
||||
ck_assert_int_eq(out.chunkMessage, false);
|
||||
ck_assert_int_eq(out.dataSetClassIdEnabled, false);
|
||||
ck_assert_int_eq(out.groupHeaderEnabled, false);
|
||||
ck_assert_int_eq(out.networkMessageType, UA_NETWORKMESSAGE_DATASET);
|
||||
ck_assert_int_eq(out.picosecondsEnabled, false);
|
||||
ck_assert_int_eq(out.promotedFieldsEnabled, false);
|
||||
ck_assert_int_eq(out.securityEnabled, false);
|
||||
ck_assert_int_eq(out.timestampEnabled, false);
|
||||
ck_assert_int_eq(out.publisherIdEnabled, false);
|
||||
|
||||
ck_assert_int_eq(out.payloadHeaderEnabled, true);
|
||||
ck_assert_int_eq(out.payloadHeader.dataSetPayloadHeader.count, 1);
|
||||
ck_assert_int_eq(out.payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0], 62541);
|
||||
|
||||
//dataSetMessage
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNrEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNr, 4711);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageType, UA_DATASETMESSAGE_DATAKEYFRAME);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding, UA_FIELDENCODING_VARIANT);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.picoSecondsIncluded, false);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.statusEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.status, 22);
|
||||
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMinorVersionEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersionEnabled, true);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMinorVersion, 47);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersion, 47);
|
||||
|
||||
//dataSetFields
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue, true);
|
||||
ck_assert_int_eq(*((UA_UInt16*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.data), 42);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].hasValue, true);
|
||||
ck_assert_int_eq(*((UA_Boolean*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].value.data), 1);
|
||||
|
||||
UA_NetworkMessage_deleteMembers(&out);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(UA_Networkmessage_DataSetFieldsNull_json_decode) {
|
||||
// given
|
||||
UA_NetworkMessage out;
|
||||
memset(&out, 0, sizeof(UA_NetworkMessage));
|
||||
UA_ByteString buf = UA_STRING("{ \"MessageId\": \"32235546-05d9-4fd7-97df-ea3ff3408574\", "
|
||||
"\"MessageType\": \"ua-data\", \"PublisherId\": \"MQTT-Localhost\", "
|
||||
"\"DataSetClassId\": \"00000005-cab9-4470-8f8a-2c1ead207e0e\", \"Messages\": "
|
||||
"[ { \"DataSetWriterId\": 1, \"SequenceNumber\": 224, \"MetaDataVersion\": "
|
||||
"{ \"MajorVersion\": 1, \"MinorVersion\": 1 },\"Payload\":null}]}");
|
||||
// when
|
||||
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&out, &buf);
|
||||
// then
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
ck_assert_int_eq(out.dataSetClassId.data1, 5);
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages->header.dataSetMessageSequenceNr, 224);
|
||||
ck_assert_ptr_eq(out.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields, NULL);
|
||||
|
||||
UA_NetworkMessage_deleteMembers(&out);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(UA_NetworkMessage_fieldNames_json_decode) {
|
||||
// given
|
||||
UA_NetworkMessage out;
|
||||
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\","
|
||||
"\"MessageType\":\"ua-data\",\"Messages\":"
|
||||
"[{\"DataSetWriterId\":62541,\"MetaDataVersion\":"
|
||||
"{\"MajorVersion\":1478393530,\"MinorVersion\":12345},"
|
||||
"\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"Type\":5,\"Body\":42},\"Test2\":"
|
||||
"{\"Type\":13,\"Body\":\"2018-06-05T05:58:36.000Z\"}}}]}");
|
||||
// when
|
||||
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&out, &buf);
|
||||
// then
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
//NetworkMessage
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[0], 'T');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[1], 'e');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[2], 's');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[3], 't');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[0], 'T');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[1], 'e');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[2], 's');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[3], 't');
|
||||
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[4], '2');
|
||||
|
||||
UA_NetworkMessage_deleteMembers(&out);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *testSuite_networkmessage(void) {
|
||||
Suite *s = suite_create("Built-in Data Types 62541-6 Json");
|
||||
TCase *tc_json_networkmessage = tcase_create("networkmessage_json");
|
||||
|
||||
tcase_add_test(tc_json_networkmessage, UA_PubSub_EnDecode);
|
||||
tcase_add_test(tc_json_networkmessage, UA_NetworkMessage_oneMessage_twoFields_json_decode);
|
||||
tcase_add_test(tc_json_networkmessage, UA_NetworkMessage_json_decode);
|
||||
tcase_add_test(tc_json_networkmessage, UA_Networkmessage_DataSetFieldsNull_json_decode);
|
||||
tcase_add_test(tc_json_networkmessage, UA_NetworkMessage_fieldNames_json_decode);
|
||||
|
||||
suite_add_tcase(s, tc_json_networkmessage);
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int number_failed = 0;
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
|
||||
s = testSuite_networkmessage();
|
||||
sr = srunner_create(s);
|
||||
srunner_set_fork_status(sr, CK_NOFORK);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed += srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
@ -24,3 +24,6 @@ BrokerConnectionTransportDataType
|
||||
BrokerWriterGroupTransportDataType
|
||||
BrokerDataSetWriterTransportDataType
|
||||
BrokerWriterGroupTransportType
|
||||
JsonDataSetWriterMessageDataType
|
||||
JsonDataSetMessageContentMask
|
||||
JsonNetworkMessageContentMask
|
||||
|
Loading…
Reference in New Issue
Block a user