#endif
#ifndef _SPARKPLUGLIB_H_
#define _SPARKPLUGLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
// Enable/disable debug messages
#define SPARKPLUG_DEBUG 1
#ifdef SPARKPLUG_DEBUG
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
#define DEBUG_PRINT(...) do {} while (0)
#endif
// Constants
#define DATA_SET_DATA_TYPE_UNKNOWN 0
#define DATA_SET_DATA_TYPE_INT8 1
#define DATA_SET_DATA_TYPE_INT16 2
#define DATA_SET_DATA_TYPE_INT32 3
#define DATA_SET_DATA_TYPE_INT64 4
#define DATA_SET_DATA_TYPE_UINT8 5
#define DATA_SET_DATA_TYPE_UINT16 6
#define DATA_SET_DATA_TYPE_UINT32 7
#define DATA_SET_DATA_TYPE_UINT64 8
#define DATA_SET_DATA_TYPE_FLOAT 9
#define DATA_SET_DATA_TYPE_DOUBLE 10
#define DATA_SET_DATA_TYPE_BOOLEAN 11
#define DATA_SET_DATA_TYPE_STRING 12
#define DATA_SET_DATA_TYPE_DATETIME 13
#define DATA_SET_DATA_TYPE_TEXT 14
#define METRIC_DATA_TYPE_UNKNOWN 0
#define METRIC_DATA_TYPE_INT8 1
#define METRIC_DATA_TYPE_INT16 2
#define METRIC_DATA_TYPE_INT32 3
#define METRIC_DATA_TYPE_INT64 4
#define METRIC_DATA_TYPE_UINT8 5
#define METRIC_DATA_TYPE_UINT16 6
#define METRIC_DATA_TYPE_UINT32 7
#define METRIC_DATA_TYPE_UINT64 8
#define METRIC_DATA_TYPE_FLOAT 9
#define METRIC_DATA_TYPE_DOUBLE 10
#define METRIC_DATA_TYPE_BOOLEAN 11
#define METRIC_DATA_TYPE_STRING 12
#define METRIC_DATA_TYPE_DATETIME 13
#define METRIC_DATA_TYPE_TEXT 14
#define METRIC_DATA_TYPE_UUID 15
#define METRIC_DATA_TYPE_DATASET 16
#define METRIC_DATA_TYPE_BYTES 17
#define METRIC_DATA_TYPE_FILE 18
#define METRIC_DATA_TYPE_TEMPLATE 19
#define PARAMETER_DATA_TYPE_UNKNOWN 0
#define PARAMETER_DATA_TYPE_INT8 1
#define PARAMETER_DATA_TYPE_INT16 2
#define PARAMETER_DATA_TYPE_INT32 3
#define PARAMETER_DATA_TYPE_INT64 4
#define PARAMETER_DATA_TYPE_UINT8 5
#define PARAMETER_DATA_TYPE_UINT16 6
#define PARAMETER_DATA_TYPE_UINT32 7
#define PARAMETER_DATA_TYPE_UINT64 8
#define PARAMETER_DATA_TYPE_FLOAT 9
#define PARAMETER_DATA_TYPE_DOUBLE 10
#define PARAMETER_DATA_TYPE_BOOLEAN 11
#define PARAMETER_DATA_TYPE_STRING 12
#define PARAMETER_DATA_TYPE_DATETIME 13
#define PARAMETER_DATA_TYPE_TEXT 14
#define PROPERTY_DATA_TYPE_UNKNOWN 0
#define PROPERTY_DATA_TYPE_INT8 1
#define PROPERTY_DATA_TYPE_INT16 2
#define PROPERTY_DATA_TYPE_INT32 3
#define PROPERTY_DATA_TYPE_INT64 4
#define PROPERTY_DATA_TYPE_UINT8 5
#define PROPERTY_DATA_TYPE_UINT16 6
#define PROPERTY_DATA_TYPE_UINT32 7
#define PROPERTY_DATA_TYPE_UINT64 8
#define PROPERTY_DATA_TYPE_FLOAT 9
#define PROPERTY_DATA_TYPE_DOUBLE 10
#define PROPERTY_DATA_TYPE_BOOLEAN 11
#define PROPERTY_DATA_TYPE_STRING 12
#define PROPERTY_DATA_TYPE_DATETIME 13
#define PROPERTY_DATA_TYPE_TEXT 14
/**
* Attach Metadata to an existing Metric.
*
* Caution: The metadata structure is duplicated via shallow copy, and
* it is expected that any pointers within it are safe to pass to free().
* This will happen if pb_release() is called on this structure or any
* structure referencing it, for example via a call to free_payload().
*
* @param metric Pointer to destination metric that metadata will be added to
* @param metadata Pointer to a source metadata structure that will be copied onto metric
*
* @return Returns >= 0 on success, or negative on failure
*/
int add_metadata_to_metric(org_eclipse_tahu_protobuf_Payload_Metric *metric,
org_eclipse_tahu_protobuf_Payload_MetaData *metadata);
/**
* Attach a Metric to an existing Payload.
*
*
Caution: The metric structure is duplicated via shallow
* copy, and it is expected that any pointers within it are safe
* to pass to free(). This will happen if pb_release() is called
* on this structure or any structure referencing it, for
* example via a call to free_payload().
*
* @param payload Pointer to the destination payload that metric will be added to
* @param metric Pointer to source metric structure that will be copied onto payload
*
* @return Returns >= 0 on success, or negative on failure
*/
int add_metric_to_payload(org_eclipse_tahu_protobuf_Payload *payload,
org_eclipse_tahu_protobuf_Payload_Metric *metric);
/**
* Helper function to properly cast and push a value into the propertyvalue data structure.
*
*
Mostly useful when directly building property structures.
*
* (No pointers passed into this function are retained by the target structure)
*
* @param propertyvalue
* Pointer to propertyvalue structure to receive the value
* @param datatype Datatype of the value being received (e.g. PROPERTY_DATA_TYPE_INT8)
* @param value Pointer to the value to use (cannot be NULL)
* @param size Size of the memory pointed to by value
*
* @return Returns >= 0 on success, or negative on failure
*/
int set_propertyvalue(org_eclipse_tahu_protobuf_Payload_PropertyValue *propertyvalue,
uint32_t datatype,
const void *value,
size_t size);
/**
* Add a simple Property to an existing PropertySet
*
* (No pointers passed into this function are retained by the target structure)
*
* @param propertyset
* Pointer to destination PropertySet that property will be added to
* @param key Pointer to null-terminated string giving name of new property
* @param type Datatype of new property value (e.g. PROPERTY_DATA_TYPE_INT8)
* @param value Pointer to value to use for new property, or NULL if reported property value should be NULL.
* @param size_of_value
* Size of data pointed to by value
*
* @return Returns >= 0 on success, or negative on failure
*/
int add_property_to_set(org_eclipse_tahu_protobuf_Payload_PropertySet *propertyset,
const char *key,
uint32_t type,
const void *value,
size_t size_of_value);
/**
* Add a PropertySet to an existing Metric
*
*
Caution: The propertyset structure is duplicated via shallow
* copy, and it is expected that any pointers within it are safe
* to pass to free(). This will happen if pb_release() is called
* on this structure or any structure referencing it, for
* example via a call to free_payload().
*
* @param metric Pointer to the destination metric that propertyset will be added to
* @param properties Pointer to source propertyset structure that will be copied onto metric
*
* @return Returns >= 0 on success, or negative on failure
*/
int add_propertyset_to_metric(org_eclipse_tahu_protobuf_Payload_Metric *metric,
org_eclipse_tahu_protobuf_Payload_PropertySet *properties);
/**
* Helper function to properly cast and push a value into the
* metric data structure.
*
*
Mostly useful when directly building metric structures.
*
*
Caution: When using datatype METRIC_DATA_TYPE_DATASET or
* METRIC_DATA_TYPE_TEMPLATE, the structure passed in via value
* is duplicated using a shallow copy, and it is expected that
* any pointers within it are safe to pass to free(). This will
* happen if pb_release() is called on the metric or any
* structure referencing it, for example via a call to
* free_payload().
*
* When using other datatype values, no pointers are retained by the metric.
*
* @param metric
* Pointer to metric structure to receive the
* value
* @param datatype Datatype of the value being received (e.g. PROPERTY_DATA_TYPE_INT8)
* @param value Pointer to the value to use (cannot be NULL)
* @param size Size of the memory pointed to by value
*
* @return Returns >= 0 on success, or negative on failure
*/
int set_metric_value(org_eclipse_tahu_protobuf_Payload_Metric *metric, uint32_t datatype, const void *value, size_t size);
/**
* Add a simple Metric to an existing Payload
*
*
Caution: When using datatype METRIC_DATA_TYPE_DATASET or
* METRIC_DATA_TYPE_TEMPLATE, the structure passed in via value
* is duplicated using a shallow copy, and it is expected that
* any pointers within it are safe to pass to free(). This will
* happen if pb_release() is called on the metric or any
* structure referencing it, for example via a call to
* free_payload().
*
* When using other datatype values, no pointers are retained by the metric.
*
* CAUTION: The underlying library will allocate memory as
* needed when building the structure. On success, it will be
* necessary to call free_payload() on the structure to release
* those allocations.
*
* @param payload Pointer to the destination payload that metric will be added to
* @param name Pointer to null-terminated string giving name of metric; may be NULL if not using name field on this metric
* @param has_alias Boolean indicating if the alias number should be included on the metric
* @param alias Alias number to use if has_alias is true
* @param datatype Datatype of the value (e.g. METRIC_DATA_TYPE_BOOLEAN)
* @param is_historical
* Boolean indicating if is_historical falg should be set on this metric
* @param is_transient
* Boolean if is_transient flag should be set on this metric
* @param value Pointer to value to use for metric; may be NULL if desired to set is_null flag and not include a value
* @param size_of_value
* Size of data pointed to by value
*
* @return Returns >= 0 on success, or negative on failure
*/
int add_simple_metric(org_eclipse_tahu_protobuf_Payload *payload,
const char *name,
bool has_alias,
uint64_t alias,
uint64_t datatype,
bool is_historical,
bool is_transient,
const void *value,
size_t size_of_value);
/**
* Encode a Payload into an array of bytes
*
* @param out_buffer Pointer to destination buffer to receive
* the encoded payload, or NULL if you just
* want to calculate the size of the encoded
* payload
* @param buffer_length
* Size of the destination buffer in bytes
* @param payload Pointer to the source payload structure
*
* @return Returns the size of the encoded payload in bytes on
* success, or -1 on failure
*/
ssize_t encode_payload(uint8_t *out_buffer,
size_t buffer_length,
const org_eclipse_tahu_protobuf_Payload *payload);
/**
* Build a payload structure from an encoded buffer
*
*
CAUTION: The underlying library will allocate memory as
* needed when building the structure. On success, it will be
* necessary to call free_payload() on the structure to release
* those allocations when done using it.
*
* @param payload Pointer to the destination structure to receive the payload;
* WARNING: any memory allocations referenced
* by the payload structure before it is passed
* into this function will be lost. They
* should be explicitly freed first if
* necessary.
* @param in_buffer Pointer to the buffer holding the encoded payload
* @param buffer_length
* Size of the incoming buffer
*
* @return Returns negative on failure, or number of bytes
* unused from buffer_length on success
*/
ssize_t decode_payload(org_eclipse_tahu_protobuf_Payload *payload,
const uint8_t *in_buffer,
size_t buffer_length);
/**
* Free memory from an existing Payload
*
*
This walks through the payload structure and any sub-structures it references, and frees all pointers as dynamic allocations.
*
*
This does NOT release the payload structure itself. It is up to the calling application to do that if necessary.
*
* @param payload Pointer to the Payload structure to release.
*
* @return Returns >= 0 on success, or negative on failure
*/
int free_payload(org_eclipse_tahu_protobuf_Payload *payload);
/**
* Get the current timestamp in milliseconds (format used inside SparkPlug payloads)
*
* @return The current timestamp in milliseconds since Jan 1, 1970 UTC.
*/
uint64_t get_current_timestamp(void);
/**
* Reset the sequence number to 0.
*
* This should be used just before starting a new NBIRTH message.
*/
void reset_sparkplug_sequence(void);
/**
* Get the next empty Payload.
*
*
This does the initial payload setup including the timestamp and sequence number.
*
* @param payload Pointer to the destination payload structure to setup;
* WARNING: any memory allocations referenced
* by the payload structure before it is passed
* into this function will be lost. They
* should be explicitly freed first if
* necessary.
*
* @return Returns >= 0 on success, or negative on failure
*/
int get_next_payload(org_eclipse_tahu_protobuf_Payload *payload);
/**
* Initialize a Dataset with the values passed in
*
*
Caution: The row value structures are duplicated via
* shallow copy, and it is expected that any pointers within
* them are safe to pass to free(). This will happen if
* pb_release() is called on this structure or any structure
* referencing it, for example via a call to free_payload().
*
* @param dataset Pointer to dataset to initialize
* WARNING: any memory allocations referenced
* by the dataset structure before it is passed
* into this function will be lost. They
* should be explicitly freed first if
* necessary.
* @param num_of_rows
* Number of rows in the dataset
* @param num_of_columns
* Number of columns in the dataset
* @param datatypes Array of datatypes, one per column (e.g. DATA_SET_DATA_TYPE_INT8)
* @param column_keys
* Array of pointers to null-terminated strings
* giving names for each column (these strings
* are copied into new allocations)
* @param row_data Array of row value structures
*
* @return Returns >= 0 on success, or negative on failure
*/
int init_dataset(org_eclipse_tahu_protobuf_Payload_DataSet *dataset,
uint64_t num_of_rows,
uint64_t num_of_columns,
const uint32_t datatypes[],
const char *column_keys[],
const org_eclipse_tahu_protobuf_Payload_DataSet_Row row_data[]);
/**
* Initialize a Metric with the values of the arguments passed in
*
*
Caution: When using datatype METRIC_DATA_TYPE_DATASET or
* METRIC_DATA_TYPE_TEMPLATE, the structure passed in via value
* is duplicated using a shallow copy, and it is expected that
* any pointers within it are safe to pass to free(). This will
* happen if pb_release() is called on the metric or any
* structure referencing it, for example via a call to
* free_payload().
*
*
When using other datatype values, no pointers are retained by the metric.
*
*
CAUTION: The underlying library will allocate memory as
* needed when building the structure. On success, it will be
* necessary to call free_payload() on the structure to release
* those allocations.
*
* @param metric Pointer to the metric data structure to initialize;
* WARNING: any memory allocations referenced
* by the metric structure before it is passed
* into this function will be lost. They
* should be explicitly freed first if
* necessary.
* @param name Pointer to null-terminated string giving name of metric; may be NULL if not using name field on this metric
* @param has_alias Boolean indicating if the alias number should be included on the metric
* @param alias Alias number to use if has_alias is true
* @param datatype Datatype of the value (e.g. METRIC_DATA_TYPE_BOOLEAN)
* @param is_historical
* Boolean indicating if is_historical falg should be set on this metric
* @param is_transient
* Boolean if is_transient flag should be set on this metric
* @param value Pointer to value to use for metric; may be NULL if desired to set is_null flag and not include a value
* @param size_of_value
* Size of data pointed to by value
*
* @return Returns >= 0 on success, or negative on failure
*/
int init_metric(org_eclipse_tahu_protobuf_Payload_Metric *metric,
const char *name,
bool has_alias,
uint64_t alias,
uint64_t datatype,
bool is_historical,
bool is_transient,
const void *value,
size_t size_of_value);
/**
* Display a full Sparkplug Payload
*
* @param payload Pointer to the payload structure to display
*/
void print_payload(org_eclipse_tahu_protobuf_Payload *payload);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
================================================
FILE: c/core/include/tahu.pb.h
================================================
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.1 */
#ifndef PB_ORG_ECLIPSE_TAHU_PROTOBUF_TAHU_PB_H_INCLUDED
#define PB_ORG_ECLIPSE_TAHU_PROTOBUF_TAHU_PB_H_INCLUDED
#include
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Struct definitions */
typedef struct _org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension {
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension;
typedef struct _org_eclipse_tahu_protobuf_Payload_DataSet_Row {
pb_size_t elements_count;
struct _org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *elements;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_DataSet_Row;
typedef struct _org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension {
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension;
typedef struct _org_eclipse_tahu_protobuf_Payload_PropertySet {
pb_size_t keys_count;
char **keys;
pb_size_t values_count;
struct _org_eclipse_tahu_protobuf_Payload_PropertyValue *values;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_PropertySet;
typedef struct _org_eclipse_tahu_protobuf_Payload_PropertySetList {
pb_size_t propertyset_count;
struct _org_eclipse_tahu_protobuf_Payload_PropertySet *propertyset;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_PropertySetList;
typedef struct _org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension {
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension;
typedef struct _org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension {
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension;
typedef struct _org_eclipse_tahu_protobuf_Payload {
bool has_timestamp;
uint64_t timestamp;
pb_size_t metrics_count;
struct _org_eclipse_tahu_protobuf_Payload_Metric *metrics;
bool has_seq;
uint64_t seq;
char *uuid;
pb_bytes_array_t *body;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload;
typedef struct _org_eclipse_tahu_protobuf_Payload_DataSet {
bool has_num_of_columns;
uint64_t num_of_columns;
pb_size_t columns_count;
char **columns;
pb_size_t types_count;
uint32_t *types;
pb_size_t rows_count;
struct _org_eclipse_tahu_protobuf_Payload_DataSet_Row *rows;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_DataSet;
typedef struct _org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue {
pb_size_t which_value;
union {
uint32_t int_value;
uint64_t long_value;
float float_value;
double double_value;
bool boolean_value;
char *string_value;
org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension extension_value;
} value;
} org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue;
typedef struct _org_eclipse_tahu_protobuf_Payload_MetaData {
bool has_is_multi_part;
bool is_multi_part;
char *content_type;
bool has_size;
uint64_t size;
bool has_seq;
uint64_t seq;
char *file_name;
char *file_type;
char *md5;
char *description;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_MetaData;
typedef struct _org_eclipse_tahu_protobuf_Payload_PropertyValue {
bool has_type;
uint32_t type;
bool has_is_null;
bool is_null;
pb_size_t which_value;
union {
uint32_t int_value;
uint64_t long_value;
float float_value;
double double_value;
bool boolean_value;
char *string_value;
org_eclipse_tahu_protobuf_Payload_PropertySet propertyset_value;
org_eclipse_tahu_protobuf_Payload_PropertySetList propertysets_value;
org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension extension_value;
} value;
} org_eclipse_tahu_protobuf_Payload_PropertyValue;
typedef struct _org_eclipse_tahu_protobuf_Payload_Template {
char *version;
pb_size_t metrics_count;
struct _org_eclipse_tahu_protobuf_Payload_Metric *metrics;
pb_size_t parameters_count;
struct _org_eclipse_tahu_protobuf_Payload_Template_Parameter *parameters;
char *template_ref;
bool has_is_definition;
bool is_definition;
pb_extension_t *extensions;
} org_eclipse_tahu_protobuf_Payload_Template;
typedef struct _org_eclipse_tahu_protobuf_Payload_Template_Parameter {
char *name;
bool has_type;
uint32_t type;
pb_size_t which_value;
union {
uint32_t int_value;
uint64_t long_value;
float float_value;
double double_value;
bool boolean_value;
char *string_value;
org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension extension_value;
} value;
} org_eclipse_tahu_protobuf_Payload_Template_Parameter;
typedef struct _org_eclipse_tahu_protobuf_Payload_Metric {
char *name;
bool has_alias;
uint64_t alias;
bool has_timestamp;
uint64_t timestamp;
bool has_datatype;
uint32_t datatype;
bool has_is_historical;
bool is_historical;
bool has_is_transient;
bool is_transient;
bool has_is_null;
bool is_null;
bool has_metadata;
org_eclipse_tahu_protobuf_Payload_MetaData metadata;
bool has_properties;
org_eclipse_tahu_protobuf_Payload_PropertySet properties;
pb_size_t which_value;
union {
uint32_t int_value;
uint64_t long_value;
float float_value;
double double_value;
bool boolean_value;
char *string_value;
pb_bytes_array_t *bytes_value;
org_eclipse_tahu_protobuf_Payload_DataSet dataset_value;
org_eclipse_tahu_protobuf_Payload_Template template_value;
org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension extension_value;
} value;
} org_eclipse_tahu_protobuf_Payload_Metric;
/* Initializer values for message structs */
#define org_eclipse_tahu_protobuf_Payload_init_default {false, 0, 0, NULL, false, 0, NULL, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_Template_init_default {NULL, 0, NULL, 0, NULL, NULL, false, 0, NULL}
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default {NULL, false, 0, 0, {0}}
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_init_default {NULL}
#define org_eclipse_tahu_protobuf_Payload_DataSet_init_default {false, 0, 0, NULL, 0, NULL, 0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_init_default {0, {0}}
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_init_default {NULL}
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_init_default {0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_init_default {false, 0, false, 0, 0, {0}}
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_init_default {NULL}
#define org_eclipse_tahu_protobuf_Payload_PropertySet_init_default {0, NULL, 0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_init_default {0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_MetaData_init_default {false, 0, NULL, false, 0, false, 0, NULL, NULL, NULL, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_Metric_init_default {NULL, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, org_eclipse_tahu_protobuf_Payload_MetaData_init_default, false, org_eclipse_tahu_protobuf_Payload_PropertySet_init_default, 0, {0}}
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_init_default {NULL}
#define org_eclipse_tahu_protobuf_Payload_init_zero {false, 0, 0, NULL, false, 0, NULL, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_Template_init_zero {NULL, 0, NULL, 0, NULL, NULL, false, 0, NULL}
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_zero {NULL, false, 0, 0, {0}}
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_init_zero {NULL}
#define org_eclipse_tahu_protobuf_Payload_DataSet_init_zero {false, 0, 0, NULL, 0, NULL, 0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_init_zero {0, {0}}
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_init_zero {NULL}
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_init_zero {0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_init_zero {false, 0, false, 0, 0, {0}}
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_init_zero {NULL}
#define org_eclipse_tahu_protobuf_Payload_PropertySet_init_zero {0, NULL, 0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_init_zero {0, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_MetaData_init_zero {false, 0, NULL, false, 0, false, 0, NULL, NULL, NULL, NULL, NULL}
#define org_eclipse_tahu_protobuf_Payload_Metric_init_zero {NULL, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, org_eclipse_tahu_protobuf_Payload_MetaData_init_zero, false, org_eclipse_tahu_protobuf_Payload_PropertySet_init_zero, 0, {0}}
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_init_zero {NULL}
/* Field tags (for use in manual encoding/decoding) */
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_elements_tag 1
#define org_eclipse_tahu_protobuf_Payload_PropertySet_keys_tag 1
#define org_eclipse_tahu_protobuf_Payload_PropertySet_values_tag 2
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_propertyset_tag 1
#define org_eclipse_tahu_protobuf_Payload_timestamp_tag 1
#define org_eclipse_tahu_protobuf_Payload_metrics_tag 2
#define org_eclipse_tahu_protobuf_Payload_seq_tag 3
#define org_eclipse_tahu_protobuf_Payload_uuid_tag 4
#define org_eclipse_tahu_protobuf_Payload_body_tag 5
#define org_eclipse_tahu_protobuf_Payload_DataSet_num_of_columns_tag 1
#define org_eclipse_tahu_protobuf_Payload_DataSet_columns_tag 2
#define org_eclipse_tahu_protobuf_Payload_DataSet_types_tag 3
#define org_eclipse_tahu_protobuf_Payload_DataSet_rows_tag 4
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag 1
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_long_value_tag 2
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_float_value_tag 3
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_double_value_tag 4
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_boolean_value_tag 5
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_string_value_tag 6
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_extension_value_tag 7
#define org_eclipse_tahu_protobuf_Payload_MetaData_is_multi_part_tag 1
#define org_eclipse_tahu_protobuf_Payload_MetaData_content_type_tag 2
#define org_eclipse_tahu_protobuf_Payload_MetaData_size_tag 3
#define org_eclipse_tahu_protobuf_Payload_MetaData_seq_tag 4
#define org_eclipse_tahu_protobuf_Payload_MetaData_file_name_tag 5
#define org_eclipse_tahu_protobuf_Payload_MetaData_file_type_tag 6
#define org_eclipse_tahu_protobuf_Payload_MetaData_md5_tag 7
#define org_eclipse_tahu_protobuf_Payload_MetaData_description_tag 8
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag 3
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_long_value_tag 4
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_float_value_tag 5
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_double_value_tag 6
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_boolean_value_tag 7
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_string_value_tag 8
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_propertyset_value_tag 9
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_propertysets_value_tag 10
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_extension_value_tag 11
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_type_tag 1
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_is_null_tag 2
#define org_eclipse_tahu_protobuf_Payload_Template_version_tag 1
#define org_eclipse_tahu_protobuf_Payload_Template_metrics_tag 2
#define org_eclipse_tahu_protobuf_Payload_Template_parameters_tag 3
#define org_eclipse_tahu_protobuf_Payload_Template_template_ref_tag 4
#define org_eclipse_tahu_protobuf_Payload_Template_is_definition_tag 5
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_int_value_tag 3
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_long_value_tag 4
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_float_value_tag 5
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_double_value_tag 6
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_boolean_value_tag 7
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag 8
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_extension_value_tag 9
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_name_tag 1
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_type_tag 2
#define org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag 10
#define org_eclipse_tahu_protobuf_Payload_Metric_long_value_tag 11
#define org_eclipse_tahu_protobuf_Payload_Metric_float_value_tag 12
#define org_eclipse_tahu_protobuf_Payload_Metric_double_value_tag 13
#define org_eclipse_tahu_protobuf_Payload_Metric_boolean_value_tag 14
#define org_eclipse_tahu_protobuf_Payload_Metric_string_value_tag 15
#define org_eclipse_tahu_protobuf_Payload_Metric_bytes_value_tag 16
#define org_eclipse_tahu_protobuf_Payload_Metric_dataset_value_tag 17
#define org_eclipse_tahu_protobuf_Payload_Metric_template_value_tag 18
#define org_eclipse_tahu_protobuf_Payload_Metric_extension_value_tag 19
#define org_eclipse_tahu_protobuf_Payload_Metric_name_tag 1
#define org_eclipse_tahu_protobuf_Payload_Metric_alias_tag 2
#define org_eclipse_tahu_protobuf_Payload_Metric_timestamp_tag 3
#define org_eclipse_tahu_protobuf_Payload_Metric_datatype_tag 4
#define org_eclipse_tahu_protobuf_Payload_Metric_is_historical_tag 5
#define org_eclipse_tahu_protobuf_Payload_Metric_is_transient_tag 6
#define org_eclipse_tahu_protobuf_Payload_Metric_is_null_tag 7
#define org_eclipse_tahu_protobuf_Payload_Metric_metadata_tag 8
#define org_eclipse_tahu_protobuf_Payload_Metric_properties_tag 9
/* Struct field encoding specification for nanopb */
#define org_eclipse_tahu_protobuf_Payload_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, UINT64, timestamp, 1) \
X(a, POINTER, REPEATED, MESSAGE, metrics, 2) \
X(a, STATIC, OPTIONAL, UINT64, seq, 3) \
X(a, POINTER, OPTIONAL, STRING, uuid, 4) \
X(a, POINTER, OPTIONAL, BYTES, body, 5) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 6)
#define org_eclipse_tahu_protobuf_Payload_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_metrics_MSGTYPE org_eclipse_tahu_protobuf_Payload_Metric
#define org_eclipse_tahu_protobuf_Payload_Template_FIELDLIST(X, a) \
X(a, POINTER, OPTIONAL, STRING, version, 1) \
X(a, POINTER, REPEATED, MESSAGE, metrics, 2) \
X(a, POINTER, REPEATED, MESSAGE, parameters, 3) \
X(a, POINTER, OPTIONAL, STRING, template_ref, 4) \
X(a, STATIC, OPTIONAL, BOOL, is_definition, 5) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 6)
#define org_eclipse_tahu_protobuf_Payload_Template_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_Template_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_Template_metrics_MSGTYPE org_eclipse_tahu_protobuf_Payload_Metric
#define org_eclipse_tahu_protobuf_Payload_Template_parameters_MSGTYPE org_eclipse_tahu_protobuf_Payload_Template_Parameter
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_FIELDLIST(X, a) \
X(a, POINTER, OPTIONAL, STRING, name, 1) \
X(a, STATIC, OPTIONAL, UINT32, type, 2) \
X(a, STATIC, ONEOF, UINT32, (value,int_value,value.int_value), 3) \
X(a, STATIC, ONEOF, UINT64, (value,long_value,value.long_value), 4) \
X(a, STATIC, ONEOF, FLOAT, (value,float_value,value.float_value), 5) \
X(a, STATIC, ONEOF, DOUBLE, (value,double_value,value.double_value), 6) \
X(a, STATIC, ONEOF, BOOL, (value,boolean_value,value.boolean_value), 7) \
X(a, POINTER, ONEOF, STRING, (value,string_value,value.string_value), 8) \
X(a, STATIC, ONEOF, MESSAGE, (value,extension_value,value.extension_value), 9)
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_CALLBACK NULL
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_value_extension_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_FIELDLIST(X, a) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 1)
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_DataSet_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, UINT64, num_of_columns, 1) \
X(a, POINTER, REPEATED, STRING, columns, 2) \
X(a, POINTER, REPEATED, UINT32, types, 3) \
X(a, POINTER, REPEATED, MESSAGE, rows, 4) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 5)
#define org_eclipse_tahu_protobuf_Payload_DataSet_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_DataSet_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_DataSet_rows_MSGTYPE org_eclipse_tahu_protobuf_Payload_DataSet_Row
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, UINT32, (value,int_value,value.int_value), 1) \
X(a, STATIC, ONEOF, UINT64, (value,long_value,value.long_value), 2) \
X(a, STATIC, ONEOF, FLOAT, (value,float_value,value.float_value), 3) \
X(a, STATIC, ONEOF, DOUBLE, (value,double_value,value.double_value), 4) \
X(a, STATIC, ONEOF, BOOL, (value,boolean_value,value.boolean_value), 5) \
X(a, POINTER, ONEOF, STRING, (value,string_value,value.string_value), 6) \
X(a, STATIC, ONEOF, MESSAGE, (value,extension_value,value.extension_value), 7)
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_CALLBACK NULL
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_value_extension_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_FIELDLIST(X, a) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 1)
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_FIELDLIST(X, a) \
X(a, POINTER, REPEATED, MESSAGE, elements, 1) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 2)
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_elements_MSGTYPE org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, UINT32, type, 1) \
X(a, STATIC, OPTIONAL, BOOL, is_null, 2) \
X(a, STATIC, ONEOF, UINT32, (value,int_value,value.int_value), 3) \
X(a, STATIC, ONEOF, UINT64, (value,long_value,value.long_value), 4) \
X(a, STATIC, ONEOF, FLOAT, (value,float_value,value.float_value), 5) \
X(a, STATIC, ONEOF, DOUBLE, (value,double_value,value.double_value), 6) \
X(a, STATIC, ONEOF, BOOL, (value,boolean_value,value.boolean_value), 7) \
X(a, POINTER, ONEOF, STRING, (value,string_value,value.string_value), 8) \
X(a, STATIC, ONEOF, MESSAGE, (value,propertyset_value,value.propertyset_value), 9) \
X(a, STATIC, ONEOF, MESSAGE, (value,propertysets_value,value.propertysets_value), 10) \
X(a, STATIC, ONEOF, MESSAGE, (value,extension_value,value.extension_value), 11)
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_CALLBACK NULL
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_value_propertyset_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_PropertySet
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_value_propertysets_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_PropertySetList
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_value_extension_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_FIELDLIST(X, a) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 1)
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_PropertySet_FIELDLIST(X, a) \
X(a, POINTER, REPEATED, STRING, keys, 1) \
X(a, POINTER, REPEATED, MESSAGE, values, 2) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 3)
#define org_eclipse_tahu_protobuf_Payload_PropertySet_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_PropertySet_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_PropertySet_values_MSGTYPE org_eclipse_tahu_protobuf_Payload_PropertyValue
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_FIELDLIST(X, a) \
X(a, POINTER, REPEATED, MESSAGE, propertyset, 1) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 2)
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_propertyset_MSGTYPE org_eclipse_tahu_protobuf_Payload_PropertySet
#define org_eclipse_tahu_protobuf_Payload_MetaData_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, BOOL, is_multi_part, 1) \
X(a, POINTER, OPTIONAL, STRING, content_type, 2) \
X(a, STATIC, OPTIONAL, UINT64, size, 3) \
X(a, STATIC, OPTIONAL, UINT64, seq, 4) \
X(a, POINTER, OPTIONAL, STRING, file_name, 5) \
X(a, POINTER, OPTIONAL, STRING, file_type, 6) \
X(a, POINTER, OPTIONAL, STRING, md5, 7) \
X(a, POINTER, OPTIONAL, STRING, description, 8) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 9)
#define org_eclipse_tahu_protobuf_Payload_MetaData_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_MetaData_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_Metric_FIELDLIST(X, a) \
X(a, POINTER, OPTIONAL, STRING, name, 1) \
X(a, STATIC, OPTIONAL, UINT64, alias, 2) \
X(a, STATIC, OPTIONAL, UINT64, timestamp, 3) \
X(a, STATIC, OPTIONAL, UINT32, datatype, 4) \
X(a, STATIC, OPTIONAL, BOOL, is_historical, 5) \
X(a, STATIC, OPTIONAL, BOOL, is_transient, 6) \
X(a, STATIC, OPTIONAL, BOOL, is_null, 7) \
X(a, STATIC, OPTIONAL, MESSAGE, metadata, 8) \
X(a, STATIC, OPTIONAL, MESSAGE, properties, 9) \
X(a, STATIC, ONEOF, UINT32, (value,int_value,value.int_value), 10) \
X(a, STATIC, ONEOF, UINT64, (value,long_value,value.long_value), 11) \
X(a, STATIC, ONEOF, FLOAT, (value,float_value,value.float_value), 12) \
X(a, STATIC, ONEOF, DOUBLE, (value,double_value,value.double_value), 13) \
X(a, STATIC, ONEOF, BOOL, (value,boolean_value,value.boolean_value), 14) \
X(a, POINTER, ONEOF, STRING, (value,string_value,value.string_value), 15) \
X(a, POINTER, ONEOF, BYTES, (value,bytes_value,value.bytes_value), 16) \
X(a, STATIC, ONEOF, MESSAGE, (value,dataset_value,value.dataset_value), 17) \
X(a, STATIC, ONEOF, MESSAGE, (value,template_value,value.template_value), 18) \
X(a, STATIC, ONEOF, MESSAGE, (value,extension_value,value.extension_value), 19)
#define org_eclipse_tahu_protobuf_Payload_Metric_CALLBACK NULL
#define org_eclipse_tahu_protobuf_Payload_Metric_DEFAULT NULL
#define org_eclipse_tahu_protobuf_Payload_Metric_metadata_MSGTYPE org_eclipse_tahu_protobuf_Payload_MetaData
#define org_eclipse_tahu_protobuf_Payload_Metric_properties_MSGTYPE org_eclipse_tahu_protobuf_Payload_PropertySet
#define org_eclipse_tahu_protobuf_Payload_Metric_value_dataset_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_DataSet
#define org_eclipse_tahu_protobuf_Payload_Metric_value_template_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_Template
#define org_eclipse_tahu_protobuf_Payload_Metric_value_extension_value_MSGTYPE org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_FIELDLIST(X, a) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 1)
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_CALLBACK pb_default_field_callback
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_DEFAULT NULL
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_Template_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_Template_Parameter_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_DataSet_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_DataSet_Row_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_PropertyValue_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_PropertySet_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_PropertySetList_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_MetaData_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_Metric_msg;
extern const pb_msgdesc_t org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define org_eclipse_tahu_protobuf_Payload_fields &org_eclipse_tahu_protobuf_Payload_msg
#define org_eclipse_tahu_protobuf_Payload_Template_fields &org_eclipse_tahu_protobuf_Payload_Template_msg
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_fields &org_eclipse_tahu_protobuf_Payload_Template_Parameter_msg
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_fields &org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_msg
#define org_eclipse_tahu_protobuf_Payload_DataSet_fields &org_eclipse_tahu_protobuf_Payload_DataSet_msg
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_fields &org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_msg
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_fields &org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_msg
#define org_eclipse_tahu_protobuf_Payload_DataSet_Row_fields &org_eclipse_tahu_protobuf_Payload_DataSet_Row_msg
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_fields &org_eclipse_tahu_protobuf_Payload_PropertyValue_msg
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_fields &org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_msg
#define org_eclipse_tahu_protobuf_Payload_PropertySet_fields &org_eclipse_tahu_protobuf_Payload_PropertySet_msg
#define org_eclipse_tahu_protobuf_Payload_PropertySetList_fields &org_eclipse_tahu_protobuf_Payload_PropertySetList_msg
#define org_eclipse_tahu_protobuf_Payload_MetaData_fields &org_eclipse_tahu_protobuf_Payload_MetaData_msg
#define org_eclipse_tahu_protobuf_Payload_Metric_fields &org_eclipse_tahu_protobuf_Payload_Metric_msg
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_fields &org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_msg
/* Maximum encoded size of messages (where known) */
/* org_eclipse_tahu_protobuf_Payload_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_Template_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_Template_Parameter_size depends on runtime parameters */
#define org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension_size 0
/* org_eclipse_tahu_protobuf_Payload_DataSet_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_size depends on runtime parameters */
#define org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension_size 0
/* org_eclipse_tahu_protobuf_Payload_DataSet_Row_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_PropertyValue_size depends on runtime parameters */
#define org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension_size 0
/* org_eclipse_tahu_protobuf_Payload_PropertySet_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_PropertySetList_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_MetaData_size depends on runtime parameters */
/* org_eclipse_tahu_protobuf_Payload_Metric_size depends on runtime parameters */
#define org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension_size 0
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
================================================
FILE: c/core/readme.txt
================================================
#/********************************************************************************
# * Copyright (c) 2014-2019 Cirrus Link Solutions and others
# *
# * This program and the accompanying materials are made available under the
# * terms of the Eclipse Public License 2.0 which is available at
# * http://www.eclipse.org/legal/epl-2.0.
# *
# * SPDX-License-Identifier: EPL-2.0
# *
# * Contributors:
# * Cirrus Link Solutions - initial implementation
# ********************************************************************************/
# To generate the base protobuf tahu NanoPB C library (using Protoc v2.6.1 and Nanopb v0.3.5)
protoc --proto_path=../../ -otahu.pb ../../sparkplug_b/sparkplug_b.proto
~/nanopb/nanopb-0.3.5-linux-x86/generator/nanopb_generator.py -f tahu.options tahu.pb
mv tahu.pb src/
mv tahu.pb.c src/
mv tahu.pb.h include/
================================================
FILE: c/core/src/pb_common.c
================================================
/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
*
* 2014 Petteri Aimonen
*/
#include "pb_common.h"
static bool load_descriptor_values(pb_field_iter_t *iter)
{
uint32_t word0;
uint32_t data_offset;
uint_least8_t format;
int_least8_t size_offset;
if (iter->index >= iter->descriptor->field_count)
return false;
word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
format = word0 & 3;
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
if (format == 0)
{
/* 1-word format */
iter->array_size = 1;
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
data_offset = (word0 >> 16) & 0xFF;
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
}
else if (format == 1)
{
/* 2-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6));
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
data_offset = word1 & 0xFFFF;
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
}
else if (format == 2)
{
/* 4-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
iter->array_size = (pb_size_t)(word0 >> 16);
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
}
else
{
/* 8-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
iter->array_size = (pb_size_t)word4;
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
}
iter->pField = (char*)iter->message + data_offset;
if (size_offset)
{
iter->pSize = (char*)iter->pField - size_offset;
}
else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
(PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
{
/* Fixed count array */
iter->pSize = &iter->array_size;
}
else
{
iter->pSize = NULL;
}
if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
{
iter->pData = *(void**)iter->pField;
}
else
{
iter->pData = iter->pField;
}
if (PB_LTYPE_IS_SUBMSG(iter->type))
{
iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
}
else
{
iter->submsg_desc = NULL;
}
return true;
}
static void advance_iterator(pb_field_iter_t *iter)
{
iter->index++;
if (iter->index >= iter->descriptor->field_count)
{
/* Restart */
iter->index = 0;
iter->field_info_index = 0;
iter->submessage_index = 0;
iter->required_field_index = 0;
}
else
{
/* Increment indexes based on previous field type.
* All field info formats have the following fields:
* - lowest 2 bits tell the amount of words in the descriptor (2^n words)
* - bits 2..7 give the lowest bits of tag number.
* - bits 8..15 give the field type.
*/
uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
if (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED)
{
iter->required_field_index++;
}
if (PB_LTYPE_IS_SUBMSG(prev_type))
{
iter->submessage_index++;
}
}
}
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
{
memset(iter, 0, sizeof(*iter));
iter->descriptor = desc;
iter->message = message;
return load_descriptor_values(iter);
}
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
{
const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
bool status;
uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
{
/* For pointer extensions, the pointer is stored directly
* in the extension structure. This avoids having an extra
* indirection. */
status = pb_field_iter_begin(iter, msg, &extension->dest);
}
else
{
status = pb_field_iter_begin(iter, msg, extension->dest);
}
iter->pSize = &extension->found;
return status;
}
bool pb_field_iter_next(pb_field_iter_t *iter)
{
advance_iterator(iter);
(void)load_descriptor_values(iter);
return iter->index != 0;
}
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
{
if (iter->tag == tag)
{
return true; /* Nothing to do, correct field already. */
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for tag number match */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
{
/* Good candidate, check further */
(void)load_descriptor_values(iter);
if (iter->tag == tag &&
PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
{
/* Found it */
return true;
}
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
static void *pb_const_cast(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator
* logic for both encoding and decoding. The cast is done using union
* to avoid spurious compiler warnings. */
union {
void *p1;
const void *p2;
} t;
t.p2 = p;
return t.p1;
}
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
{
return pb_field_iter_begin(iter, desc, pb_const_cast(message));
}
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
{
return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
}
bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (field->data_size == sizeof(pb_callback_t))
{
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
if (pCallback != NULL)
{
if (istream != NULL && pCallback->funcs.decode != NULL)
{
return pCallback->funcs.decode(istream, field, &pCallback->arg);
}
if (ostream != NULL && pCallback->funcs.encode != NULL)
{
return pCallback->funcs.encode(ostream, field, &pCallback->arg);
}
}
}
return true; /* Success, but didn't do anything */
}
#ifdef PB_VALIDATE_UTF8
/* This function checks whether a string is valid UTF-8 text.
*
* Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
* Original copyright: Markus Kuhn 2005-03-30
* Licensed under "Short code license", which allows use under MIT license or
* any compatible with it.
*/
bool pb_validate_utf8(const char *str)
{
const pb_byte_t *s = (const pb_byte_t*)str;
while (*s)
{
if (*s < 0x80)
{
/* 0xxxxxxx */
s++;
}
else if ((s[0] & 0xe0) == 0xc0)
{
/* 110XXXXx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[0] & 0xfe) == 0xc0) /* overlong? */
return false;
else
s += 2;
}
else if ((s[0] & 0xf0) == 0xe0)
{
/* 1110XXXX 10Xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
(s[0] == 0xef && s[1] == 0xbf &&
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
return false;
else
s += 3;
}
else if ((s[0] & 0xf8) == 0xf0)
{
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[3] & 0xc0) != 0x80 ||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
return false;
else
s += 4;
}
else
{
return false;
}
}
return true;
}
#endif
================================================
FILE: c/core/src/pb_decode.c
================================================
/* pb_decode.c -- decode a protobuf using minimal resources
*
* 2011 Petteri Aimonen
*/
/* Use the GCC warn_unused_result attribute to check that all return values
* are propagated correctly. On other compilers and gcc before 3.4.0 just
* ignore the annotation.
*/
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
#define checkreturn
#else
#define checkreturn __attribute__((warn_unused_result))
#endif
#include "pb.h"
#include "pb_decode.h"
#include "pb_common.h"
/**************************************
* Declarations internal to this file *
**************************************/
static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof);
static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field);
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);
static bool checkreturn find_extension_field(pb_field_iter_t *iter);
static bool pb_message_set_to_defaults(pb_field_iter_t *iter);
static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_skip_varint(pb_istream_t *stream);
static bool checkreturn pb_skip_string(pb_istream_t *stream);
#ifdef PB_ENABLE_MALLOC
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);
static void initialize_pointer_field(void *pItem, pb_field_iter_t *field);
static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field);
static void pb_release_single_field(pb_field_iter_t *field);
#endif
#ifdef PB_WITHOUT_64BIT
#define pb_int64_t int32_t
#define pb_uint64_t uint32_t
#else
#define pb_int64_t int64_t
#define pb_uint64_t uint64_t
#endif
typedef struct {
uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32];
} pb_fields_seen_t;
/*******************************
* pb_istream_t implementation *
*******************************/
static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
size_t i;
const pb_byte_t *source = (const pb_byte_t*)stream->state;
stream->state = (pb_byte_t*)stream->state + count;
if (buf != NULL)
{
for (i = 0; i < count; i++)
buf[i] = source[i];
}
return true;
}
bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
if (count == 0)
return true;
#ifndef PB_BUFFER_ONLY
if (buf == NULL && stream->callback != buf_read)
{
/* Skip input bytes */
pb_byte_t tmp[16];
while (count > 16)
{
if (!pb_read(stream, tmp, 16))
return false;
count -= 16;
}
return pb_read(stream, tmp, count);
}
#endif
if (stream->bytes_left < count)
PB_RETURN_ERROR(stream, "end-of-stream");
#ifndef PB_BUFFER_ONLY
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#else
if (!buf_read(stream, buf, count))
return false;
#endif
stream->bytes_left -= count;
return true;
}
/* Read a single byte from input stream. buf may not be NULL.
* This is an optimization for the varint decoding. */
static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf)
{
if (stream->bytes_left == 0)
PB_RETURN_ERROR(stream, "end-of-stream");
#ifndef PB_BUFFER_ONLY
if (!stream->callback(stream, buf, 1))
PB_RETURN_ERROR(stream, "io error");
#else
*buf = *(const pb_byte_t*)stream->state;
stream->state = (pb_byte_t*)stream->state + 1;
#endif
stream->bytes_left--;
return true;
}
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
{
pb_istream_t stream;
/* Cast away the const from buf without a compiler error. We are
* careful to use it only in a const manner in the callbacks.
*/
union {
void *state;
const void *c_state;
} state;
#ifdef PB_BUFFER_ONLY
stream.callback = NULL;
#else
stream.callback = &buf_read;
#endif
state.c_state = buf;
stream.state = state.state;
stream.bytes_left = bufsize;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
return stream;
}
/********************
* Helper functions *
********************/
static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof)
{
pb_byte_t byte;
uint32_t result;
if (!pb_readbyte(stream, &byte))
{
if (stream->bytes_left == 0)
{
if (eof)
{
*eof = true;
}
}
return false;
}
if ((byte & 0x80) == 0)
{
/* Quick case, 1 byte value */
result = byte;
}
else
{
/* Multibyte case */
uint_fast8_t bitpos = 7;
result = byte & 0x7F;
do
{
if (!pb_readbyte(stream, &byte))
return false;
if (bitpos >= 32)
{
/* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */
pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;
if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension))
{
PB_RETURN_ERROR(stream, "varint overflow");
}
}
else
{
result |= (uint32_t)(byte & 0x7F) << bitpos;
}
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
if (bitpos == 35 && (byte & 0x70) != 0)
{
/* The last byte was at bitpos=28, so only bottom 4 bits fit. */
PB_RETURN_ERROR(stream, "varint overflow");
}
}
*dest = result;
return true;
}
bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
{
return pb_decode_varint32_eof(stream, dest, NULL);
}
#ifndef PB_WITHOUT_64BIT
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
{
pb_byte_t byte;
uint_fast8_t bitpos = 0;
uint64_t result = 0;
do
{
if (bitpos >= 64)
PB_RETURN_ERROR(stream, "varint overflow");
if (!pb_readbyte(stream, &byte))
return false;
result |= (uint64_t)(byte & 0x7F) << bitpos;
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
*dest = result;
return true;
}
#endif
bool checkreturn pb_skip_varint(pb_istream_t *stream)
{
pb_byte_t byte;
do
{
if (!pb_read(stream, &byte, 1))
return false;
} while (byte & 0x80);
return true;
}
bool checkreturn pb_skip_string(pb_istream_t *stream)
{
uint32_t length;
if (!pb_decode_varint32(stream, &length))
return false;
if ((size_t)length != length)
{
PB_RETURN_ERROR(stream, "size too large");
}
return pb_read(stream, NULL, (size_t)length);
}
bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof)
{
uint32_t temp;
*eof = false;
*wire_type = (pb_wire_type_t) 0;
*tag = 0;
if (!pb_decode_varint32_eof(stream, &temp, eof))
{
return false;
}
*tag = temp >> 3;
*wire_type = (pb_wire_type_t)(temp & 7);
return true;
}
bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type)
{
switch (wire_type)
{
case PB_WT_VARINT: return pb_skip_varint(stream);
case PB_WT_64BIT: return pb_read(stream, NULL, 8);
case PB_WT_STRING: return pb_skip_string(stream);
case PB_WT_32BIT: return pb_read(stream, NULL, 4);
default: PB_RETURN_ERROR(stream, "invalid wire_type");
}
}
/* Read a raw value to buffer, for the purpose of passing it to callback as
* a substream. Size is maximum size on call, and actual size on return.
*/
static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size)
{
size_t max_size = *size;
switch (wire_type)
{
case PB_WT_VARINT:
*size = 0;
do
{
(*size)++;
if (*size > max_size)
PB_RETURN_ERROR(stream, "varint overflow");
if (!pb_read(stream, buf, 1))
return false;
} while (*buf++ & 0x80);
return true;
case PB_WT_64BIT:
*size = 8;
return pb_read(stream, buf, 8);
case PB_WT_32BIT:
*size = 4;
return pb_read(stream, buf, 4);
case PB_WT_STRING:
/* Calling read_raw_value with a PB_WT_STRING is an error.
* Explicitly handle this case and fallthrough to default to avoid
* compiler warnings.
*/
default: PB_RETURN_ERROR(stream, "invalid wire_type");
}
}
/* Decode string length from stream and return a substream with limited length.
* Remember to close the substream using pb_close_string_substream().
*/
bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream)
{
uint32_t size;
if (!pb_decode_varint32(stream, &size))
return false;
*substream = *stream;
if (substream->bytes_left < size)
PB_RETURN_ERROR(stream, "parent stream too short");
substream->bytes_left = (size_t)size;
stream->bytes_left -= (size_t)size;
return true;
}
bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
{
if (substream->bytes_left) {
if (!pb_read(substream, NULL, substream->bytes_left))
return false;
}
stream->state = substream->state;
#ifndef PB_NO_ERRMSG
stream->errmsg = substream->errmsg;
#endif
return true;
}
/*************************
* Decode a single field *
*************************/
static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field)
{
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
return wire_type == PB_WT_VARINT;
case PB_LTYPE_FIXED32:
return wire_type == PB_WT_32BIT;
case PB_LTYPE_FIXED64:
return wire_type == PB_WT_64BIT;
case PB_LTYPE_BYTES:
case PB_LTYPE_STRING:
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
case PB_LTYPE_FIXED_LENGTH_BYTES:
return wire_type == PB_WT_STRING;
default:
return false;
}
}
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field)
{
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
return pb_dec_bool(stream, field);
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
return pb_dec_varint(stream, field);
case PB_LTYPE_FIXED32:
case PB_LTYPE_FIXED64:
return pb_dec_fixed(stream, field);
case PB_LTYPE_BYTES:
return pb_dec_bytes(stream, field);
case PB_LTYPE_STRING:
return pb_dec_string(stream, field);
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
return pb_dec_submessage(stream, field);
case PB_LTYPE_FIXED_LENGTH_BYTES:
return pb_dec_fixed_length_bytes(stream, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
switch (PB_HTYPE(field->type))
{
case PB_HTYPE_REQUIRED:
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
return decode_basic_field(stream, field);
case PB_HTYPE_OPTIONAL:
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if (field->pSize != NULL)
*(bool*)field->pSize = true;
return decode_basic_field(stream, field);
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
&& PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Packed array */
bool status = true;
pb_istream_t substream;
pb_size_t *size = (pb_size_t*)field->pSize;
field->pData = (char*)field->pField + field->data_size * (*size);
if (!pb_make_string_substream(stream, &substream))
return false;
while (substream.bytes_left > 0 && *size < field->array_size)
{
if (!decode_basic_field(&substream, field))
{
status = false;
break;
}
(*size)++;
field->pData = (char*)field->pData + field->data_size;
}
if (substream.bytes_left != 0)
PB_RETURN_ERROR(stream, "array overflow");
if (!pb_close_string_substream(stream, &substream))
return false;
return status;
}
else
{
/* Repeated field */
pb_size_t *size = (pb_size_t*)field->pSize;
field->pData = (char*)field->pField + field->data_size * (*size);
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if ((*size)++ >= field->array_size)
PB_RETURN_ERROR(stream, "array overflow");
return decode_basic_field(stream, field);
}
case PB_HTYPE_ONEOF:
*(pb_size_t*)field->pSize = field->tag;
if (PB_LTYPE_IS_SUBMSG(field->type))
{
/* We memset to zero so that any callbacks are set to NULL.
* This is because the callbacks might otherwise have values
* from some other union field.
* If callbacks are needed inside oneof field, use .proto
* option submsg_callback to have a separate callback function
* that can set the fields before submessage is decoded.
* pb_dec_submessage() will set any default values. */
memset(field->pData, 0, (size_t)field->data_size);
}
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
return decode_basic_field(stream, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
#ifdef PB_ENABLE_MALLOC
/* Allocate storage for the field and store the pointer at iter->pData.
* array_size is the number of entries to reserve in an array.
* Zero size is not allowed, use pb_free() for releasing.
*/
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size)
{
void *ptr = *(void**)pData;
if (data_size == 0 || array_size == 0)
PB_RETURN_ERROR(stream, "invalid size");
#ifdef __AVR__
/* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284
* Realloc to size of 1 byte can cause corruption of the malloc structures.
*/
if (data_size == 1 && array_size == 1)
{
data_size = 2;
}
#endif
/* Check for multiplication overflows.
* This code avoids the costly division if the sizes are small enough.
* Multiplication is safe as long as only half of bits are set
* in either multiplicand.
*/
{
const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
if (data_size >= check_limit || array_size >= check_limit)
{
const size_t size_max = (size_t)-1;
if (size_max / array_size < data_size)
{
PB_RETURN_ERROR(stream, "size too large");
}
}
}
/* Allocate new or expand previous allocation */
/* Note: on failure the old pointer will remain in the structure,
* the message must be freed by caller also on error return. */
ptr = pb_realloc(ptr, array_size * data_size);
if (ptr == NULL)
PB_RETURN_ERROR(stream, "realloc failed");
*(void**)pData = ptr;
return true;
}
/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */
static void initialize_pointer_field(void *pItem, pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES)
{
*(void**)pItem = NULL;
}
else if (PB_LTYPE_IS_SUBMSG(field->type))
{
/* We memset to zero so that any callbacks are set to NULL.
* Then set any default values. */
pb_field_iter_t submsg_iter;
memset(pItem, 0, field->data_size);
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, pItem))
{
(void)pb_message_set_to_defaults(&submsg_iter);
}
}
}
#endif
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
#ifndef PB_ENABLE_MALLOC
PB_UNUSED(wire_type);
PB_UNUSED(field);
PB_RETURN_ERROR(stream, "no malloc support");
#else
switch (PB_HTYPE(field->type))
{
case PB_HTYPE_REQUIRED:
case PB_HTYPE_OPTIONAL:
case PB_HTYPE_ONEOF:
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL)
{
/* Duplicate field, have to release the old allocation first. */
/* FIXME: Does this work correctly for oneofs? */
pb_release_single_field(field);
}
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
*(pb_size_t*)field->pSize = field->tag;
}
if (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES)
{
/* pb_dec_string and pb_dec_bytes handle allocation themselves */
field->pData = field->pField;
return decode_basic_field(stream, field);
}
else
{
if (!allocate_field(stream, field->pField, field->data_size, 1))
return false;
field->pData = *(void**)field->pField;
initialize_pointer_field(field->pData, field);
return decode_basic_field(stream, field);
}
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
&& PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Packed array, multiple items come in at once. */
bool status = true;
pb_size_t *size = (pb_size_t*)field->pSize;
size_t allocated_size = *size;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
while (substream.bytes_left)
{
if (*size == PB_SIZE_MAX)
{
#ifndef PB_NO_ERRMSG
stream->errmsg = "too many array entries";
#endif
status = false;
break;
}
if ((size_t)*size + 1 > allocated_size)
{
/* Allocate more storage. This tries to guess the
* number of remaining entries. Round the division
* upwards. */
size_t remain = (substream.bytes_left - 1) / field->data_size + 1;
if (remain < PB_SIZE_MAX - allocated_size)
allocated_size += remain;
else
allocated_size += 1;
if (!allocate_field(&substream, field->pField, field->data_size, allocated_size))
{
status = false;
break;
}
}
/* Decode the array entry */
field->pData = *(char**)field->pField + field->data_size * (*size);
initialize_pointer_field(field->pData, field);
if (!decode_basic_field(&substream, field))
{
status = false;
break;
}
(*size)++;
}
if (!pb_close_string_substream(stream, &substream))
return false;
return status;
}
else
{
/* Normal repeated field, i.e. only one item at a time. */
pb_size_t *size = (pb_size_t*)field->pSize;
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1)))
return false;
field->pData = *(char**)field->pField + field->data_size * (*size);
(*size)++;
initialize_pointer_field(field->pData, field);
return decode_basic_field(stream, field);
}
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
#endif
}
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
if (!field->descriptor->field_callback)
return pb_skip_field(stream, wire_type);
if (wire_type == PB_WT_STRING)
{
pb_istream_t substream;
size_t prev_bytes_left;
if (!pb_make_string_substream(stream, &substream))
return false;
do
{
prev_bytes_left = substream.bytes_left;
if (!field->descriptor->field_callback(&substream, NULL, field))
PB_RETURN_ERROR(stream, "callback failed");
} while (substream.bytes_left > 0 && substream.bytes_left < prev_bytes_left);
if (!pb_close_string_substream(stream, &substream))
return false;
return true;
}
else
{
/* Copy the single scalar value to stack.
* This is required so that we can limit the stream length,
* which in turn allows to use same callback for packed and
* not-packed fields. */
pb_istream_t substream;
pb_byte_t buffer[10];
size_t size = sizeof(buffer);
if (!read_raw_value(stream, wire_type, buffer, &size))
return false;
substream = pb_istream_from_buffer(buffer, size);
return field->descriptor->field_callback(&substream, NULL, field);
}
}
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
#ifdef PB_ENABLE_MALLOC
/* When decoding an oneof field, check if there is old data that must be
* released first. */
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
if (!pb_release_union_field(stream, field))
return false;
}
#endif
switch (PB_ATYPE(field->type))
{
case PB_ATYPE_STATIC:
return decode_static_field(stream, wire_type, field);
case PB_ATYPE_POINTER:
return decode_pointer_field(stream, wire_type, field);
case PB_ATYPE_CALLBACK:
return decode_callback_field(stream, wire_type, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
/* Default handler for extension fields. Expects to have a pb_msgdesc_t
* pointer in the extension->type->arg field, pointing to a message with
* only one field in it. */
static bool checkreturn default_extension_decoder(pb_istream_t *stream,
pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin_extension(&iter, extension))
PB_RETURN_ERROR(stream, "invalid extension");
if (iter.tag != tag)
return true;
extension->found = true;
return decode_field(stream, wire_type, &iter);
}
/* Try to decode an unknown field as an extension field. Tries each extension
* decoder in turn, until one of them handles the field or loop ends. */
static bool checkreturn decode_extension(pb_istream_t *stream,
uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter)
{
pb_extension_t *extension = *(pb_extension_t* const *)iter->pData;
size_t pos = stream->bytes_left;
while (extension != NULL && pos == stream->bytes_left)
{
bool status;
if (extension->type->decode)
status = extension->type->decode(stream, extension, tag, wire_type);
else
status = default_extension_decoder(stream, extension, tag, wire_type);
if (!status)
return false;
extension = extension->next;
}
return true;
}
/* Step through the iterator until an extension field is found or until all
* entries have been checked. There can be only one extension field per
* message. Returns false if no extension field is found. */
static bool checkreturn find_extension_field(pb_field_iter_t *iter)
{
pb_size_t start = iter->index;
do {
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
return true;
(void)pb_field_iter_next(iter);
} while (iter->index != start);
return false;
}
/* Initialize message fields to default values, recursively */
static bool pb_field_set_to_default(pb_field_iter_t *field)
{
pb_type_t type;
type = field->type;
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
pb_extension_t *ext = *(pb_extension_t* const *)field->pData;
while (ext != NULL)
{
pb_field_iter_t ext_iter;
if (pb_field_iter_begin_extension(&ext_iter, ext))
{
ext->found = false;
if (!pb_message_set_to_defaults(&ext_iter))
return false;
}
ext = ext->next;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{
bool init_data = true;
if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
{
/* Set has_field to false. Still initialize the optional field
* itself also. */
*(bool*)field->pSize = false;
}
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
/* REPEATED: Set array count to 0, no need to initialize contents.
ONEOF: Set which_field to 0. */
*(pb_size_t*)field->pSize = 0;
init_data = false;
}
if (init_data)
{
if (PB_LTYPE_IS_SUBMSG(field->type))
{
/* Initialize submessage to defaults */
pb_field_iter_t submsg_iter;
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
{
if (!pb_message_set_to_defaults(&submsg_iter))
return false;
}
}
else
{
/* Initialize to zeros */
memset(field->pData, 0, (size_t)field->data_size);
}
}
}
else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
/* Initialize the pointer to NULL. */
*(void**)field->pField = NULL;
/* Initialize array count to 0. */
if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
*(pb_size_t*)field->pSize = 0;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
{
/* Don't overwrite callback */
}
return true;
}
static bool pb_message_set_to_defaults(pb_field_iter_t *iter)
{
pb_istream_t defstream = PB_ISTREAM_EMPTY;
uint32_t tag = 0;
pb_wire_type_t wire_type = PB_WT_VARINT;
bool eof;
if (iter->descriptor->default_value)
{
defstream = pb_istream_from_buffer(iter->descriptor->default_value, (size_t)-1);
if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof))
return false;
}
do
{
if (!pb_field_set_to_default(iter))
return false;
if (tag != 0 && iter->tag == tag)
{
/* We have a default value for this field in the defstream */
if (!decode_field(&defstream, wire_type, iter))
return false;
if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof))
return false;
if (iter->pSize)
*(bool*)iter->pSize = false;
}
} while (pb_field_iter_next(iter));
return true;
}
/*********************
* Decode all fields *
*********************/
static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
{
uint32_t extension_range_start = 0;
/* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed
* count field. This can only handle _one_ repeated fixed count field that
* is unpacked and unordered among other (non repeated fixed count) fields.
*/
pb_size_t fixed_count_field = PB_SIZE_MAX;
pb_size_t fixed_count_size = 0;
pb_size_t fixed_count_total_size = 0;
pb_fields_seen_t fields_seen = {{0, 0}};
const uint32_t allbits = ~(uint32_t)0;
pb_field_iter_t iter;
if (pb_field_iter_begin(&iter, fields, dest_struct))
{
if ((flags & PB_DECODE_NOINIT) == 0)
{
if (!pb_message_set_to_defaults(&iter))
PB_RETURN_ERROR(stream, "failed to set defaults");
}
}
while (stream->bytes_left)
{
uint32_t tag;
pb_wire_type_t wire_type;
bool eof;
if (!pb_decode_tag(stream, &wire_type, &tag, &eof))
{
if (eof)
break;
else
return false;
}
if (tag == 0)
{
if (flags & PB_DECODE_NULLTERMINATED)
{
break;
}
else
{
PB_RETURN_ERROR(stream, "zero tag");
}
}
if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
{
/* No match found, check if it matches an extension. */
if (tag >= extension_range_start)
{
if (!find_extension_field(&iter))
extension_range_start = (uint32_t)-1;
else
extension_range_start = iter.tag;
if (tag >= extension_range_start)
{
size_t pos = stream->bytes_left;
if (!decode_extension(stream, tag, wire_type, &iter))
return false;
if (pos != stream->bytes_left)
{
/* The field was handled */
continue;
}
}
}
/* No match found, skip data */
if (!pb_skip_field(stream, wire_type))
return false;
continue;
}
/* If a repeated fixed count field was found, get size from
* 'fixed_count_field' as there is no counter contained in the struct.
*/
if (PB_HTYPE(iter.type) == PB_HTYPE_REPEATED && iter.pSize == &iter.array_size)
{
if (fixed_count_field != iter.index) {
/* If the new fixed count field does not match the previous one,
* check that the previous one is NULL or that it finished
* receiving all the expected data.
*/
if (fixed_count_field != PB_SIZE_MAX &&
fixed_count_size != fixed_count_total_size)
{
PB_RETURN_ERROR(stream, "wrong size for fixed count field");
}
fixed_count_field = iter.index;
fixed_count_size = 0;
fixed_count_total_size = iter.array_size;
}
iter.pSize = &fixed_count_size;
}
if (PB_HTYPE(iter.type) == PB_HTYPE_REQUIRED
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
{
uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31));
fields_seen.bitfield[iter.required_field_index >> 5] |= tmp;
}
if (!decode_field(stream, wire_type, &iter))
return false;
}
/* Check that all elements of the last decoded fixed count field were present. */
if (fixed_count_field != PB_SIZE_MAX &&
fixed_count_size != fixed_count_total_size)
{
PB_RETURN_ERROR(stream, "wrong size for fixed count field");
}
/* Check that all required fields were present. */
{
/* First figure out the number of required fields by
* seeking to the end of the field array. Usually we
* are already close to end after decoding.
*/
pb_size_t req_field_count;
pb_type_t last_type;
pb_size_t i;
do {
req_field_count = iter.required_field_index;
last_type = iter.type;
} while (pb_field_iter_next(&iter));
/* Fixup if last field was also required. */
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.tag != 0)
req_field_count++;
if (req_field_count > PB_MAX_REQUIRED_FIELDS)
req_field_count = PB_MAX_REQUIRED_FIELDS;
if (req_field_count > 0)
{
/* Check the whole words */
for (i = 0; i < (req_field_count >> 5); i++)
{
if (fields_seen.bitfield[i] != allbits)
PB_RETURN_ERROR(stream, "missing required field");
}
/* Check the remaining bits (if any) */
if ((req_field_count & 31) != 0)
{
if (fields_seen.bitfield[req_field_count >> 5] !=
(allbits >> (uint_least8_t)(32 - (req_field_count & 31))))
{
PB_RETURN_ERROR(stream, "missing required field");
}
}
}
}
return true;
}
bool checkreturn pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
{
bool status;
if ((flags & PB_DECODE_DELIMITED) == 0)
{
status = pb_decode_inner(stream, fields, dest_struct, flags);
}
else
{
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
status = pb_decode_inner(&substream, fields, dest_struct, flags);
if (!pb_close_string_substream(stream, &substream))
return false;
}
#ifdef PB_ENABLE_MALLOC
if (!status)
pb_release(fields, dest_struct);
#endif
return status;
}
bool checkreturn pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct)
{
bool status;
status = pb_decode_inner(stream, fields, dest_struct, 0);
#ifdef PB_ENABLE_MALLOC
if (!status)
pb_release(fields, dest_struct);
#endif
return status;
}
#ifdef PB_ENABLE_MALLOC
/* Given an oneof field, if there has already been a field inside this oneof,
* release it before overwriting with a different one. */
static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field)
{
pb_field_iter_t old_field = *field;
pb_size_t old_tag = *(pb_size_t*)field->pSize; /* Previous which_ value */
pb_size_t new_tag = field->tag; /* New which_ value */
if (old_tag == 0)
return true; /* Ok, no old data in union */
if (old_tag == new_tag)
return true; /* Ok, old data is of same type => merge */
/* Release old data. The find can fail if the message struct contains
* invalid data. */
if (!pb_field_iter_find(&old_field, old_tag))
PB_RETURN_ERROR(stream, "invalid union tag");
pb_release_single_field(&old_field);
return true;
}
static void pb_release_single_field(pb_field_iter_t *field)
{
pb_type_t type;
type = field->type;
if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
if (*(pb_size_t*)field->pSize != field->tag)
return; /* This is not the current field in the union */
}
/* Release anything contained inside an extension or submsg.
* This has to be done even if the submsg itself is statically
* allocated. */
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
/* Release fields from all extensions in the linked list */
pb_extension_t *ext = *(pb_extension_t**)field->pData;
while (ext != NULL)
{
pb_field_iter_t ext_iter;
if (pb_field_iter_begin_extension(&ext_iter, ext))
{
pb_release_single_field(&ext_iter);
}
ext = ext->next;
}
}
else if (PB_LTYPE_IS_SUBMSG(type) && PB_ATYPE(type) != PB_ATYPE_CALLBACK)
{
/* Release fields in submessage or submsg array */
pb_size_t count = 1;
if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
field->pData = *(void**)field->pField;
}
else
{
field->pData = field->pField;
}
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(pb_size_t*)field->pSize;
if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > field->array_size)
{
/* Protect against corrupted _count fields */
count = field->array_size;
}
}
if (field->pData)
{
while (count--)
{
pb_release(field->submsg_desc, field->pData);
field->pData = (char*)field->pData + field->data_size;
}
}
}
if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
(PB_LTYPE(type) == PB_LTYPE_STRING ||
PB_LTYPE(type) == PB_LTYPE_BYTES))
{
/* Release entries in repeated string or bytes array */
void **pItem = *(void***)field->pField;
pb_size_t count = *(pb_size_t*)field->pSize;
while (count--)
{
pb_free(*pItem);
*pItem++ = NULL;
}
}
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
/* We are going to release the array, so set the size to 0 */
*(pb_size_t*)field->pSize = 0;
}
/* Release main pointer */
pb_free(*(void**)field->pField);
*(void**)field->pField = NULL;
}
}
void pb_release(const pb_msgdesc_t *fields, void *dest_struct)
{
pb_field_iter_t iter;
if (!dest_struct)
return; /* Ignore NULL pointers, similar to free() */
if (!pb_field_iter_begin(&iter, fields, dest_struct))
return; /* Empty message type */
do
{
pb_release_single_field(&iter);
} while (pb_field_iter_next(&iter));
}
#endif
/* Field decoders */
bool pb_decode_bool(pb_istream_t *stream, bool *dest)
{
uint32_t value;
if (!pb_decode_varint32(stream, &value))
return false;
*(bool*)dest = (value != 0);
return true;
}
bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest)
{
pb_uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
if (value & 1)
*dest = (pb_int64_t)(~(value >> 1));
else
*dest = (pb_int64_t)(value >> 1);
return true;
}
bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
{
union {
uint32_t fixed32;
pb_byte_t bytes[4];
} u;
if (!pb_read(stream, u.bytes, 4))
return false;
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
/* fast path - if we know that we're on little endian, assign directly */
*(uint32_t*)dest = u.fixed32;
#else
*(uint32_t*)dest = ((uint32_t)u.bytes[0] << 0) |
((uint32_t)u.bytes[1] << 8) |
((uint32_t)u.bytes[2] << 16) |
((uint32_t)u.bytes[3] << 24);
#endif
return true;
}
#ifndef PB_WITHOUT_64BIT
bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
{
union {
uint64_t fixed64;
pb_byte_t bytes[8];
} u;
if (!pb_read(stream, u.bytes, 8))
return false;
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
/* fast path - if we know that we're on little endian, assign directly */
*(uint64_t*)dest = u.fixed64;
#else
*(uint64_t*)dest = ((uint64_t)u.bytes[0] << 0) |
((uint64_t)u.bytes[1] << 8) |
((uint64_t)u.bytes[2] << 16) |
((uint64_t)u.bytes[3] << 24) |
((uint64_t)u.bytes[4] << 32) |
((uint64_t)u.bytes[5] << 40) |
((uint64_t)u.bytes[6] << 48) |
((uint64_t)u.bytes[7] << 56);
#endif
return true;
}
#endif
static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field)
{
return pb_decode_bool(stream, (bool*)field->pData);
}
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
{
pb_uint64_t value, clamped;
if (!pb_decode_varint(stream, &value))
return false;
/* Cast to the proper field size, while checking for overflows */
if (field->data_size == sizeof(pb_uint64_t))
clamped = *(pb_uint64_t*)field->pData = value;
else if (field->data_size == sizeof(uint32_t))
clamped = *(uint32_t*)field->pData = (uint32_t)value;
else if (field->data_size == sizeof(uint_least16_t))
clamped = *(uint_least16_t*)field->pData = (uint_least16_t)value;
else if (field->data_size == sizeof(uint_least8_t))
clamped = *(uint_least8_t*)field->pData = (uint_least8_t)value;
else
PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
return true;
}
else
{
pb_uint64_t value;
pb_int64_t svalue;
pb_int64_t clamped;
if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
{
if (!pb_decode_svarint(stream, &svalue))
return false;
}
else
{
if (!pb_decode_varint(stream, &value))
return false;
/* See issue 97: Google's C++ protobuf allows negative varint values to
* be cast as int32_t, instead of the int64_t that should be used when
* encoding. Previous nanopb versions had a bug in encoding. In order to
* not break decoding of such messages, we cast <=32 bit fields to
* int32_t first to get the sign correct.
*/
if (field->data_size == sizeof(pb_int64_t))
svalue = (pb_int64_t)value;
else
svalue = (int32_t)value;
}
/* Cast to the proper field size, while checking for overflows */
if (field->data_size == sizeof(pb_int64_t))
clamped = *(pb_int64_t*)field->pData = svalue;
else if (field->data_size == sizeof(int32_t))
clamped = *(int32_t*)field->pData = (int32_t)svalue;
else if (field->data_size == sizeof(int_least16_t))
clamped = *(int_least16_t*)field->pData = (int_least16_t)svalue;
else if (field->data_size == sizeof(int_least8_t))
clamped = *(int_least8_t*)field->pData = (int_least8_t)svalue;
else
PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != svalue)
PB_RETURN_ERROR(stream, "integer too large");
return true;
}
}
static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
return pb_decode_double_as_float(stream, (float*)field->pData);
}
#endif
if (field->data_size == sizeof(uint32_t))
{
return pb_decode_fixed32(stream, field->pData);
}
#ifndef PB_WITHOUT_64BIT
else if (field->data_size == sizeof(uint64_t))
{
return pb_decode_fixed64(stream, field->pData);
}
#endif
else
{
PB_RETURN_ERROR(stream, "invalid data_size");
}
}
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
size_t alloc_size;
pb_bytes_array_t *dest;
if (!pb_decode_varint32(stream, &size))
return false;
if (size > PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "bytes overflow");
alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size);
if (size > alloc_size)
PB_RETURN_ERROR(stream, "size too large");
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
if (stream->bytes_left < size)
PB_RETURN_ERROR(stream, "end-of-stream");
if (!allocate_field(stream, field->pData, alloc_size, 1))
return false;
dest = *(pb_bytes_array_t**)field->pData;
#endif
}
else
{
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "bytes overflow");
dest = (pb_bytes_array_t*)field->pData;
}
dest->size = (pb_size_t)size;
return pb_read(stream, dest->bytes, (size_t)size);
}
static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
size_t alloc_size;
pb_byte_t *dest = (pb_byte_t*)field->pData;
if (!pb_decode_varint32(stream, &size))
return false;
if (size == (uint32_t)-1)
PB_RETURN_ERROR(stream, "size too large");
/* Space for null terminator */
alloc_size = (size_t)(size + 1);
if (alloc_size < size)
PB_RETURN_ERROR(stream, "size too large");
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
if (stream->bytes_left < size)
PB_RETURN_ERROR(stream, "end-of-stream");
if (!allocate_field(stream, field->pData, alloc_size, 1))
return false;
dest = *(pb_byte_t**)field->pData;
#endif
}
else
{
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "string overflow");
}
dest[size] = 0;
if (!pb_read(stream, dest, (size_t)size))
return false;
#ifdef PB_VALIDATE_UTF8
if (!pb_validate_utf8((const char*)dest))
PB_RETURN_ERROR(stream, "invalid utf8");
#endif
return true;
}
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field)
{
bool status = true;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
if (field->submsg_desc == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor");
/* New array entries need to be initialized, while required and optional
* submessages have already been initialized in the top-level pb_decode. */
if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED ||
PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
pb_field_iter_t submsg_iter;
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
{
if (!pb_message_set_to_defaults(&submsg_iter))
PB_RETURN_ERROR(stream, "failed to set defaults");
}
}
/* Submessages can have a separate message-level callback that is called
* before decoding the message. Typically it is used to set callback fields
* inside oneofs. */
if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
{
/* Message callback is stored right before pSize. */
pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
if (callback->funcs.decode)
{
status = callback->funcs.decode(&substream, field, &callback->arg);
}
}
/* Now decode the submessage contents */
if (status)
{
status = pb_decode_inner(&substream, field->submsg_desc, field->pData, 0);
}
if (!pb_close_string_substream(stream, &substream))
return false;
return status;
}
static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
if (!pb_decode_varint32(stream, &size))
return false;
if (size > PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "bytes overflow");
if (size == 0)
{
/* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */
memset(field->pData, 0, (size_t)field->data_size);
return true;
}
if (size != field->data_size)
PB_RETURN_ERROR(stream, "incorrect fixed length bytes size");
return pb_read(stream, (pb_byte_t*)field->pData, (size_t)field->data_size);
}
#ifdef PB_CONVERT_DOUBLE_FLOAT
bool pb_decode_double_as_float(pb_istream_t *stream, float *dest)
{
uint_least8_t sign;
int exponent;
uint32_t mantissa;
uint64_t value;
union { float f; uint32_t i; } out;
if (!pb_decode_fixed64(stream, &value))
return false;
/* Decompose input value */
sign = (uint_least8_t)((value >> 63) & 1);
exponent = (int)((value >> 52) & 0x7FF) - 1023;
mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */
/* Figure if value is in range representable by floats. */
if (exponent == 1024)
{
/* Special value */
exponent = 128;
}
else if (exponent > 127)
{
/* Too large, convert to infinity */
exponent = 128;
mantissa = 0;
}
else if (exponent < -150)
{
/* Too small, convert to zero */
exponent = -127;
mantissa = 0;
}
else if (exponent < -126)
{
/* Denormalized */
mantissa |= 0x1000000;
mantissa >>= (-126 - exponent);
exponent = -127;
}
/* Round off mantissa */
mantissa = (mantissa + 1) >> 1;
/* Check if mantissa went over 2.0 */
if (mantissa & 0x800000)
{
exponent += 1;
mantissa &= 0x7FFFFF;
mantissa >>= 1;
}
/* Combine fields */
out.i = mantissa;
out.i |= (uint32_t)(exponent + 127) << 23;
out.i |= (uint32_t)sign << 31;
*dest = out.f;
return true;
}
#endif
================================================
FILE: c/core/src/pb_encode.c
================================================
/* pb_encode.c -- encode a protobuf using minimal resources
*
* 2011 Petteri Aimonen
*/
#include "pb.h"
#include "pb_encode.h"
#include "pb_common.h"
/* Use the GCC warn_unused_result attribute to check that all return values
* are propagated correctly. On other compilers and gcc before 3.4.0 just
* ignore the annotation.
*/
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
#define checkreturn
#else
#define checkreturn __attribute__((warn_unused_result))
#endif
/**************************************
* Declarations internal to this file *
**************************************/
static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field);
static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field);
static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field);
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high);
static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
#ifdef PB_WITHOUT_64BIT
#define pb_int64_t int32_t
#define pb_uint64_t uint32_t
#else
#define pb_int64_t int64_t
#define pb_uint64_t uint64_t
#endif
/*******************************
* pb_ostream_t implementation *
*******************************/
static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
size_t i;
pb_byte_t *dest = (pb_byte_t*)stream->state;
stream->state = dest + count;
for (i = 0; i < count; i++)
dest[i] = buf[i];
return true;
}
pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
{
pb_ostream_t stream;
#ifdef PB_BUFFER_ONLY
stream.callback = (void*)1; /* Just a marker value */
#else
stream.callback = &buf_write;
#endif
stream.state = buf;
stream.max_size = bufsize;
stream.bytes_written = 0;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
return stream;
}
bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
if (count > 0 && stream->callback != NULL)
{
if (stream->bytes_written + count > stream->max_size)
PB_RETURN_ERROR(stream, "stream full");
#ifdef PB_BUFFER_ONLY
if (!buf_write(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#else
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#endif
}
stream->bytes_written += count;
return true;
}
/*************************
* Encode a single field *
*************************/
/* Read a bool value without causing undefined behavior even if the value
* is invalid. See issue #434 and
* https://stackoverflow.com/questions/27661768/weird-results-for-conditional
*/
static bool safe_read_bool(const void *pSize)
{
const char *p = (const char *)pSize;
size_t i;
for (i = 0; i < sizeof(bool); i++)
{
if (p[i] != 0)
return true;
}
return false;
}
/* Encode a static array. Handles the size calculations and possible packing. */
static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field)
{
pb_size_t i;
pb_size_t count;
#ifndef PB_ENCODE_ARRAYS_UNPACKED
size_t size;
#endif
count = *(pb_size_t*)field->pSize;
if (count == 0)
return true;
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
PB_RETURN_ERROR(stream, "array max size exceeded");
#ifndef PB_ENCODE_ARRAYS_UNPACKED
/* We always pack arrays if the datatype allows it. */
if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
return false;
/* Determine the total size of packed array. */
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
{
size = 4 * (size_t)count;
}
else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
size = 8 * (size_t)count;
}
else
{
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
void *pData_orig = field->pData;
for (i = 0; i < count; i++)
{
if (!pb_enc_varint(&sizestream, field))
PB_RETURN_ERROR(stream, PB_GET_ERROR(&sizestream));
field->pData = (char*)field->pData + field->data_size;
}
field->pData = pData_orig;
size = sizestream.bytes_written;
}
if (!pb_encode_varint(stream, (pb_uint64_t)size))
return false;
if (stream->callback == NULL)
return pb_write(stream, NULL, size); /* Just sizing.. */
/* Write the data */
for (i = 0; i < count; i++)
{
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32 || PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
if (!pb_enc_fixed(stream, field))
return false;
}
else
{
if (!pb_enc_varint(stream, field))
return false;
}
field->pData = (char*)field->pData + field->data_size;
}
}
else /* Unpacked fields */
#endif
{
for (i = 0; i < count; i++)
{
/* Normally the data is stored directly in the array entries, but
* for pointer-type string and bytes fields, the array entries are
* actually pointers themselves also. So we have to dereference once
* more to get to the actual data. */
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
(PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES))
{
bool status;
void *pData_orig = field->pData;
field->pData = *(void* const*)field->pData;
if (!field->pData)
{
/* Null pointer in array is treated as empty string / bytes */
status = pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0);
}
else
{
status = encode_basic_field(stream, field);
}
field->pData = pData_orig;
if (!status)
return false;
}
else
{
if (!encode_basic_field(stream, field))
return false;
}
field->pData = (char*)field->pData + field->data_size;
}
}
return true;
}
/* In proto3, all fields are optional and are only encoded if their value is "non-zero".
* This function implements the check for the zero value. */
static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field)
{
pb_type_t type = field->type;
if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{
if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
{
/* Required proto2 fields inside proto3 submessage, pretty rare case */
return false;
}
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
/* Repeated fields inside proto3 submessage: present if count != 0 */
return *(const pb_size_t*)field->pSize == 0;
}
else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
/* Oneof fields */
return *(const pb_size_t*)field->pSize == 0;
}
else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
{
/* Proto2 optional fields inside proto3 message, or proto3
* submessage fields. */
return safe_read_bool(field->pSize) == false;
}
/* Rest is proto3 singular fields */
if (PB_LTYPE(type) == PB_LTYPE_BYTES)
{
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData;
return bytes->size == 0;
}
else if (PB_LTYPE(type) == PB_LTYPE_STRING)
{
return *(const char*)field->pData == '\0';
}
else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
{
/* Fixed length bytes is only empty if its length is fixed
* as 0. Which would be pretty strange, but we can check
* it anyway. */
return field->data_size == 0;
}
else if (PB_LTYPE_IS_SUBMSG(type))
{
/* Check all fields in the submessage to find if any of them
* are non-zero. The comparison cannot be done byte-per-byte
* because the C struct may contain padding bytes that must
* be skipped. Note that usually proto3 submessages have
* a separate has_field that is checked earlier in this if.
*/
pb_field_iter_t iter;
if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData))
{
do
{
if (!pb_check_proto3_default_value(&iter))
{
return false;
}
} while (pb_field_iter_next(&iter));
}
return true;
}
}
{
/* Catch-all branch that does byte-per-byte comparison for zero value.
*
* This is for all pointer fields, and for static PB_LTYPE_VARINT,
* UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also
* callback fields. These all have integer or pointer value which
* can be compared with 0.
*/
pb_size_t i;
const char *p = (const char*)field->pData;
for (i = 0; i < field->data_size; i++)
{
if (p[i] != 0)
{
return false;
}
}
return true;
}
}
/* Encode a field with static or pointer allocation, i.e. one whose data
* is available to the encoder directly. */
static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (!field->pData)
{
/* Missing pointer field */
return true;
}
if (!pb_encode_tag_for_field(stream, field))
return false;
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
return pb_enc_bool(stream, field);
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
return pb_enc_varint(stream, field);
case PB_LTYPE_FIXED32:
case PB_LTYPE_FIXED64:
return pb_enc_fixed(stream, field);
case PB_LTYPE_BYTES:
return pb_enc_bytes(stream, field);
case PB_LTYPE_STRING:
return pb_enc_string(stream, field);
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
return pb_enc_submessage(stream, field);
case PB_LTYPE_FIXED_LENGTH_BYTES:
return pb_enc_fixed_length_bytes(stream, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
/* Encode a field with callback semantics. This means that a user function is
* called to provide and encode the actual data. */
static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (field->descriptor->field_callback != NULL)
{
if (!field->descriptor->field_callback(NULL, stream, field))
PB_RETURN_ERROR(stream, "callback error");
}
return true;
}
/* Encode a single field of any callback, pointer or static type. */
static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field)
{
/* Check field presence */
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
if (*(const pb_size_t*)field->pSize != field->tag)
{
/* Different type oneof field */
return true;
}
}
else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
{
if (field->pSize)
{
if (safe_read_bool(field->pSize) == false)
{
/* Missing optional field */
return true;
}
}
else if (PB_ATYPE(field->type) == PB_ATYPE_STATIC)
{
/* Proto3 singular field */
if (pb_check_proto3_default_value(field))
return true;
}
}
if (!field->pData)
{
if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED)
PB_RETURN_ERROR(stream, "missing required field");
/* Pointer field set to NULL */
return true;
}
/* Then encode field contents */
if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK)
{
return encode_callback_field(stream, field);
}
else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
{
return encode_array(stream, field);
}
else
{
return encode_basic_field(stream, field);
}
}
/* Default handler for extension fields. Expects to have a pb_msgdesc_t
* pointer in the extension->type->arg field, pointing to a message with
* only one field in it. */
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin_extension_const(&iter, extension))
PB_RETURN_ERROR(stream, "invalid extension");
return encode_field(stream, &iter);
}
/* Walk through all the registered extensions and give them a chance
* to encode themselves. */
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field)
{
const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
while (extension)
{
bool status;
if (extension->type->encode)
status = extension->type->encode(stream, extension);
else
status = default_extension_encoder(stream, extension);
if (!status)
return false;
extension = extension->next;
}
return true;
}
/*********************
* Encode all fields *
*********************/
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin_const(&iter, fields, src_struct))
return true; /* Empty message type */
do {
if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
{
/* Special case for the extension field placeholder */
if (!encode_extension_field(stream, &iter))
return false;
}
else
{
/* Regular field */
if (!encode_field(stream, &iter))
return false;
}
} while (pb_field_iter_next(&iter));
return true;
}
bool checkreturn pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags)
{
if ((flags & PB_ENCODE_DELIMITED) != 0)
{
return pb_encode_submessage(stream, fields, src_struct);
}
else if ((flags & PB_ENCODE_NULLTERMINATED) != 0)
{
const pb_byte_t zero = 0;
if (!pb_encode(stream, fields, src_struct))
return false;
return pb_write(stream, &zero, 1);
}
else
{
return pb_encode(stream, fields, src_struct);
}
}
bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct)
{
pb_ostream_t stream = PB_OSTREAM_SIZING;
if (!pb_encode(&stream, fields, src_struct))
return false;
*size = stream.bytes_written;
return true;
}
/********************
* Helper functions *
********************/
/* This function avoids 64-bit shifts as they are quite slow on many platforms. */
static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high)
{
size_t i = 0;
pb_byte_t buffer[10];
pb_byte_t byte = (pb_byte_t)(low & 0x7F);
low >>= 7;
while (i < 4 && (low != 0 || high != 0))
{
byte |= 0x80;
buffer[i++] = byte;
byte = (pb_byte_t)(low & 0x7F);
low >>= 7;
}
if (high)
{
byte = (pb_byte_t)(byte | ((high & 0x07) << 4));
high >>= 3;
while (high)
{
byte |= 0x80;
buffer[i++] = byte;
byte = (pb_byte_t)(high & 0x7F);
high >>= 7;
}
}
buffer[i++] = byte;
return pb_write(stream, buffer, i);
}
bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
{
if (value <= 0x7F)
{
/* Fast path: single byte */
pb_byte_t byte = (pb_byte_t)value;
return pb_write(stream, &byte, 1);
}
else
{
#ifdef PB_WITHOUT_64BIT
return pb_encode_varint_32(stream, value, 0);
#else
return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32));
#endif
}
}
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
{
pb_uint64_t zigzagged;
if (value < 0)
zigzagged = ~((pb_uint64_t)value << 1);
else
zigzagged = (pb_uint64_t)value << 1;
return pb_encode_varint(stream, zigzagged);
}
bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
{
uint32_t val = *(const uint32_t*)value;
pb_byte_t bytes[4];
bytes[0] = (pb_byte_t)(val & 0xFF);
bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
return pb_write(stream, bytes, 4);
}
#ifndef PB_WITHOUT_64BIT
bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
{
uint64_t val = *(const uint64_t*)value;
pb_byte_t bytes[8];
bytes[0] = (pb_byte_t)(val & 0xFF);
bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
bytes[4] = (pb_byte_t)((val >> 32) & 0xFF);
bytes[5] = (pb_byte_t)((val >> 40) & 0xFF);
bytes[6] = (pb_byte_t)((val >> 48) & 0xFF);
bytes[7] = (pb_byte_t)((val >> 56) & 0xFF);
return pb_write(stream, bytes, 8);
}
#endif
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
{
pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype;
return pb_encode_varint(stream, tag);
}
bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field )
{
pb_wire_type_t wiretype;
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
wiretype = PB_WT_VARINT;
break;
case PB_LTYPE_FIXED32:
wiretype = PB_WT_32BIT;
break;
case PB_LTYPE_FIXED64:
wiretype = PB_WT_64BIT;
break;
case PB_LTYPE_BYTES:
case PB_LTYPE_STRING:
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
case PB_LTYPE_FIXED_LENGTH_BYTES:
wiretype = PB_WT_STRING;
break;
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
return pb_encode_tag(stream, wiretype, field->tag);
}
bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
{
if (!pb_encode_varint(stream, (pb_uint64_t)size))
return false;
return pb_write(stream, buffer, size);
}
bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
{
/* First calculate the message size using a non-writing substream. */
pb_ostream_t substream = PB_OSTREAM_SIZING;
size_t size;
bool status;
if (!pb_encode(&substream, fields, src_struct))
{
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
return false;
}
size = substream.bytes_written;
if (!pb_encode_varint(stream, (pb_uint64_t)size))
return false;
if (stream->callback == NULL)
return pb_write(stream, NULL, size); /* Just sizing */
if (stream->bytes_written + size > stream->max_size)
PB_RETURN_ERROR(stream, "stream full");
/* Use a substream to verify that a callback doesn't write more than
* what it did the first time. */
substream.callback = stream->callback;
substream.state = stream->state;
substream.max_size = size;
substream.bytes_written = 0;
#ifndef PB_NO_ERRMSG
substream.errmsg = NULL;
#endif
status = pb_encode(&substream, fields, src_struct);
stream->bytes_written += substream.bytes_written;
stream->state = substream.state;
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
if (substream.bytes_written != size)
PB_RETURN_ERROR(stream, "submsg size changed");
return status;
}
/* Field encoders */
static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field)
{
uint32_t value = safe_read_bool(field->pData) ? 1 : 0;
PB_UNUSED(field);
return pb_encode_varint(stream, value);
}
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
{
/* Perform unsigned integer extension */
pb_uint64_t value = 0;
if (field->data_size == sizeof(uint_least8_t))
value = *(const uint_least8_t*)field->pData;
else if (field->data_size == sizeof(uint_least16_t))
value = *(const uint_least16_t*)field->pData;
else if (field->data_size == sizeof(uint32_t))
value = *(const uint32_t*)field->pData;
else if (field->data_size == sizeof(pb_uint64_t))
value = *(const pb_uint64_t*)field->pData;
else
PB_RETURN_ERROR(stream, "invalid data_size");
return pb_encode_varint(stream, value);
}
else
{
/* Perform signed integer extension */
pb_int64_t value = 0;
if (field->data_size == sizeof(int_least8_t))
value = *(const int_least8_t*)field->pData;
else if (field->data_size == sizeof(int_least16_t))
value = *(const int_least16_t*)field->pData;
else if (field->data_size == sizeof(int32_t))
value = *(const int32_t*)field->pData;
else if (field->data_size == sizeof(pb_int64_t))
value = *(const pb_int64_t*)field->pData;
else
PB_RETURN_ERROR(stream, "invalid data_size");
if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
return pb_encode_svarint(stream, value);
#ifdef PB_WITHOUT_64BIT
else if (value < 0)
return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1);
#endif
else
return pb_encode_varint(stream, (pb_uint64_t)value);
}
}
static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
return pb_encode_float_as_double(stream, *(float*)field->pData);
}
#endif
if (field->data_size == sizeof(uint32_t))
{
return pb_encode_fixed32(stream, field->pData);
}
#ifndef PB_WITHOUT_64BIT
else if (field->data_size == sizeof(uint64_t))
{
return pb_encode_fixed64(stream, field->pData);
}
#endif
else
{
PB_RETURN_ERROR(stream, "invalid data_size");
}
}
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
{
const pb_bytes_array_t *bytes = NULL;
bytes = (const pb_bytes_array_t*)field->pData;
if (bytes == NULL)
{
/* Treat null pointer as an empty bytes field */
return pb_encode_string(stream, NULL, 0);
}
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
{
PB_RETURN_ERROR(stream, "bytes size exceeded");
}
return pb_encode_string(stream, bytes->bytes, (size_t)bytes->size);
}
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field)
{
size_t size = 0;
size_t max_size = (size_t)field->data_size;
const char *str = (const char*)field->pData;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
max_size = (size_t)-1;
}
else
{
/* pb_dec_string() assumes string fields end with a null
* terminator when the type isn't PB_ATYPE_POINTER, so we
* shouldn't allow more than max-1 bytes to be written to
* allow space for the null terminator.
*/
if (max_size == 0)
PB_RETURN_ERROR(stream, "zero-length string");
max_size -= 1;
}
if (str == NULL)
{
size = 0; /* Treat null pointer as an empty string */
}
else
{
const char *p = str;
/* strnlen() is not always available, so just use a loop */
while (size < max_size && *p != '\0')
{
size++;
p++;
}
if (*p != '\0')
{
PB_RETURN_ERROR(stream, "unterminated string");
}
}
#ifdef PB_VALIDATE_UTF8
if (!pb_validate_utf8(str))
PB_RETURN_ERROR(stream, "invalid utf8");
#endif
return pb_encode_string(stream, (const pb_byte_t*)str, size);
}
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (field->submsg_desc == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor");
if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
{
/* Message callback is stored right before pSize. */
pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
if (callback->funcs.encode)
{
if (!callback->funcs.encode(stream, field, &callback->arg))
return false;
}
}
return pb_encode_submessage(stream, field->submsg_desc, field->pData);
}
static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
{
return pb_encode_string(stream, (const pb_byte_t*)field->pData, (size_t)field->data_size);
}
#ifdef PB_CONVERT_DOUBLE_FLOAT
bool pb_encode_float_as_double(pb_ostream_t *stream, float value)
{
union { float f; uint32_t i; } in;
uint_least8_t sign;
int exponent;
uint64_t mantissa;
in.f = value;
/* Decompose input value */
sign = (uint_least8_t)((in.i >> 31) & 1);
exponent = (int)((in.i >> 23) & 0xFF) - 127;
mantissa = in.i & 0x7FFFFF;
if (exponent == 128)
{
/* Special value (NaN etc.) */
exponent = 1024;
}
else if (exponent == -127)
{
if (!mantissa)
{
/* Zero */
exponent = -1023;
}
else
{
/* Denormalized */
mantissa <<= 1;
while (!(mantissa & 0x800000))
{
mantissa <<= 1;
exponent--;
}
mantissa &= 0x7FFFFF;
}
}
/* Combine fields */
mantissa <<= 29;
mantissa |= (uint64_t)(exponent + 1023) << 52;
mantissa |= (uint64_t)sign << 63;
return pb_encode_fixed64(stream, &mantissa);
}
#endif
================================================
FILE: c/core/src/tahu.c
================================================
/********************************************************************************
* Copyright (c) 2014-2019 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
#include
#include
#include
#include
#include
#include
#include
static uint8_t payload_sequence;
int add_metadata_to_metric(org_eclipse_tahu_protobuf_Payload_Metric *metric,
org_eclipse_tahu_protobuf_Payload_MetaData *metadata) {
DEBUG_PRINT("Adding metadata...\n");
metric->has_metadata = true;
memcpy(&metric->metadata, metadata, sizeof(metric->metadata));
return 0;
}
int add_metric_to_payload(org_eclipse_tahu_protobuf_Payload *payload,
org_eclipse_tahu_protobuf_Payload_Metric *metric) {
DEBUG_PRINT("Adding metric to payload...\n");
const int old_count = payload->metrics_count;
const int new_count = (old_count + 1);
const size_t new_allocation_size = sizeof(org_eclipse_tahu_protobuf_Payload_Metric) * new_count;
void *realloc_result = realloc(payload->metrics, new_allocation_size);
//DEBUG_PRINT("realloc_result=%p\n", realloc_result);
if (realloc_result == NULL) {
fprintf(stderr, "realloc failed in add_metric_to_payload\n");
return -1;
}
payload->metrics = realloc_result;
payload->metrics_count = new_count;
memcpy(&payload->metrics[old_count], metric, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
return 0;
}
int set_propertyvalue(org_eclipse_tahu_protobuf_Payload_PropertyValue *propertyvalue,
uint32_t datatype,
const void *value,
size_t size) {
DEBUG_PRINT("Set property value...\n");
switch (datatype) {
case PROPERTY_DATA_TYPE_INT8:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag;
propertyvalue->value.int_value = *(int8_t *)value;
break;
case PROPERTY_DATA_TYPE_INT16:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag;
propertyvalue->value.int_value = *(int16_t *)value;
break;
case PROPERTY_DATA_TYPE_INT32:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag;
propertyvalue->value.int_value = *(int32_t *)value;
break;
case PROPERTY_DATA_TYPE_INT64:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_long_value_tag;
propertyvalue->value.long_value = *(int64_t *)value;
break;
case PROPERTY_DATA_TYPE_UINT8:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag;
propertyvalue->value.int_value = *(uint8_t *)value;
break;
case PROPERTY_DATA_TYPE_UINT16:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag;
propertyvalue->value.int_value = *(uint16_t *)value;
break;
case PROPERTY_DATA_TYPE_UINT32:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_long_value_tag;
propertyvalue->value.long_value = *(uint32_t *)value;
break;
case PROPERTY_DATA_TYPE_UINT64:
case PROPERTY_DATA_TYPE_DATETIME:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_long_value_tag;
propertyvalue->value.long_value = *(uint64_t *)value;
break;
case PROPERTY_DATA_TYPE_FLOAT:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_float_value_tag;
propertyvalue->value.float_value = *(float *)value;
break;
case PROPERTY_DATA_TYPE_DOUBLE:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_double_value_tag;
propertyvalue->value.double_value = *(double *)value;
break;
case PROPERTY_DATA_TYPE_BOOLEAN:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_boolean_value_tag;
propertyvalue->value.boolean_value = *(bool *)value;
break;
case PROPERTY_DATA_TYPE_STRING:
case PROPERTY_DATA_TYPE_TEXT:
propertyvalue->which_value = org_eclipse_tahu_protobuf_Payload_PropertyValue_string_value_tag;
propertyvalue->value.string_value = strndup(value, size);
break;
default:
fprintf(stderr, "Invalid datatype(%u) in set_propertyvalue\n", datatype);
return -1;
}
return 0;
}
int add_property_to_set(org_eclipse_tahu_protobuf_Payload_PropertySet *propertyset,
const char *key,
uint32_t datatype,
const void *value,
size_t size_of_value) {
DEBUG_PRINT("Add property to set...\n");
if (propertyset->keys_count != propertyset->values_count) {
fprintf(stderr, "Mismatched key/value counts in add_property_to_set\n");
return -1;
}
const int old_count = propertyset->keys_count;
const int new_count = (old_count + 1);
const size_t key_allocation_size = sizeof(char *) * new_count;
const size_t value_allocation_size = sizeof(org_eclipse_tahu_protobuf_Payload_PropertyValue) * new_count;
void *key_allocation_result = realloc(propertyset->keys, key_allocation_size);
void *value_allocation_result = realloc(propertyset->values, value_allocation_size);
//DEBUG_PRINT("key=%p value=%p\n", key_allocation_result, value_allocation_result);
if ((key_allocation_result == NULL) || (value_allocation_result == NULL)) {
fprintf(stderr, "realloc failed in add_metric_to_payload\n");
return -1;
}
propertyset->keys = key_allocation_result;
propertyset->keys_count = new_count;
propertyset->values = value_allocation_result;
propertyset->values_count = new_count;
propertyset->keys[old_count] = strdup(key);
if (propertyset->keys[old_count] == NULL) {
fprintf(stderr, "strdup failed in add_metric_to_payload\n");
return -1;
}
memset(&propertyset->values[old_count], 0, sizeof(org_eclipse_tahu_protobuf_Payload_PropertyValue));
propertyset->values[old_count].has_type = true;
propertyset->values[old_count].type = datatype;
if (value == NULL) {
propertyset->values[old_count].has_is_null = true;
propertyset->values[old_count].is_null = true;
} else {
set_propertyvalue(&propertyset->values[old_count], datatype, value, size_of_value);
}
return 0;
}
int add_propertyset_to_metric(org_eclipse_tahu_protobuf_Payload_Metric *metric,
org_eclipse_tahu_protobuf_Payload_PropertySet *properties) {
DEBUG_PRINT("Add propertyset to metric...\n");
metric->has_properties = true;
memcpy(&metric->properties, properties, sizeof(metric->properties));
return 0;
}
int set_metric_value(org_eclipse_tahu_protobuf_Payload_Metric *metric, uint32_t datatype, const void *value, size_t size) {
DEBUG_PRINT("Set metric value...\n");
switch (datatype) {
case METRIC_DATA_TYPE_INT8:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag;
metric->value.int_value = *(int8_t *)value;
break;
case METRIC_DATA_TYPE_INT16:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag;
metric->value.int_value = *(int16_t *)value;
break;
case METRIC_DATA_TYPE_INT32:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag;
metric->value.int_value = *(int32_t *)value;
break;
case METRIC_DATA_TYPE_INT64:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_long_value_tag;
metric->value.long_value = *(int64_t *)value;
break;
case METRIC_DATA_TYPE_UINT8:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag;
metric->value.int_value = *(uint8_t *)value;
break;
case METRIC_DATA_TYPE_UINT16:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag;
metric->value.int_value = *(uint16_t *)value;
break;
case METRIC_DATA_TYPE_UINT32:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_long_value_tag;
metric->value.long_value = *(uint32_t *)value;
break;
case METRIC_DATA_TYPE_UINT64:
case METRIC_DATA_TYPE_DATETIME:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_long_value_tag;
metric->value.long_value = *(uint64_t *)value;
break;
case METRIC_DATA_TYPE_FLOAT:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_float_value_tag;
metric->value.float_value = *(float *)value;
break;
case METRIC_DATA_TYPE_DOUBLE:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_double_value_tag;
metric->value.double_value = *(double *)value;
break;
case METRIC_DATA_TYPE_BOOLEAN:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_boolean_value_tag;
metric->value.boolean_value = *(bool *)value;
break;
case METRIC_DATA_TYPE_STRING:
case METRIC_DATA_TYPE_TEXT:
case METRIC_DATA_TYPE_UUID:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_string_value_tag;
metric->value.string_value = strndup(value, size);
break;
case METRIC_DATA_TYPE_DATASET:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_dataset_value_tag;
memcpy(&metric->value.dataset_value, value, sizeof(metric->value.dataset_value));
break;
case METRIC_DATA_TYPE_TEMPLATE:
metric->which_value = org_eclipse_tahu_protobuf_Payload_Metric_template_value_tag;
memcpy(&metric->value.template_value, value, sizeof(metric->value.template_value));
break;
case METRIC_DATA_TYPE_BYTES:
case METRIC_DATA_TYPE_FILE:
case METRIC_DATA_TYPE_UNKNOWN:
default:
fprintf(stderr, "Unhandled datatype(%u) in set_metric_value\n", datatype);
return -1;
}
return 0;
}
int add_simple_metric(org_eclipse_tahu_protobuf_Payload *payload,
const char *name,
bool has_alias,
uint64_t alias,
uint64_t datatype,
bool is_historical,
bool is_transient,
const void *value,
size_t size_of_value) {
DEBUG_PRINT("Add simple metric...\n");
org_eclipse_tahu_protobuf_Payload_Metric new_metric;
memset(&new_metric, 0, sizeof(new_metric));
if (name != NULL) {
new_metric.name = strdup(name);
if (new_metric.name == NULL) {
fprintf(stderr, "strdup name failed in add_simple_metric\n");
return -1;
}
}
new_metric.has_alias = has_alias;
new_metric.alias = alias;
new_metric.has_timestamp = true;
new_metric.timestamp = get_current_timestamp();
new_metric.has_datatype = true;
new_metric.datatype = datatype;
if (is_historical) {
new_metric.has_is_historical = true;
new_metric.is_historical = true;
}
if (is_transient) {
new_metric.has_is_transient = true;
new_metric.is_transient = true;
}
if (value == NULL) {
new_metric.has_is_null = true;
new_metric.is_null = true;
} else {
set_metric_value(&new_metric, datatype, value, size_of_value);
}
add_metric_to_payload(payload, &new_metric);
return 0;
}
ssize_t encode_payload(uint8_t *out_buffer,
size_t buffer_length,
const org_eclipse_tahu_protobuf_Payload *payload) {
// Use a different stream if the user wants a normal encode or just a size check
pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
pb_ostream_t buffer_stream = pb_ostream_from_buffer(out_buffer, buffer_length);
pb_ostream_t *node_stream = ((out_buffer == NULL) ? &sizing_stream : &buffer_stream);
// Encode the payload
DEBUG_PRINT("Encoding payload...\n");
const bool encode_result = pb_encode(node_stream, org_eclipse_tahu_protobuf_Payload_fields, payload);
const size_t message_length = node_stream->bytes_written;
DEBUG_PRINT("Message length: %zd\n", message_length);
// Error Check
if (!encode_result) {
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(node_stream));
return -1;
}
DEBUG_PRINT("Encoding succeeded\n");
return message_length;
}
ssize_t decode_payload(org_eclipse_tahu_protobuf_Payload *payload,
const uint8_t *in_buffer,
size_t buffer_length) {
DEBUG_PRINT("Decoding payload...\n");
pb_istream_t node_stream = pb_istream_from_buffer(in_buffer, buffer_length);
memset(payload, 0, sizeof(org_eclipse_tahu_protobuf_Payload));
const bool decode_result = pb_decode(&node_stream, org_eclipse_tahu_protobuf_Payload_fields, payload);
if (!decode_result) {
fprintf(stderr, "Decoding failed: %s\n", PB_GET_ERROR(&node_stream));
return -1;
}
#ifdef SPARKPLUG_DEBUG
// Print the message data
print_payload(payload);
#endif
return node_stream.bytes_left;
}
int free_payload(org_eclipse_tahu_protobuf_Payload *payload) {
DEBUG_PRINT("Free payload memory...\n");
pb_release(org_eclipse_tahu_protobuf_Payload_fields, payload);
return 0;
}
uint64_t get_current_timestamp() {
// Set the timestamp
struct timespec ts;
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif
return ts.tv_sec * UINT64_C(1000) + ts.tv_nsec / 1000000;
}
void reset_sparkplug_sequence(void) {
payload_sequence = 0;
}
int get_next_payload(org_eclipse_tahu_protobuf_Payload *payload) {
// Initialize payload
DEBUG_PRINT("Current Sequence Number: %u\n", payload_sequence);
memset(payload, 0, sizeof(org_eclipse_tahu_protobuf_Payload));
payload->has_timestamp = true;
payload->timestamp = get_current_timestamp();
payload->has_seq = true;
payload->seq = payload_sequence;
// Increment/wrap the sequence number (stored in a U8, so it
// will wrap 255-to-0 automatically)
payload_sequence++;
return 0;
}
int init_dataset(org_eclipse_tahu_protobuf_Payload_DataSet *dataset,
uint64_t num_of_rows,
uint64_t num_of_columns,
const uint32_t datatypes[],
const char *column_keys[],
const org_eclipse_tahu_protobuf_Payload_DataSet_Row row_data[]) {
DEBUG_PRINT("Init dataset...\n");
memset(dataset, 0, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet));
dataset->has_num_of_columns = true;
dataset->num_of_columns = num_of_columns;
dataset->columns_count = num_of_columns;
const size_t key_size = num_of_columns * sizeof(char *);
dataset->columns = malloc(key_size);
if (dataset->columns == NULL) {
fprintf(stderr, "malloc(%lu) failure in init_dataset\n", key_size);
return -1;
}
for (int i = 0; i < num_of_columns; i++) {
dataset->columns[i] = strdup(column_keys[i]);
if (dataset->columns[i] == NULL) {
fprintf(stderr, "strdup failed in init_dataset\n");
return -1;
}
}
dataset->types_count = num_of_columns;
const size_t datatypes_size = num_of_columns * sizeof(uint32_t);
dataset->types = malloc(datatypes_size);
if (dataset->types == NULL) {
fprintf(stderr, "malloc(%lu) failure in init_dataset\n", datatypes_size);
return -1;
}
memcpy(dataset->types, datatypes, datatypes_size);
dataset->rows_count = num_of_rows;
const size_t row_data_size = num_of_rows * sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_Row);
dataset->rows = malloc(row_data_size);
if (dataset->rows == NULL) {
fprintf(stderr, "malloc(%lu) failure in init_dataset\n", row_data_size);
return -1;
}
memcpy(dataset->rows, row_data, row_data_size);
return 0;
}
int init_metric(org_eclipse_tahu_protobuf_Payload_Metric *metric,
const char *name,
bool has_alias,
uint64_t alias,
uint64_t datatype,
bool is_historical,
bool is_transient,
const void *value,
size_t size_of_value) {
DEBUG_PRINT("Init metric...\n");
memset(metric, 0, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
if (name != NULL) {
metric->name = strdup(name);
if (metric->name == NULL) {
fprintf(stderr, "strdup failed to copy metric name\n");
return -1;
}
}
if (has_alias) {
metric->has_alias = true;
metric->alias = alias;
}
if (is_historical && !is_transient) {
metric->has_timestamp = true;
metric->timestamp = get_current_timestamp();
}
metric->has_datatype = true;
metric->datatype = datatype;
if (is_historical) {
metric->has_is_historical = true;
metric->is_historical = true;
}
if (is_transient) {
metric->has_is_transient = true;
metric->is_transient = true;
}
if (value == NULL) {
metric->has_is_null = true;
metric->is_null = true;
} else {
return set_metric_value(metric, datatype, value, size_of_value);
}
// No support for metadata or properties in this function...
return 0;
}
/*
* Display a full Sparkplug Payload
*/
#define PP(...) fprintf(stdout,__VA_ARGS__)
#define EMPTY_PREFIX ""
void print_metadata(const char *prefix, org_eclipse_tahu_protobuf_Payload_MetaData *metadata);
void print_propertyvalue(const char *prefix, org_eclipse_tahu_protobuf_Payload_PropertyValue *value);
void print_propertyset(const char *prefix, org_eclipse_tahu_protobuf_Payload_PropertySet *properties);
void print_propertysetlist(const char *prefix, org_eclipse_tahu_protobuf_Payload_PropertySetList *propertysetlist);
void print_dataset_row(const char *prefix, org_eclipse_tahu_protobuf_Payload_DataSet_Row *row);
void print_datasetvalue(const char *prefix, org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *dsvalue);
void print_dataset(const char *prefix, org_eclipse_tahu_protobuf_Payload_DataSet *dataset_value);
void print_template_parameter(const char *prefix, org_eclipse_tahu_protobuf_Payload_Template_Parameter *template_parameter);
void print_template(const char *prefix, org_eclipse_tahu_protobuf_Payload_Template *template);
void print_metric(const char *prefix, org_eclipse_tahu_protobuf_Payload_Metric *metric);
void print_payload(org_eclipse_tahu_protobuf_Payload *payload);
void print_metadata(const char *prefix, org_eclipse_tahu_protobuf_Payload_MetaData *metadata) {
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
if (metadata->has_is_multi_part) {
PP("%sis_multi_part=%u\n", prefix, metadata->is_multi_part);
}
if (metadata->content_type != NULL) {
PP("%scontent_type=%s [%p]\n", prefix, metadata->content_type, metadata->content_type);
}
if (metadata->has_size) {
PP("%shas_size=%lu\n", prefix, metadata->size);
}
if (metadata->has_seq) {
PP("%sseq=%lu\n", prefix, metadata->seq);
}
if (metadata->file_name != NULL) {
PP("%sfile_name=%s [%p]\n", prefix, metadata->file_name, metadata->file_name);
}
if (metadata->file_type != NULL) {
PP("%sfile_type=%s [%p]\n", prefix, metadata->file_type, metadata->file_type);
}
if (metadata->md5 != NULL) {
PP("%smd5=%s [%p]\n", prefix, metadata->md5, metadata->md5);
}
if (metadata->description != NULL) {
PP("%sdescription=%s [%p]\n", prefix, metadata->description, metadata->description);
}
if (metadata->extensions != NULL) {
PP("%sextensions=[%p] (display not supported)\n", prefix, metadata->extensions);
}
}
void print_propertyvalue(const char *prefix, org_eclipse_tahu_protobuf_Payload_PropertyValue *value) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
if (value->has_type) {
PP("%stype=%u\n", prefix, value->type);
}
if (value->has_is_null) {
PP("%sis_null=%u\n", prefix, value->is_null);
}
switch (value->which_value) {
case org_eclipse_tahu_protobuf_Payload_PropertyValue_int_value_tag:
PP("%sint_value=%d\n", prefix, value->value.int_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_long_value_tag:
PP("%slong_value=%ld\n", prefix, value->value.long_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_float_value_tag:
PP("%sfloat_value=%f\n", prefix, value->value.float_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_double_value_tag:
PP("%sdouble_value=%f\n", prefix, value->value.double_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_boolean_value_tag:
PP("%sboolean_value=%u\n", prefix, value->value.boolean_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_string_value_tag:
PP("%sstring_value=%s [%p]\n", prefix, value->value.string_value, value->value.string_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_propertyset_value_tag:
snprintf(temp, sizeof(temp), "%spropertyset.", prefix);
print_propertyset(temp, &value->value.propertyset_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_propertysets_value_tag:
snprintf(temp, sizeof(temp), "%spropertysets.", prefix);
print_propertysetlist(temp, &value->value.propertysets_value);
break;
case org_eclipse_tahu_protobuf_Payload_PropertyValue_extension_value_tag:
PP("%sextension_value=[%p] (display not supported)\n", prefix, value->value.extension_value.extensions);
break;
default:
PP("%sinvalid which_value=%u\n", prefix, value->which_value);
}
}
void print_propertyset(const char *prefix, org_eclipse_tahu_protobuf_Payload_PropertySet *properties) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
PP("%skeys=[%p] (count=%u)\n", prefix, properties->keys, properties->keys_count);
for (int i = 0; i < properties->keys_count; i++) {
PP("%s keys[%u]=%s [%p]\n", prefix, i, properties->keys[i], properties->keys[i]);
}
PP("%svalues=[%p] (count=%u)\n", prefix, properties->values, properties->values_count);
for (int i = 0; i < properties->values_count; i++) {
snprintf(temp, sizeof(temp), "%svalues[%u].", prefix, i);
print_propertyvalue(temp, &properties->values[i]);
}
if (properties->extensions != NULL) {
PP("%sextension=[%p] (display not supported)\n", prefix, properties->extensions);
}
}
void print_propertysetlist(const char *prefix, org_eclipse_tahu_protobuf_Payload_PropertySetList *propertysetlist) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
// pb_size_t propertyset_count;
// struct _org_eclipse_tahu_protobuf_Payload_PropertySet *propertyset;
PP("%spropertyset=[%p] (count=%u)\n", prefix, propertysetlist->propertyset, propertysetlist->propertyset_count);
for (int i = 0; i < propertysetlist->propertyset_count; i++) {
snprintf(temp, sizeof(temp), "%s.propertyset[%u].", prefix, i);
print_propertyset(temp, &propertysetlist->propertyset[i]);
}
if (propertysetlist->extensions != NULL) {
PP("%sextensions=[%p] (display not supported)\n", prefix, propertysetlist->extensions);
}
}
void print_dataset_row(const char *prefix, org_eclipse_tahu_protobuf_Payload_DataSet_Row *row) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
PP("%selements=[%p] (count=%u)\n", prefix, row->elements, row->elements_count);
for (int i = 0; i < row->elements_count; i++) {
snprintf(temp, sizeof(temp), "%selements[%u].", prefix, i);
print_datasetvalue(temp, &row->elements[i]);
}
if (row->extensions != NULL) {
PP("%selements=[%p] (display not supported)\n", prefix, row->extensions);
}
}
void print_datasetvalue(const char *prefix, org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *dsvalue) {
switch (dsvalue->which_value) {
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag:
PP("%sint_value=%d\n", prefix, dsvalue->value.int_value);
break;
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_long_value_tag:
PP("%slong_value=%ld\n", prefix, dsvalue->value.long_value);
break;
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_float_value_tag:
PP("%sfloat_value=%f\n", prefix, dsvalue->value.float_value);
break;
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_double_value_tag:
PP("%sdouble_value=%f\n", prefix, dsvalue->value.double_value);
break;
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_boolean_value_tag:
PP("%sboolean_value=%u\n", prefix, dsvalue->value.boolean_value);
break;
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_string_value_tag:
PP("%sstring_value=%s [%p]\n", prefix, dsvalue->value.string_value, dsvalue->value.string_value);
break;
case org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_extension_value_tag:
PP("%sextension_value=[%p] (display not supported)\n", prefix, dsvalue->value.extension_value.extensions);
break;
default:
PP("%sinvalid which_value=%u\n", prefix, dsvalue->which_value);
}
}
void print_dataset(const char *prefix, org_eclipse_tahu_protobuf_Payload_DataSet *dataset_value) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
if (dataset_value->has_num_of_columns) {
PP("%snum_of_columns=%lu\n", prefix, dataset_value->num_of_columns);
}
PP("%scolumns=[%p] (count=%u)\n", prefix, dataset_value->columns, dataset_value->columns_count);
for (int i = 0; i < dataset_value->columns_count; i++) {
PP("%scolumn[%u]=%s [%p]\n", prefix, i, dataset_value->columns[i], dataset_value->columns[i]);
}
PP("%stypes=[%p] (count=%u)\n", prefix, dataset_value->types, dataset_value->types_count);
for (int i = 0; i < dataset_value->types_count; i++) {
PP("%stype[%u]=%u\n", prefix, i, dataset_value->types[i]);
}
PP("%srows=[%p] (count=%u)\n", prefix, dataset_value->rows, dataset_value->rows_count);
for (int i = 0; i < dataset_value->rows_count; i++) {
snprintf(temp, sizeof(temp), "%srow[%u].", prefix, i);
print_dataset_row(temp, &dataset_value->rows[i]);
}
if (dataset_value->extensions != NULL) {
PP("%sextensions=[%p]\n", prefix, dataset_value->extensions);
}
}
void print_template_parameter(const char *prefix, org_eclipse_tahu_protobuf_Payload_Template_Parameter *template_parameter) {
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
// char *name;
if (template_parameter->name != NULL) {
PP("%sname=%s [%p]\n", prefix, template_parameter->name, template_parameter->name);
}
if (template_parameter->has_type) {
PP("%stype=%u\n", prefix, template_parameter->type);
}
// pb_size_t which_value;
switch (template_parameter->which_value) {
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_int_value_tag:
PP("%sint_value=%d\n", prefix, template_parameter->value.int_value);
break;
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_long_value_tag:
PP("%slong_value=%ld\n", prefix, template_parameter->value.long_value);
break;
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_float_value_tag:
PP("%sfloat_value=%f\n", prefix, template_parameter->value.float_value);
break;
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_double_value_tag:
PP("%sdouble_value=%f\n", prefix, template_parameter->value.double_value);
break;
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_boolean_value_tag:
PP("%sboolean_value=%u\n", prefix, template_parameter->value.boolean_value);
break;
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag:
PP("%sstring_value=%s [%p]\n", prefix, template_parameter->value.string_value, template_parameter->value.string_value);
break;
case org_eclipse_tahu_protobuf_Payload_Template_Parameter_extension_value_tag:
PP("%sextension_value=[%p] (display not supported)\n", prefix, template_parameter->value.extension_value.extensions);
break;
default:
PP("%sinvalid which_value=%u\n", prefix, template_parameter->which_value);
}
}
void print_template(const char *prefix, org_eclipse_tahu_protobuf_Payload_Template *template) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
if (template->version != NULL) {
PP("%sversion=%s [%p]\n", prefix, template->version, template->version);
}
PP("%smetrics=[%p] (count=%u)\n", prefix, template->metrics, template->metrics_count);
for (int i = 0; i < template->metrics_count; i++) {
snprintf(temp, sizeof(temp), "%smetric[%u].", prefix, i);
print_metric(temp, &template->metrics[i]);
}
PP("%sparameters=[%p] (count=%u)\n", prefix, template->parameters, template->parameters_count);
for (int i = 0; i < template->parameters_count; i++) {
snprintf(temp, sizeof(temp), "%sparameter[%u].", prefix, i);
print_template_parameter(temp, &template->parameters[i]);
}
if (template->template_ref != NULL) {
PP("%stemplate_ref=%s [%p]\n", prefix, template->template_ref, template->template_ref);
}
if (template->has_is_definition) {
PP("%sis_definition=%u\n", prefix, template->is_definition);
}
if (template->extensions != NULL) {
PP("%sextensions=[%p] (display not supported)\n", prefix, template->extensions);
}
}
void print_metric(const char *prefix, org_eclipse_tahu_protobuf_Payload_Metric *metric) {
char temp[64];
if (prefix == NULL) {
prefix = EMPTY_PREFIX;
}
if (metric->name != NULL) {
PP("%sname=%s [%p]\n", prefix, metric->name, metric->name);
}
if (metric->has_alias) {
PP("%salias=%ld\n", prefix, metric->alias);
}
if (metric->has_timestamp) {
PP("%stimestamp=%ld\n", prefix, metric->timestamp);
}
if (metric->has_datatype) {
PP("%sdatatype=%u\n", prefix, metric->datatype);
}
if (metric->has_is_historical) {
PP("%sis_historical=%u\n", prefix, metric->is_historical);
}
if (metric->has_is_transient) {
PP("%sis_transient=%u\n", prefix, metric->is_transient);
}
if (metric->has_is_null) {
PP("%sis_null=%u\n", prefix, metric->is_null);
}
if (metric->has_metadata) {
snprintf(temp, sizeof(temp), "%smetadata.", prefix);
print_metadata(temp, &metric->metadata);
}
if (metric->has_properties) {
snprintf(temp, sizeof(temp), "%sproperties.", prefix);
print_propertyset(temp, &metric->properties);
}
switch (metric->which_value) {
case org_eclipse_tahu_protobuf_Payload_Metric_int_value_tag:
PP("%sint_value=%d\n", prefix, metric->value.int_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_long_value_tag:
PP("%slong_value=%ld\n", prefix, metric->value.long_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_float_value_tag:
PP("%sfloat_value=%f\n", prefix, metric->value.float_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_double_value_tag:
PP("%sdouble_value=%f\n", prefix, metric->value.double_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_boolean_value_tag:
PP("%sboolean_value=%d\n", prefix, metric->value.boolean_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_string_value_tag:
PP("%sstring_value=%s [%p]\n", prefix, metric->value.string_value, metric->value.string_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_dataset_value_tag:
snprintf(temp, sizeof(temp), "%sdataset.", prefix);
print_dataset(temp, &metric->value.dataset_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_bytes_value_tag:
PP("%sbytes_value=[%p] (display not supported)\n", prefix, metric->value.bytes_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_template_value_tag:
snprintf(temp, sizeof(temp), "%stemplate.", prefix);
print_template(temp, &metric->value.template_value);
break;
case org_eclipse_tahu_protobuf_Payload_Metric_extension_value_tag:
PP("%sextension_value=[%p] (display not supported)\n", prefix, metric->value.extension_value.extensions);
break;
default:
PP("%sinvalid which_type=%u", prefix, metric->which_value);
break;
}
}
void print_payload(org_eclipse_tahu_protobuf_Payload *payload) {
char temp[64];
PP("-----PAYLOAD BEGIN-----\n");
if (payload->has_timestamp) {
PP("timestamp=%ld\n", payload->timestamp);
}
if (payload->has_seq) {
PP("seq=%ld\n", payload->seq);
}
if (payload->uuid != NULL) {
PP("uuid=%s [%p]\n", payload->uuid, payload->uuid);
}
if (payload->body != NULL) {
PP("body=[%p] (display not supported)\n", payload->body);
}
if (payload->extensions != NULL) {
PP("extensions=[%p] (display not supported)\n", payload->extensions);
}
PP("metrics=[%p] (count=%u)\n", payload->metrics, payload->metrics_count);
for (int i = 0; i < payload->metrics_count; i++) {
snprintf(temp, sizeof(temp), "metric[%u].", i);
print_metric(temp, &payload->metrics[i]);
}
PP("-----PAYLOAD END-----\n");
}
================================================
FILE: c/core/src/tahu.pb.c
================================================
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.1 */
#include "tahu.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(org_eclipse_tahu_protobuf_Payload, org_eclipse_tahu_protobuf_Payload, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_Template, org_eclipse_tahu_protobuf_Payload_Template, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_Template_Parameter, org_eclipse_tahu_protobuf_Payload_Template_Parameter, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension, org_eclipse_tahu_protobuf_Payload_Template_Parameter_ParameterValueExtension, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_DataSet, org_eclipse_tahu_protobuf_Payload_DataSet, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue, org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension, org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_DataSetValueExtension, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_DataSet_Row, org_eclipse_tahu_protobuf_Payload_DataSet_Row, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_PropertyValue, org_eclipse_tahu_protobuf_Payload_PropertyValue, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension, org_eclipse_tahu_protobuf_Payload_PropertyValue_PropertyValueExtension, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_PropertySet, org_eclipse_tahu_protobuf_Payload_PropertySet, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_PropertySetList, org_eclipse_tahu_protobuf_Payload_PropertySetList, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_MetaData, org_eclipse_tahu_protobuf_Payload_MetaData, AUTO)
PB_BIND(org_eclipse_tahu_protobuf_Payload_Metric, org_eclipse_tahu_protobuf_Payload_Metric, 2)
PB_BIND(org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension, org_eclipse_tahu_protobuf_Payload_Metric_MetricValueExtension, AUTO)
================================================
FILE: c/core/tahu.options
================================================
org.eclipse.tahu.protobuf.Payload.body type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.metrics type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.uuid type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.DataSet.columns type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.DataSet.rows type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.DataSet.types type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.DataSet.DataSetValue.string_value type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.DataSet.Row.elements type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.MetaData.content_type type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.MetaData.description type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.MetaData.file_name type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.MetaData.file_type type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.MetaData.md5 type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Metric.bytes_value type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Metric.name type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Metric.string_value type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.PropertySet.keys type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.PropertySet.values type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.PropertySetList.propertyset type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.PropertyValue.string_value type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Template.metrics type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Template.template_ref type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Template.version type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Template.parameters type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Template.Parameter.name type:FT_POINTER
org.eclipse.tahu.protobuf.Payload.Template.Parameter.string_value type:FT_POINTER
================================================
FILE: c/core/test/.gitignore
================================================
test_dynamic.dSYM
test_static.dSYM
================================================
FILE: c/core/test/test.c
================================================
/********************************************************************************
* Copyright (c) 2014-2019 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Local Functions */
void publisher(struct mosquitto *mosq, char *topic, void *buf, unsigned len);
void publish_births(struct mosquitto *mosq);
void publish_node_birth(struct mosquitto *mosq);
void publish_device_birth(struct mosquitto *mosq);
void publish_ddata_message(struct mosquitto *mosq);
/* Mosquitto Callbacks */
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message);
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result);
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos);
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str);
uint64_t ALIAS_NODE_CONTROL_NEXT_SERVER = 0;
uint64_t ALIAS_NODE_CONTROL_REBIRTH = 1;
uint64_t ALIAS_NODE_CONTROL_REBOOT = 2;
uint64_t ALIAS_NODE_METRIC_0 = 3;
uint64_t ALIAS_NODE_METRIC_1 = 4;
uint64_t ALIAS_NODE_METRIC_UINT32 = 5;
uint64_t ALIAS_NODE_METRIC_FLOAT = 6;
uint64_t ALIAS_NODE_METRIC_DOUBLE = 7;
uint64_t ALIAS_NODE_METRIC_DATASET = 8;
uint64_t ALIAS_NODE_METRIC_2 = 9;
uint64_t ALIAS_DEVICE_METRIC_0 = 10;
uint64_t ALIAS_DEVICE_METRIC_1 = 11;
uint64_t ALIAS_DEVICE_METRIC_2 = 12;
uint64_t ALIAS_DEVICE_METRIC_3 = 13;
uint64_t ALIAS_DEVICE_METRIC_UDT_INST = 14;
uint64_t ALIAS_DEVICE_METRIC_INT8 = 15;
uint64_t ALIAS_DEVICE_METRIC_UINT32 = 16;
uint64_t ALIAS_DEVICE_METRIC_FLOAT = 17;
uint64_t ALIAS_DEVICE_METRIC_DOUBLE = 18;
uint64_t ALIAS_NODE_METRIC_I8 = 19;
uint64_t ALIAS_NODE_METRIC_I16 = 20;
uint64_t ALIAS_NODE_METRIC_I32 = 21;
uint64_t ALIAS_NODE_METRIC_I64 = 22;
uint64_t ALIAS_NODE_METRIC_UI8 = 23;
uint64_t ALIAS_NODE_METRIC_UI16 = 24;
uint64_t ALIAS_NODE_METRIC_UI32 = 25;
uint64_t ALIAS_NODE_METRIC_UI64 = 26;
int main(int argc, char *argv[]) {
// MQTT Parameters
char *host = "broker.hivemq.com";
int port = 1883;
int keepalive = 60;
bool clean_session = true;
struct mosquitto *mosq = NULL;
// MQTT Setup
srand(time(NULL));
mosquitto_lib_init();
mosq = mosquitto_new(NULL, clean_session, NULL);
if (!mosq) {
fprintf(stderr, "Error: Out of memory.\n");
return 1;
}
fprintf(stdout, "Setting up callbacks\n");
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
mosquitto_username_pw_set(mosq, "admin", "changeme");
mosquitto_will_set(mosq, "spBv1.0/Sparkplug B Devices/NDEATH/C Edge Node 1", 0, NULL, 0, false);
// Optional 'self-signed' SSL parameters for MQTT
//mosquitto_tls_insecure_set(mosq, true);
//mosquitto_tls_opts_set(mosq, 0, "tlsv1.2", NULL); // 0 is DO NOT SSL_VERIFY_PEER
// Optional 'real' SSL parameters for MQTT
//mosquitto_tls_set(mosq, NULL, "/etc/ssl/certs/", NULL, NULL, NULL); // Necessary if the CA or other certs need to be picked up elsewhere on the local filesystem
//mosquitto_tls_insecure_set(mosq, false);
//mosquitto_tls_opts_set(mosq, 1, "tlsv1.2", NULL); // 1 is SSL_VERIFY_PEER
// MQTT Connect
fprintf(stdout, "Starting connection...\n");
if (mosquitto_connect(mosq, host, port, keepalive)) {
fprintf(stderr, "Unable to connect.\n");
return 1;
}
// Publish the NBIRTH and DBIRTH Sparkplug messages (Birth Certificates)
publish_births(mosq);
// Loop and publish more DDATA messages every 5 seconds. Note this should only be done in real/production
// scenarios with change events on inputs. Because Sparkplug ensures state there is no reason to send DDATA
// messages unless the state of a I/O point has changed.
int i;
for (i = 0; i < 100; i++) {
publish_ddata_message(mosq);
int j;
for (j = 0; j < 50; j++) {
usleep(100000);
mosquitto_loop(mosq, -1, 1);
}
}
//mosquitto_loop_forever(mosq, -1, 1);
// Close and cleanup
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
/*
* Callback for incoming MQTT messages. Since this is a Sparkplug implementation these will be NCMD and DCMD messages
*/
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) {
if (message->payloadlen) {
fprintf(stdout, "%s :: %d\n", message->topic, message->payloadlen);
} else {
fprintf(stdout, "%s (null)\n", message->topic);
}
fflush(stdout);
// Decode the payload
org_eclipse_tahu_protobuf_Payload inbound_payload = org_eclipse_tahu_protobuf_Payload_init_zero;
if (decode_payload(&inbound_payload, message->payload, message->payloadlen) < 0) {
fprintf(stderr, "Failed to decode the payload\n");
}
print_payload(&inbound_payload);
// Get the number of metrics in the payload and iterate over them handling them as needed
for (int i = 0; i < inbound_payload.metrics_count; i++) {
// Handle the incoming message as necessary - start with the 'Node Control' metrics
if (inbound_payload.metrics[i].alias == ALIAS_NODE_CONTROL_NEXT_SERVER) {
// 'Node Control/Next Server' is an NCMD used to tell the device/client application to
// disconnect from the current MQTT server and connect to the next MQTT server in the
// list of available servers. This is used for clients that have a pool of MQTT servers
// to connect to.
fprintf(stderr, "'Node Control/Next Server' is not implemented in this example\n");
} else if (inbound_payload.metrics[i].alias == ALIAS_NODE_CONTROL_REBIRTH) {
// 'Node Control/Rebirth' is an NCMD used to tell the device/client application to resend
// its full NBIRTH and DBIRTH again. MQTT Engine will send this NCMD to a device/client
// application if it receives an NDATA or DDATA with a metric that was not published in the
// original NBIRTH or DBIRTH. This is why the application must send all known metrics in
// its original NBIRTH and DBIRTH messages.
publish_births(mosq);
} else if (inbound_payload.metrics[i].alias == ALIAS_NODE_CONTROL_REBOOT) {
// 'Node Control/Reboot' is an NCMD used to tell a device/client application to reboot
// This can be used for devices that need a full application reset via a soft reboot.
// In this case, we fake a full reboot with a republishing of the NBIRTH and DBIRTH
// messages.
publish_births(mosq);
} else if (inbound_payload.metrics[i].alias == ALIAS_DEVICE_METRIC_2) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an Int16 because of how we declated it in the DBIRTH
uint32_t new_value = inbound_payload.metrics[i].value.int_value;
fprintf(stdout, "CMD message for output/Device Metric2 - New Value: %d\n", new_value);
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric2' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_2, METRIC_DATA_TYPE_INT16, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else if (inbound_payload.metrics[i].alias == ALIAS_DEVICE_METRIC_3) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an Boolean because of how we declared it in the DBIRTH
bool new_value = inbound_payload.metrics[i].value.boolean_value;
fprintf(stdout, "CMD message for output/Device Metric3 - New Value: %s\n", new_value ? "true" : "false");
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric3' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_3, METRIC_DATA_TYPE_BOOLEAN, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else if (inbound_payload.metrics[i].alias == ALIAS_DEVICE_METRIC_FLOAT) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an float because of how we declared it in the DBIRTH
float new_value = inbound_payload.metrics[i].value.float_value;
fprintf(stdout, "CMD message for Device Metric FLOAT - New Value: %f\n", new_value);
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric FLOAT' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_FLOAT, METRIC_DATA_TYPE_FLOAT, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else if (inbound_payload.metrics[i].alias == ALIAS_DEVICE_METRIC_DOUBLE) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an double because of how we declared it in the DBIRTH
double new_value = inbound_payload.metrics[i].value.double_value;
fprintf(stdout, "CMD message for Device Metric DOUBLE - New Value: %f\n", new_value);
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric DOUBLE' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_DOUBLE, METRIC_DATA_TYPE_DOUBLE, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else {
fprintf(stderr, "Unknown CMD: %s\n", inbound_payload.metrics[i].name);
}
}
free_payload(&inbound_payload);
}
/*
* Callback for successful or unsuccessful MQTT connect. Upon successful connect, subscribe to our Sparkplug NCMD and DCMD messages.
* A production application should handle MQTT connect failures and reattempt as necessary.
*/
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) {
if (!result) {
// Subscribe to commands
fprintf(stdout, "Subscribing on CMD topics\n");
mosquitto_subscribe(mosq, NULL, "spBv1.0/Sparkplug B Devices/NCMD/C Edge Node 1/#", 0);
mosquitto_subscribe(mosq, NULL, "spBv1.0/Sparkplug B Devices/DCMD/C Edge Node 1/#", 0);
} else {
fprintf(stderr, "MQTT Connect failed\n");
}
}
/*
* Callback for successful MQTT subscriptions.
*/
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) {
int i;
fprintf(stdout, "Subscribed (mid: %d): %d", mid, granted_qos[0]);
for (i = 1; i < qos_count; i++) {
fprintf(stdout, ", %d", granted_qos[i]);
}
fprintf(stdout, "\n");
}
/*
* MQTT logger callback
*/
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) {
// Print all log messages regardless of level.
fprintf(stdout, "%s\n", str);
}
/*
* Helper function to publish MQTT messages to the MQTT server
*/
void publisher(struct mosquitto *mosq, char *topic, void *buf, unsigned len) {
// publish the data
mosquitto_publish(mosq, NULL, topic, len, buf, 0, false);
}
/*
* Helper to publish the Sparkplug NBIRTH and DBIRTH messages after initial MQTT connect.
* This is also used for Rebirth requests from the backend.
*/
void publish_births(struct mosquitto *mosq) {
// Initialize the sequence number for Sparkplug MQTT messages
// This must be zero on every NBIRTH publish
reset_sparkplug_sequence();
// Publish the NBIRTH
publish_node_birth(mosq);
// Publish the DBIRTH
publish_device_birth(mosq);
}
/*
* Helper function to publish a NBIRTH message. The NBIRTH should include all 'node control' metrics that denote device capability.
* In addition, it should include every node metric that may ever be published from this edge node. If any NDATA messages arrive at
* MQTT Engine that were not included in the NBIRTH, MQTT Engine will request a Rebirth from the device.
*/
void publish_node_birth(struct mosquitto *mosq) {
// Create the NBIRTH payload
org_eclipse_tahu_protobuf_Payload nbirth_payload;
get_next_payload(&nbirth_payload);
nbirth_payload.uuid = strdup("MyUUID");
// Add node control metrics
fprintf(stdout, "Adding metric: 'Node Control/Next Server'\n");
bool next_server_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Next Server", true, ALIAS_NODE_CONTROL_NEXT_SERVER, METRIC_DATA_TYPE_BOOLEAN, false, false, &next_server_value, sizeof(next_server_value));
fprintf(stdout, "Adding metric: 'Node Control/Rebirth'\n");
bool rebirth_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Rebirth", true, ALIAS_NODE_CONTROL_REBIRTH, METRIC_DATA_TYPE_BOOLEAN, false, false, &rebirth_value, sizeof(rebirth_value));
fprintf(stdout, "Adding metric: 'Node Control/Reboot'\n");
bool reboot_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Reboot", true, ALIAS_NODE_CONTROL_REBOOT, METRIC_DATA_TYPE_BOOLEAN, false, false, &reboot_value, sizeof(reboot_value));
// Add some regular node metrics
fprintf(stdout, "Adding metric: 'Node Metric0'\n");
const char *nbirth_metric_zero_value = "hello node";
add_simple_metric(&nbirth_payload, "Node Metric0", true, ALIAS_NODE_METRIC_0, METRIC_DATA_TYPE_STRING, false, false, nbirth_metric_zero_value, sizeof(nbirth_metric_zero_value));
fprintf(stdout, "Adding metric: 'Node Metric1'\n");
bool nbirth_metric_one_value = true;
add_simple_metric(&nbirth_payload, "Node Metric1", true, ALIAS_NODE_METRIC_1, METRIC_DATA_TYPE_BOOLEAN, false, false, &nbirth_metric_one_value, sizeof(nbirth_metric_one_value));
fprintf(stdout, "Adding metric: 'Node Metric UINT32'\n");
uint32_t nbirth_metric_uint32_value = 100;
add_simple_metric(&nbirth_payload, "Node Metric UINT32", true, ALIAS_NODE_METRIC_UINT32, METRIC_DATA_TYPE_UINT32, false, false, &nbirth_metric_uint32_value, sizeof(nbirth_metric_uint32_value));
fprintf(stdout, "Adding metric: 'Node Metric FLOAT'\n");
float nbirth_metric_float_value = 100.12;
add_simple_metric(&nbirth_payload, "Node Metric FLOAT", true, ALIAS_NODE_METRIC_FLOAT, METRIC_DATA_TYPE_FLOAT, false, false, &nbirth_metric_float_value, sizeof(nbirth_metric_float_value));
double nbirth_metric_double_value = 1000.123456789;
add_simple_metric(&nbirth_payload, "Node Metric DOUBLE", true, ALIAS_NODE_METRIC_DOUBLE, METRIC_DATA_TYPE_DOUBLE, false, false, &nbirth_metric_double_value, sizeof(nbirth_metric_double_value));
// All INT Types
fprintf(stdout, "Adding metric: 'Node Metric I8'\n");
int8_t nbirth_metric_i8_value = 100;
add_simple_metric(&nbirth_payload, "Node Metric I8", true, ALIAS_NODE_METRIC_I8, METRIC_DATA_TYPE_INT8, false, false, &nbirth_metric_i8_value, sizeof(nbirth_metric_i8_value));
fprintf(stdout, "Adding metric: 'Node Metric I16'\n");
int16_t nbirth_metric_i16_value = 100;
add_simple_metric(&nbirth_payload, "Node Metric I16", true, ALIAS_NODE_METRIC_I16, METRIC_DATA_TYPE_INT16, false, false, &nbirth_metric_i16_value, sizeof(nbirth_metric_i16_value));
fprintf(stdout, "Adding metric: 'Node Metric I32'\n");
int32_t nbirth_metric_i32_value = 100;
add_simple_metric(&nbirth_payload, "Node Metric I32", true, ALIAS_NODE_METRIC_I32, METRIC_DATA_TYPE_INT32, false, false, &nbirth_metric_i32_value, sizeof(nbirth_metric_i32_value));
fprintf(stdout, "Adding metric: 'Node Metric I64'\n");
int64_t nbirth_metric_i64_value = 100;
add_simple_metric(&nbirth_payload, "Node Metric I64", true, ALIAS_NODE_METRIC_I64, METRIC_DATA_TYPE_INT64, false, false, &nbirth_metric_i64_value, sizeof(nbirth_metric_i64_value));
// All UINT Types
fprintf(stdout, "Adding metric: 'Node Metric UI8'\n");
uint8_t nbirth_metric_ui8_value = 200;
add_simple_metric(&nbirth_payload, "Node Metric UI8", true, ALIAS_NODE_METRIC_UI8, METRIC_DATA_TYPE_UINT8, false, false, &nbirth_metric_ui8_value, sizeof(nbirth_metric_ui8_value));
fprintf(stdout, "Adding metric: 'Node Metric UI16'\n");
uint16_t nbirth_metric_ui16_value = 200;
add_simple_metric(&nbirth_payload, "Node Metric UI16", true, ALIAS_NODE_METRIC_UI16, METRIC_DATA_TYPE_UINT16, false, false, &nbirth_metric_ui16_value, sizeof(nbirth_metric_ui16_value));
fprintf(stdout, "Adding metric: 'Node Metric UI32'\n");
uint32_t nbirth_metric_ui32_value = 200;
add_simple_metric(&nbirth_payload, "Node Metric UI32", true, ALIAS_NODE_METRIC_UI32, METRIC_DATA_TYPE_UINT32, false, false, &nbirth_metric_ui32_value, sizeof(nbirth_metric_ui32_value));
fprintf(stdout, "Adding metric: 'Node Metric UI64'\n");
uint64_t nbirth_metric_ui64_value = 200;
add_simple_metric(&nbirth_payload, "Node Metric UI64", true, ALIAS_NODE_METRIC_UI64, METRIC_DATA_TYPE_UINT64, false, false, &nbirth_metric_ui64_value, sizeof(nbirth_metric_ui64_value));
// Create a DataSet
org_eclipse_tahu_protobuf_Payload_DataSet dataset = org_eclipse_tahu_protobuf_Payload_DataSet_init_default;
uint32_t datatypes[] = { DATA_SET_DATA_TYPE_INT8, DATA_SET_DATA_TYPE_INT16, DATA_SET_DATA_TYPE_INT32 };
const char *column_keys[] = { "Int8s", "Int16s", "Int32s" };
org_eclipse_tahu_protobuf_Payload_DataSet_Row *row_data = (org_eclipse_tahu_protobuf_Payload_DataSet_Row *)
calloc(2, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_Row));
row_data[0].elements_count = 3;
row_data[0].elements = (org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *)
calloc(3, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue));
row_data[0].elements[0].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[0].elements[0].value.int_value = 0;
row_data[0].elements[1].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[0].elements[1].value.int_value = 1;
row_data[0].elements[2].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[0].elements[2].value.int_value = 2;
row_data[1].elements_count = 3;
row_data[1].elements = (org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *)
calloc(3, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue));
row_data[1].elements[0].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[1].elements[0].value.int_value = 3;
row_data[1].elements[1].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[1].elements[1].value.int_value = 4;
row_data[1].elements[2].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[1].elements[2].value.int_value = 5;
init_dataset(&dataset, 2, 3, datatypes, column_keys, row_data);
free(row_data);
// Create the a Metric with the DataSet value and add it to the payload
fprintf(stdout, "Adding metric: 'DataSet'\n");
org_eclipse_tahu_protobuf_Payload_Metric dataset_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&dataset_metric, "DataSet", true, ALIAS_NODE_METRIC_DATASET, METRIC_DATA_TYPE_DATASET, false, false, &dataset, sizeof(dataset));
add_metric_to_payload(&nbirth_payload, &dataset_metric);
// Add a metric with a custom property
fprintf(stdout, "Adding metric: 'Node Metric2'\n");
org_eclipse_tahu_protobuf_Payload_Metric prop_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t nbirth_metric_two_value = 13;
init_metric(&prop_metric, "Node Metric2", true, ALIAS_NODE_METRIC_2, METRIC_DATA_TYPE_INT16, false, false, &nbirth_metric_two_value, sizeof(nbirth_metric_two_value));
org_eclipse_tahu_protobuf_Payload_PropertySet properties = org_eclipse_tahu_protobuf_Payload_PropertySet_init_default;
add_property_to_set(&properties, "engUnit", PROPERTY_DATA_TYPE_STRING, "MyCustomUnits", sizeof("MyCustomUnits"));
add_propertyset_to_metric(&prop_metric, &properties);
add_metric_to_payload(&nbirth_payload, &prop_metric);
// Create a metric called RPMs which is a member of the UDT definition - note aliases do not apply to UDT members
org_eclipse_tahu_protobuf_Payload_Metric rpms_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t rpms_value = 0;
init_metric(&rpms_metric, "RPMs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &rpms_value, sizeof(rpms_value));
// Create a metric called AMPs which is a member of the UDT definition - note aliases do not apply to UDT members
org_eclipse_tahu_protobuf_Payload_Metric amps_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t amps_value = 0;
init_metric(&s_metric, "AMPs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &s_value, sizeof(amps_value));
// Create a Template/UDT Parameter - this is purely for example of including parameters and is not actually used by UDT instances
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter.name = strdup("Index");
parameter.has_type = true;
parameter.type = PARAMETER_DATA_TYPE_STRING;
parameter.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag;
parameter.value.string_value = strdup("0");
// Create the UDT definition value which includes the UDT members and parameters
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.metrics_count = 2;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(2, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = rpms_metric;
udt_template.metrics[1] = amps_metric;
udt_template.parameters_count = 1;
udt_template.parameters = (org_eclipse_tahu_protobuf_Payload_Template_Parameter *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Template_Parameter));
udt_template.parameters[0] = parameter;
udt_template.template_ref = NULL;
udt_template.has_is_definition = true;
udt_template.is_definition = true;
// Create the root UDT definition and add the UDT definition value which includes the UDT members and parameters
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "_types_/Custom_Motor", false, 0, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
// Add the UDT to the payload
add_metric_to_payload(&nbirth_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload for debug
print_payload(&nbirth_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &nbirth_payload);
// Publish the NBIRTH on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/NBIRTH/C Edge Node 1", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&nbirth_payload);
}
void publish_device_birth(struct mosquitto *mosq) {
// Create the DBIRTH payload
org_eclipse_tahu_protobuf_Payload dbirth_payload;
get_next_payload(&dbirth_payload);
// Add some device metrics
fprintf(stdout, "Adding metric: 'input/Device Metric0'\n");
char dbirth_metric_zero_value[] = "hello device";
add_simple_metric(&dbirth_payload, "input/Device Metric0", true, ALIAS_DEVICE_METRIC_0, METRIC_DATA_TYPE_STRING, false, false, &dbirth_metric_zero_value, sizeof(dbirth_metric_zero_value));
fprintf(stdout, "Adding metric: 'input/Device Metric1'\n");
bool dbirth_metric_one_value = true;
add_simple_metric(&dbirth_payload, "input/Device Metric1", true, ALIAS_DEVICE_METRIC_1, METRIC_DATA_TYPE_BOOLEAN, false, false, &dbirth_metric_one_value, sizeof(dbirth_metric_one_value));
fprintf(stdout, "Adding metric: 'output/Device Metric2'\n");
uint32_t dbirth_metric_two_value = 16;
add_simple_metric(&dbirth_payload, "output/Device Metric2", true, ALIAS_DEVICE_METRIC_2, METRIC_DATA_TYPE_INT16, false, false, &dbirth_metric_two_value, sizeof(dbirth_metric_two_value));
fprintf(stdout, "Adding metric: 'output/Device Metric3'\n");
bool dbirth_metric_three_value = true;
add_simple_metric(&dbirth_payload, "output/Device Metric3", true, ALIAS_DEVICE_METRIC_3, METRIC_DATA_TYPE_BOOLEAN, false, false, &dbirth_metric_three_value, sizeof(dbirth_metric_three_value));
fprintf(stdout, "Adding metric: 'Device Metric INT8'\n");
int dbirth_metric_int8_value = 100;
add_simple_metric(&dbirth_payload, "Device Metric INT8", true, ALIAS_DEVICE_METRIC_INT8, METRIC_DATA_TYPE_INT8, false, false, &dbirth_metric_int8_value, sizeof(dbirth_metric_int8_value));
fprintf(stdout, "Adding metric: 'Device Metric UINT32'\n");
int dbirth_metric_uint32_value = 100;
add_simple_metric(&dbirth_payload, "Device Metric UINT32", true, ALIAS_DEVICE_METRIC_UINT32, METRIC_DATA_TYPE_UINT32, false, false, &dbirth_metric_uint32_value, sizeof(dbirth_metric_uint32_value));
fprintf(stdout, "Adding metric: 'Device Metric FLOAT'\n");
float dbirth_metric_float_value = 100.12;
add_simple_metric(&dbirth_payload, "Device Metric FLOAT", true, ALIAS_DEVICE_METRIC_FLOAT, METRIC_DATA_TYPE_FLOAT, false, false, &dbirth_metric_float_value, sizeof(dbirth_metric_float_value));
double dbirth_metric_double_value = 1000.123;
add_simple_metric(&dbirth_payload, "Device Metric DOUBLE", true, ALIAS_DEVICE_METRIC_DOUBLE, METRIC_DATA_TYPE_DOUBLE, false, false, &dbirth_metric_double_value, sizeof(dbirth_metric_double_value));
// Create a metric called RPMs for the UDT instance
org_eclipse_tahu_protobuf_Payload_Metric rpms_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t rpms_value = 123;
init_metric(&rpms_metric, "RPMs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &rpms_value, sizeof(rpms_value));
// Create a metric called AMPs for the UDT instance and create a custom property (milliamps) for it
org_eclipse_tahu_protobuf_Payload_Metric amps_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t amps_value = 456;
init_metric(&s_metric, "AMPs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &s_value, sizeof(amps_value));
org_eclipse_tahu_protobuf_Payload_PropertySet properties = org_eclipse_tahu_protobuf_Payload_PropertySet_init_default;
add_property_to_set(&properties, "engUnit", PROPERTY_DATA_TYPE_STRING, "milliamps", sizeof("milliamps"));
add_propertyset_to_metric(&s_metric, &properties);
// Create a Template/UDT instance Parameter - this is purely for example of including parameters and is not actually used by UDT instances
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter.name = strdup("Index");
parameter.has_type = true;
parameter.type = PARAMETER_DATA_TYPE_STRING;
parameter.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag;
parameter.value.string_value = strdup("1");
// Create the UDT instance value which includes the UDT members and parameters
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.version = NULL;
udt_template.metrics_count = 2;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(2, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = rpms_metric;
udt_template.metrics[1] = amps_metric;
udt_template.parameters_count = 1;
udt_template.parameters = (org_eclipse_tahu_protobuf_Payload_Template_Parameter *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Template_Parameter));
udt_template.parameters[0] = parameter;
udt_template.template_ref = strdup("Custom_Motor");
udt_template.has_is_definition = true;
udt_template.is_definition = false;
// Create the root UDT instance and add the UDT instance value
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "My_Custom_Motor", true, ALIAS_DEVICE_METRIC_UDT_INST, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
// Add the UDT Instance to the payload
add_metric_to_payload(&dbirth_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload
print_payload(&dbirth_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &dbirth_payload);
// Publish the DBIRTH on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DBIRTH/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&dbirth_payload);
}
void publish_ddata_message(struct mosquitto *mosq) {
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Add some device metrics to denote changed values on inputs
fprintf(stdout, "Adding metric: 'input/Device Metric0'\n");
char ddata_metric_zero_value[15];
snprintf(ddata_metric_zero_value, sizeof(ddata_metric_zero_value), "%04X-%04X-%04X", (rand() % 0x10000), (rand() % 0x10000), (rand() % 0x10000));
// Note the Metric name 'input/Device Metric0' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_0, METRIC_DATA_TYPE_STRING, false, false, ddata_metric_zero_value, sizeof(ddata_metric_zero_value));
fprintf(stdout, "Adding metric: 'input/Device Metric1'\n");
bool ddata_metric_one_value = rand() % 2;
// Note the Metric name 'input/Device Metric1' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_1, METRIC_DATA_TYPE_BOOLEAN, false, false, &ddata_metric_one_value, sizeof(ddata_metric_one_value));
fprintf(stdout, "Adding metric: 'Device Metric INT8'\n");
int ddata_metric_int8_value = rand() % 100;
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_INT8, METRIC_DATA_TYPE_INT8, false, false, &ddata_metric_int8_value, sizeof(ddata_metric_int8_value));
fprintf(stdout, "Adding metric: 'Device Metric UINT32'\n");
int ddata_metric_uint32_value = rand() % 1000;
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_UINT32, METRIC_DATA_TYPE_UINT32, false, false, &ddata_metric_uint32_value, sizeof(ddata_metric_uint32_value));
fprintf(stdout, "Adding metric: 'Device Metric FLOAT'\n");
float ddata_metric_float_value = ((float)rand() / (float)(RAND_MAX)) * 5.0;
add_simple_metric(&ddata_payload, NULL, true, ALIAS_DEVICE_METRIC_FLOAT, METRIC_DATA_TYPE_FLOAT, false, false, &ddata_metric_float_value, sizeof(ddata_metric_float_value));
#ifdef SPARKPLUG_DEBUG
// Print the payload
print_payload(&ddata_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
}
================================================
FILE: c/core/test.sh
================================================
#/********************************************************************************
# * Copyright (c) 2014-2019 Cirrus Link Solutions and others
# *
# * This program and the accompanying materials are made available under the
# * terms of the Eclipse Public License 2.0 which is available at
# * http://www.eclipse.org/legal/epl-2.0.
# *
# * SPDX-License-Identifier: EPL-2.0
# *
# * Contributors:
# * Cirrus Link Solutions - initial implementation
# ********************************************************************************/
#!/bin/sh
#echo "Running static example..."
#./test/test_static
echo ""
echo "Running dynamic example..."
#echo "Starting LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}"
PWD=`pwd`
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${PWD}/lib
#echo "New LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}"
./test/test_dynamic
================================================
FILE: c/examples/template_as_custom_props/Makefile
================================================
#/********************************************************************************
# * Copyright (c) 2014, 2018 Cirrus Link Solutions and others
# *
# * This program and the accompanying materials are made available under the
# * terms of the Eclipse Public License 2.0 which is available at
# * http://www.eclipse.org/legal/epl-2.0.
# *
# * SPDX-License-Identifier: EPL-2.0
# *
# * Contributors:
# * Cirrus Link Solutions - initial implementation
# ********************************************************************************/
TARGET = example
LIBS = ../../../../client_libraries/c/lib/libtahu.a -Llib -L/usr/local/lib -lmosquitto
CC = gcc
CFLAGS = -g -Wall -I../../../../client_libraries/c/include/
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $@
clean:
-rm -f *.o
-rm -f $(TARGET)
================================================
FILE: c/examples/template_as_custom_props/example.c
================================================
/********************************************************************************
* Copyright (c) 2014, 2018 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Mosquitto Callbacks */
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message);
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result);
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos);
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str);
/* Local Functions */
void publisher(struct mosquitto *mosq, char *topic, void *buf, unsigned len);
void publish_births(struct mosquitto *mosq);
void publish_node_birth(struct mosquitto *mosq);
void publish_device_birth(struct mosquitto *mosq);
void publish_ddata_message(struct mosquitto *mosq);
int main(int argc, char *argv[]) {
// MQTT Parameters
char *host = "localhost";
int port = 1883;
int keepalive = 60;
bool clean_session = true;
struct mosquitto *mosq = NULL;
// MQTT Setup
srand(time(NULL));
mosquitto_lib_init();
mosq = mosquitto_new(NULL, clean_session, NULL);
if (!mosq) {
fprintf(stderr, "Error: Out of memory.\n");
return 1;
}
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
mosquitto_username_pw_set(mosq, "admin", "changeme");
mosquitto_will_set(mosq, "spBv1.0/Sparkplug B Devices/NDEATH/C Edge Node 1", 0, NULL, 0, false);
// Optional SSL parameters for MQTT
//mosquitto_tls_insecure_set(mosq, true);
//mosquitto_tls_opts_set(mosq, 0, "tlsv1.2", NULL); // 0 is DO NOT SSL_VERIFY_PEER
// MQTT Connect
if (mosquitto_connect(mosq, host, port, keepalive)) {
fprintf(stderr, "Unable to connect.\n");
return 1;
}
// Publish the NBIRTH and DBIRTH Sparkplug messages (Birth Certificates)
publish_births(mosq);
// Loop and publish more DDATA messages every 5 seconds. Note this should only be done in real/production
// scenarios with change events on inputs. Because Sparkplug ensures state there is no reason to send DDATA
// messages unless the state of a I/O point has changed.
int i;
for (i = 0; i < 100; i++) {
publish_ddata_message(mosq);
int j;
for (j = 0; j < 50; j++) {
usleep(100000);
mosquitto_loop(mosq, 0, 1);
}
}
// Close and cleanup
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
/*
* Helper function to publish MQTT messages to the MQTT server
*/
void publisher(struct mosquitto *mosq, char *topic, void *buf, unsigned len) {
// publish the data
mosquitto_publish(mosq, NULL, topic, len, buf, 0, false);
}
/*
* Callback for incoming MQTT messages. Since this is a Sparkplug implementation these will be NCMD and DCMD messages
*/
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) {
if (message->payloadlen) {
fprintf(stdout, "%s :: %d\n", message->topic, message->payloadlen);
} else {
fprintf(stdout, "%s (null)\n", message->topic);
}
fflush(stdout);
// Decode the payload
org_eclipse_tahu_protobuf_Payload inbound_payload = org_eclipse_tahu_protobuf_Payload_init_zero;
if (decode_payload(&inbound_payload, message->payload, message->payloadlen)) {
} else {
fprintf(stderr, "Failed to decode the payload\n");
return; // JPL 04/06/17...
}
// Get the number of metrics in the payload and iterate over them handling them as needed
int i;
for (i = 0; i < inbound_payload.metrics_count; i++) {
// Handle the incoming message as necessary - start with the 'Node Control' metrics
// JPL 04/06/17... Handle ALIAS metrics versus text-name based metrics
if (inbound_payload.metrics[i].name == NULL) { // alias 0 to 2
switch (inbound_payload.metrics[i].alias) {
case 0: // Next Server
fprintf(stderr, "Using Next Configured MQtt Server\n");
break;
case 1: // Resend Births
fprintf(stderr, "Resend Birth Certificates\n");
publish_births(mosq);
break;
case 2: // Next Server
fprintf(stderr, "REBOOT Operating system\n");
//system("reboot");
break;
}
} else if (strcmp(inbound_payload.metrics[i].name, "Node Control/Next Server") == 0) {
// 'Node Control/Next Server' is an NCMD used to tell the device/client application to
// disconnect from the current MQTT server and connect to the next MQTT server in the
// list of available servers. This is used for clients that have a pool of MQTT servers
// to connect to.
fprintf(stderr, "'Node Control/Next Server' is not implemented in this example\n");
} else if (strcmp(inbound_payload.metrics[i].name, "Node Control/Rebirth") == 0) {
// 'Node Control/Rebirth' is an NCMD used to tell the device/client application to resend
// its full NBIRTH and DBIRTH again. MQTT Engine will send this NCMD to a device/client
// application if it receives an NDATA or DDATA with a metric that was not published in the
// original NBIRTH or DBIRTH. This is why the application must send all known metrics in
// its original NBIRTH and DBIRTH messages.
publish_births(mosq);
} else if (strcmp(inbound_payload.metrics[i].name, "Node Control/Reboot") == 0) {
// 'Node Control/Reboot' is an NCMD used to tell a device/client application to reboot
// This can be used for devices that need a full application reset via a soft reboot.
// In this case, we fake a full reboot with a republishing of the NBIRTH and DBIRTH
// messages.
publish_births(mosq);
} else {
fprintf(stderr, "Unknown CMD: %s\n", inbound_payload.metrics[i].name);
}
}
free_payload(&inbound_payload); // JPL 04/06/17...
}
/*
* Callback for successful or unsuccessful MQTT connect. Upon successful connect, subscribe to our Sparkplug NCMD and DCMD messages.
* A production application should handle MQTT connect failures and reattempt as necessary.
*/
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) {
if (!result) {
// Subscribe to commands
mosquitto_subscribe(mosq, NULL, "spBv1.0/Sparkplug B Devices/NCMD/C Edge Node 1/#", 0);
mosquitto_subscribe(mosq, NULL, "spBv1.0/Sparkplug B Devices/DCMD/C Edge Node 1/#", 0);
} else {
fprintf(stderr, "MQTT Connect failed\n");
}
}
/*
* Callback for successful MQTT subscriptions.
*/
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) {
int i;
fprintf(stdout, "Subscribed (mid: %d): %d", mid, granted_qos[0]);
for (i = 1; i < qos_count; i++) {
fprintf(stdout, ", %d", granted_qos[i]);
}
fprintf(stdout, "\n");
}
/*
* MQTT logger callback
*/
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) {
// Print all log messages regardless of level.
fprintf(stdout, "%s\n", str);
}
/*
* Helper to publish the Sparkplug NBIRTH and DBIRTH messages after initial MQTT connect.
* This is also used for Rebirth requests from the backend.
*/
void publish_births(struct mosquitto *mosq) {
// Initialize the sequence number for Sparkplug MQTT messages
// This must be zero on every NBIRTH publish
// Publish the NBIRTH
publish_node_birth(mosq);
// Publish the DBIRTH
publish_device_birth(mosq);
}
/*
* Helper function to publish a NBIRTH message. The NBIRTH should include all 'node control' metrics that denote device capability.
* In addition, it should include every node metric that may ever be published from this edge node. If any NDATA messages arrive at
* MQTT Engine that were not included in the NBIRTH, MQTT Engine will request a Rebirth from the device.
*/
void publish_node_birth(struct mosquitto *mosq) {
// Create the NBIRTH payload
org_eclipse_tahu_protobuf_Payload nbirth_payload;
// Initialize the sequence number for Sparkplug MQTT messages
// This must be zero on every NBIRTH publish
reset_sparkplug_sequence();
get_next_payload(&nbirth_payload);
// Add node control metrics
fprintf(stdout, "Adding metric: 'Node Control/Next Server'\n");
bool next_server_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Next Server", true, 0, METRIC_DATA_TYPE_BOOLEAN, false, false, &next_server_value, sizeof(next_server_value));
fprintf(stdout, "Adding metric: 'Node Control/Rebirth'\n");
bool rebirth_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Rebirth", true, 1, METRIC_DATA_TYPE_BOOLEAN, false, false, &rebirth_value, sizeof(rebirth_value));
fprintf(stdout, "Adding metric: 'Node Control/Reboot'\n");
bool reboot_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Reboot", true, 2, METRIC_DATA_TYPE_BOOLEAN, false, false, &reboot_value, sizeof(reboot_value));
// Create a metric called 'My Real Metric' which will be a member of the Template definition - note aliases do not apply to Template members
org_eclipse_tahu_protobuf_Payload_Metric my_real_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t my_real_metric_value = 0; // Default value
init_metric(&my_real_metric, "My Real Metric", false, 0, METRIC_DATA_TYPE_INT32, false, false, &my_real_metric_value, sizeof(my_real_metric_value));
// Create some Template Parameters - In this example we're using them as custom properties of a regular metric via a Template
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter_one = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter_one.name = strdup("MyPropKey1");
parameter_one.has_type = true;
parameter_one.type = PARAMETER_DATA_TYPE_STRING;
parameter_one.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag;
parameter_one.value.string_value = strdup("MyDefaultPropValue1");
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter_two = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter_two.name = strdup("MyPropKey2");
parameter_two.has_type = true;
parameter_two.type = PARAMETER_DATA_TYPE_INT32;
parameter_two.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_int_value_tag;
parameter_two.value.int_value = 0; // Default value
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter_three = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter_three.name = strdup("MyPropKey3");
parameter_three.has_type = true;
parameter_three.type = PARAMETER_DATA_TYPE_FLOAT;
parameter_three.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_float_value_tag;
parameter_three.value.float_value = 0.0; // Default value
// Create the Template definition value which includes the single Template members and parameters which are custom properties of the 'real metric'
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.metrics_count = 1;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = my_real_metric;
udt_template.parameters_count = 3;
udt_template.parameters = (org_eclipse_tahu_protobuf_Payload_Template_Parameter *)calloc(3, sizeof(org_eclipse_tahu_protobuf_Payload_Template_Parameter));
udt_template.parameters[0] = parameter_one;
udt_template.parameters[1] = parameter_two;
udt_template.parameters[2] = parameter_three;
udt_template.template_ref = NULL;
udt_template.has_is_definition = true;
udt_template.is_definition = true;
// Create the root Template definition and add the Template definition value which includes the Template members and parameters
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "_types_/My Metric Definition", true, 3, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
// Add the Template to the payload
add_metric_to_payload(&nbirth_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload for debug
print_payload(&nbirth_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &nbirth_payload);
// Publish the NBIRTH on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/NBIRTH/C Edge Node 1", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&nbirth_payload);
}
void publish_device_birth(struct mosquitto *mosq) {
// Create the DBIRTH payload
org_eclipse_tahu_protobuf_Payload dbirth_payload;
get_next_payload(&dbirth_payload);
// Add a metric with a custom property. For use with Ignition, in order to see this as a Tag Property - it must be a known Ignition Tag Property.
fprintf(stdout, "Adding metric: 'Device Metric1'\n");
org_eclipse_tahu_protobuf_Payload_Metric prop_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t nbirth_metric_two_value = 13;
init_metric(&prop_metric, "Device Metric1", true, 4, METRIC_DATA_TYPE_INT16, false, false, &nbirth_metric_two_value, sizeof(nbirth_metric_two_value));
org_eclipse_tahu_protobuf_Payload_PropertySet properties = org_eclipse_tahu_protobuf_Payload_PropertySet_init_default;
add_property_to_set(&properties, "engUnit", PROPERTY_DATA_TYPE_STRING, "MyCustomUnits", sizeof("MyCustomUnits"));
add_propertyset_to_metric(&prop_metric, &properties);
add_metric_to_payload(&dbirth_payload, &prop_metric);
// Create a metric called 'My Real Metric' for the Template instance
org_eclipse_tahu_protobuf_Payload_Metric my_real_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t my_real_metric_value = 123; // Not a default - this is the actual value of the instance
init_metric(&my_real_metric, "My Real Metric", false, 0, METRIC_DATA_TYPE_INT32, false, false, &my_real_metric_value, sizeof(my_real_metric_value));
// Create some Template/UDT instance Parameters - in this example they represent custom tag properties
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter_one = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter_one.name = strdup("MyPropKey1");
parameter_one.has_type = true;
parameter_one.type = PARAMETER_DATA_TYPE_STRING;
parameter_one.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag;
parameter_one.value.string_value = strdup("MyInstancePropValue1");
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter_two = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter_two.name = strdup("MyPropKey2");
parameter_two.has_type = true;
parameter_two.type = PARAMETER_DATA_TYPE_INT32;
parameter_two.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_int_value_tag;
parameter_two.value.int_value = 1089;
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter_three = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter_three.name = strdup("MyPropKey3");
parameter_three.has_type = true;
parameter_three.type = PARAMETER_DATA_TYPE_FLOAT;
parameter_three.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_float_value_tag;
parameter_three.value.float_value = 12.34;
// Create the Template instance value which includes the Template members and parameters
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.version = NULL;
udt_template.metrics_count = 1;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = my_real_metric;
udt_template.parameters_count = 3;
udt_template.parameters = (org_eclipse_tahu_protobuf_Payload_Template_Parameter *)calloc(3, sizeof(org_eclipse_tahu_protobuf_Payload_Template_Parameter));
udt_template.parameters[0] = parameter_one;
udt_template.parameters[1] = parameter_two;
udt_template.parameters[2] = parameter_three;
udt_template.template_ref = strdup("My Metric Definition");
udt_template.has_is_definition = true;
udt_template.is_definition = false;
// Create the root Template instance and add the Template instance value
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "My Metric Instance 1", true, 5, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
// Add the Template Instance to the payload
add_metric_to_payload(&dbirth_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload
print_payload(&dbirth_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &dbirth_payload);
// Publish the DBIRTH on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DBIRTH/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&dbirth_payload);
}
void publish_ddata_message(struct mosquitto *mosq) {
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Update the metric called 'My Real Metric' for the Template instance to update the 'real' metric value
org_eclipse_tahu_protobuf_Payload_Metric my_real_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t my_real_metric_value = rand(); // Not a default - this is the actual value of the metric of instance
init_metric(&my_real_metric, "My Real Metric", false, 0, METRIC_DATA_TYPE_INT32, false, false, &my_real_metric_value, sizeof(my_real_metric_value));
// Create the Template instance value which includes the Template members and parameters
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.version = NULL;
udt_template.metrics_count = 1;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = my_real_metric;
udt_template.has_is_definition = true;
udt_template.is_definition = false;
// Create the root Template instance and add the Template instance value
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "My Metric Instance 1", true, 5, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
add_metric_to_payload(&ddata_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload
print_payload(&ddata_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
}
================================================
FILE: c/examples/udt_example/Makefile
================================================
#/********************************************************************************
# * Copyright (c) 2014, 2018 Cirrus Link Solutions and others
# *
# * This program and the accompanying materials are made available under the
# * terms of the Eclipse Public License 2.0 which is available at
# * http://www.eclipse.org/legal/epl-2.0.
# *
# * SPDX-License-Identifier: EPL-2.0
# *
# * Contributors:
# * Cirrus Link Solutions - initial implementation
# ********************************************************************************/
TARGET = example
LIBS = ../../../../client_libraries/c/lib/libtahu.a -Llib -L/usr/local/lib -lmosquitto
CC = gcc
CFLAGS = -g -Wall -I../../../../client_libraries/c/include/
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $@
clean:
-rm -f *.o
-rm -f $(TARGET)
================================================
FILE: c/examples/udt_example/example.c
================================================
/********************************************************************************
* Copyright (c) 2014, 2018 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Mosquitto Callbacks */
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message);
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result);
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos);
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str);
/* Local Functions */
void publisher(struct mosquitto *mosq, char *topic, void *buf, unsigned len);
void publish_births(struct mosquitto *mosq);
void publish_node_birth(struct mosquitto *mosq);
void publish_device_birth(struct mosquitto *mosq);
void publish_ddata_message(struct mosquitto *mosq);
enum alias_map {
Next_Server = 0,
Rebirth = 1,
Reboot = 2,
Dataset = 3,
Node_Metric0 = 4,
Node_Metric1 = 5,
Node_Metric2 = 6,
Device_Metric0 = 7,
Device_Metric1 = 8,
Device_Metric2 = 9,
Device_Metric3 = 10,
My_Custom_Motor = 11
};
int main(int argc, char *argv[]) {
// MQTT Parameters
char *host = "localhost";
int port = 1883;
int keepalive = 60;
bool clean_session = true;
struct mosquitto *mosq = NULL;
// MQTT Setup
srand(time(NULL));
mosquitto_lib_init();
mosq = mosquitto_new(NULL, clean_session, NULL);
if (!mosq) {
fprintf(stderr, "Error: Out of memory.\n");
return 1;
}
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
mosquitto_username_pw_set(mosq, "admin", "changeme");
mosquitto_will_set(mosq, "spBv1.0/Sparkplug B Devices/NDEATH/C Edge Node 1", 0, NULL, 0, false);
// Optional SSL parameters for MQTT
//mosquitto_tls_insecure_set(mosq, true);
//mosquitto_tls_opts_set(mosq, 0, "tlsv1.2", NULL); // 0 is DO NOT SSL_VERIFY_PEER
// MQTT Connect
if (mosquitto_connect(mosq, host, port, keepalive)) {
fprintf(stderr, "Unable to connect.\n");
return 1;
}
// Publish the NBIRTH and DBIRTH Sparkplug messages (Birth Certificates)
publish_births(mosq);
// Loop and publish more DDATA messages every 5 seconds. Note this should only be done in real/production
// scenarios with change events on inputs. Because Sparkplug ensures state there is no reason to send DDATA
// messages unless the state of a I/O point has changed.
int i;
for (i = 0; i < 100; i++) {
publish_ddata_message(mosq);
int j;
for (j = 0; j < 50; j++) {
usleep(10000);
mosquitto_loop(mosq, 0, 1);
}
}
// Close and cleanup
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
/*
* Helper function to publish MQTT messages to the MQTT server
*/
void publisher(struct mosquitto *mosq, char *topic, void *buf, unsigned len) {
// publish the data
mosquitto_publish(mosq, NULL, topic, len, buf, 0, false);
}
/*
* Callback for incoming MQTT messages. Since this is a Sparkplug implementation these will be NCMD and DCMD messages
*/
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) {
if (message->payloadlen) {
fprintf(stdout, "%s :: %d\n", message->topic, message->payloadlen);
} else {
fprintf(stdout, "%s (null)\n", message->topic);
}
fflush(stdout);
// Decode the payload
org_eclipse_tahu_protobuf_Payload inbound_payload = org_eclipse_tahu_protobuf_Payload_init_zero;
if (decode_payload(&inbound_payload, message->payload, message->payloadlen)) {
} else {
fprintf(stderr, "Failed to decode the payload\n");
}
// Get the number of metrics in the payload and iterate over them handling them as needed
int i;
for (i = 0; i < inbound_payload.metrics_count; i++) {
if (inbound_payload.metrics[i].name != NULL) {
// Handle the incoming message as necessary - start with the 'Node Control' metrics
if (strcmp(inbound_payload.metrics[i].name, "Node Control/Next Server") == 0) {
// 'Node Control/Next Server' is an NCMD used to tell the device/client application to
// disconnect from the current MQTT server and connect to the next MQTT server in the
// list of available servers. This is used for clients that have a pool of MQTT servers
// to connect to.
fprintf(stderr, "'Node Control/Next Server' is not implemented in this example\n");
} else if (strcmp(inbound_payload.metrics[i].name, "Node Control/Rebirth") == 0) {
// 'Node Control/Rebirth' is an NCMD used to tell the device/client application to resend
// its full NBIRTH and DBIRTH again. MQTT Engine will send this NCMD to a device/client
// application if it receives an NDATA or DDATA with a metric that was not published in the
// original NBIRTH or DBIRTH. This is why the application must send all known metrics in
// its original NBIRTH and DBIRTH messages.
publish_births(mosq);
} else if (strcmp(inbound_payload.metrics[i].name, "Node Control/Reboot") == 0) {
// 'Node Control/Reboot' is an NCMD used to tell a device/client application to reboot
// This can be used for devices that need a full application reset via a soft reboot.
// In this case, we fake a full reboot with a republishing of the NBIRTH and DBIRTH
// messages.
publish_births(mosq);
} else if (strcmp(inbound_payload.metrics[i].name, "output/Device Metric2") == 0) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an Int16 because of how we declated it in the DBIRTH
uint32_t new_value = inbound_payload.metrics[i].value.int_value;
fprintf(stdout, "CMD message for output/Device Metric2 - New Value: %d\n", new_value);
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric2' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, Device_Metric2, METRIC_DATA_TYPE_INT16, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else if (strcmp(inbound_payload.metrics[i].name, "output/Device Metric3") == 0) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an Boolean because of how we declated it in the DBIRTH
bool new_value = inbound_payload.metrics[i].value.boolean_value;
fprintf(stdout, "CMD message for output/Device Metric3 - New Value: %s\n", new_value ? "true" : "false");
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric3' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, Device_Metric3, METRIC_DATA_TYPE_BOOLEAN, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else {
fprintf(stderr, "Unknown CMD: %s\n", inbound_payload.metrics[i].name);
}
} else if (inbound_payload.metrics[i].has_alias) {
// Handle the incoming message as necessary - start with the 'Node Control' metrics
if (inbound_payload.metrics[i].alias == Next_Server) {
// 'Node Control/Next Server' is an NCMD used to tell the device/client application to
// disconnect from the current MQTT server and connect to the next MQTT server in the
// list of available servers. This is used for clients that have a pool of MQTT servers
// to connect to.
fprintf(stderr, "'Node Control/Next Server' is not implemented in this example\n");
} else if (inbound_payload.metrics[i].alias == Rebirth) {
// 'Node Control/Rebirth' is an NCMD used to tell the device/client application to resend
// its full NBIRTH and DBIRTH again. MQTT Engine will send this NCMD to a device/client
// application if it receives an NDATA or DDATA with a metric that was not published in the
// original NBIRTH or DBIRTH. This is why the application must send all known metrics in
// its original NBIRTH and DBIRTH messages.
publish_births(mosq);
} else if (inbound_payload.metrics[i].alias == Reboot) {
// 'Node Control/Reboot' is an NCMD used to tell a device/client application to reboot
// This can be used for devices that need a full application reset via a soft reboot.
// In this case, we fake a full reboot with a republishing of the NBIRTH and DBIRTH
// messages.
publish_births(mosq);
} else if (inbound_payload.metrics[i].alias == Device_Metric2) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an Int16 because of how we declated it in the DBIRTH
uint32_t new_value = inbound_payload.metrics[i].value.int_value;
fprintf(stdout, "CMD message for output/Device Metric2 - New Value: %d\n", new_value);
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric2' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, Device_Metric2, METRIC_DATA_TYPE_INT16, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else if (inbound_payload.metrics[i].alias == Device_Metric3) {
// This is a metric we declared in our DBIRTH message and we're emulating an output.
// So, on incoming 'writes' to the output we must publish a DDATA with the new output
// value. If this were a real output we'd write to the output and then read it back
// before publishing a DDATA message.
// We know this is an Boolean because of how we declated it in the DBIRTH
bool new_value = inbound_payload.metrics[i].value.boolean_value;
fprintf(stdout, "CMD message for output/Device Metric3 - New Value: %s\n", new_value ? "true" : "false");
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Note the Metric name 'output/Device Metric3' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, Device_Metric3, METRIC_DATA_TYPE_BOOLEAN, false, false, &new_value, sizeof(new_value));
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 128;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
} else {
fprintf(stderr, "Unknown CMD: %ld\n", inbound_payload.metrics[i].alias);
}
} else {
fprintf(stdout, "Not a metric name or alias??\n");
}
}
}
/*
* Callback for successful or unsuccessful MQTT connect. Upon successful connect, subscribe to our Sparkplug NCMD and DCMD messages.
* A production application should handle MQTT connect failures and reattempt as necessary.
*/
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) {
if (!result) {
// Subscribe to commands
mosquitto_subscribe(mosq, NULL, "spBv1.0/Sparkplug B Devices/NCMD/C Edge Node 1/#", 0);
mosquitto_subscribe(mosq, NULL, "spBv1.0/Sparkplug B Devices/DCMD/C Edge Node 1/#", 0);
} else {
fprintf(stderr, "MQTT Connect failed\n");
}
}
/*
* Callback for successful MQTT subscriptions.
*/
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) {
int i;
fprintf(stdout, "Subscribed (mid: %d): %d", mid, granted_qos[0]);
for (i = 1; i < qos_count; i++) {
fprintf(stdout, ", %d", granted_qos[i]);
}
fprintf(stdout, "\n");
}
/*
* MQTT logger callback
*/
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) {
// Print all log messages regardless of level.
fprintf(stdout, "%s\n", str);
}
/*
* Helper to publish the Sparkplug NBIRTH and DBIRTH messages after initial MQTT connect.
* This is also used for Rebirth requests from the backend.
*/
void publish_births(struct mosquitto *mosq) {
// Initialize the sequence number for Sparkplug MQTT messages
// This must be zero on every NBIRTH publish
// Publish the NBIRTH
publish_node_birth(mosq);
// Publish the DBIRTH
publish_device_birth(mosq);
}
/*
* Helper function to publish a NBIRTH message. The NBIRTH should include all 'node control' metrics that denote device capability.
* In addition, it should include every node metric that may ever be published from this edge node. If any NDATA messages arrive at
* MQTT Engine that were not included in the NBIRTH, MQTT Engine will request a Rebirth from the device.
*/
void publish_node_birth(struct mosquitto *mosq) {
// Create the NBIRTH payload
org_eclipse_tahu_protobuf_Payload nbirth_payload;
// Initialize the sequence number for Sparkplug MQTT messages
// This must be zero on every NBIRTH publish
reset_sparkplug_sequence();
get_next_payload(&nbirth_payload);
nbirth_payload.uuid = strdup("MyUUID");
// Add node control metrics
fprintf(stdout, "Adding metric: 'Node Control/Next Server'\n");
bool next_server_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Next Server", true, Next_Server, METRIC_DATA_TYPE_BOOLEAN, false, false, &next_server_value, sizeof(next_server_value));
fprintf(stdout, "Adding metric: 'Node Control/Rebirth'\n");
bool rebirth_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Rebirth", true, Rebirth, METRIC_DATA_TYPE_BOOLEAN, false, false, &rebirth_value, sizeof(rebirth_value));
fprintf(stdout, "Adding metric: 'Node Control/Reboot'\n");
bool reboot_value = false;
add_simple_metric(&nbirth_payload, "Node Control/Reboot", true, Reboot, METRIC_DATA_TYPE_BOOLEAN, false, false, &reboot_value, sizeof(reboot_value));
// Add some regular node metrics
fprintf(stdout, "Adding metric: 'Node Metric0'\n");
char nbirth_metric_zero_value[] = "hello node";
add_simple_metric(&nbirth_payload, "Node Metric0", true, Node_Metric0, METRIC_DATA_TYPE_STRING, false, false, &nbirth_metric_zero_value, sizeof(nbirth_metric_zero_value));
fprintf(stdout, "Adding metric: 'Node Metric1'\n");
bool nbirth_metric_one_value = true;
add_simple_metric(&nbirth_payload, "Node Metric1", true, Node_Metric1, METRIC_DATA_TYPE_BOOLEAN, false, false, &nbirth_metric_one_value, sizeof(nbirth_metric_one_value));
// Create a DataSet
org_eclipse_tahu_protobuf_Payload_DataSet dataset = org_eclipse_tahu_protobuf_Payload_DataSet_init_default;
uint32_t datatypes[] = { DATA_SET_DATA_TYPE_INT8,
DATA_SET_DATA_TYPE_INT16,
DATA_SET_DATA_TYPE_INT32 };
const char *column_keys[] = { "Int8s",
"Int16s",
"Int32s" };
org_eclipse_tahu_protobuf_Payload_DataSet_Row *row_data = (org_eclipse_tahu_protobuf_Payload_DataSet_Row *)
calloc(2, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_Row));
row_data[0].elements_count = 3;
row_data[0].elements = (org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *)
calloc(3, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue));
row_data[0].elements[0].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[0].elements[0].value.int_value = 0;
row_data[0].elements[1].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[0].elements[1].value.int_value = 1;
row_data[0].elements[2].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[0].elements[2].value.int_value = 2;
row_data[1].elements_count = 3;
row_data[1].elements = (org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue *)
calloc(3, sizeof(org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue));
row_data[1].elements[0].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[1].elements[0].value.int_value = 3;
row_data[1].elements[1].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[1].elements[1].value.int_value = 4;
row_data[1].elements[2].which_value = org_eclipse_tahu_protobuf_Payload_DataSet_DataSetValue_int_value_tag;
row_data[1].elements[2].value.int_value = 5;
init_dataset(&dataset, 2, 3, datatypes, column_keys, row_data);
// Create the a Metric with the DataSet value and add it to the payload
fprintf(stdout, "Adding metric: 'DataSet'\n");
org_eclipse_tahu_protobuf_Payload_Metric dataset_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&dataset_metric, "DataSet", true, Dataset, METRIC_DATA_TYPE_DATASET, false, false, &dataset, sizeof(dataset));
add_metric_to_payload(&nbirth_payload, &dataset_metric);
// Add a metric with a custom property
fprintf(stdout, "Adding metric: 'Node Metric2'\n");
org_eclipse_tahu_protobuf_Payload_Metric prop_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t nbirth_metric_two_value = 13;
init_metric(&prop_metric, "Node Metric2", true, Node_Metric2, METRIC_DATA_TYPE_INT16, false, false, &nbirth_metric_two_value, sizeof(nbirth_metric_two_value));
org_eclipse_tahu_protobuf_Payload_PropertySet properties = org_eclipse_tahu_protobuf_Payload_PropertySet_init_default;
add_property_to_set(&properties, "engUnit", PROPERTY_DATA_TYPE_STRING, "MyCustomUnits", sizeof("MyCustomUnits"));
add_propertyset_to_metric(&prop_metric, &properties);
add_metric_to_payload(&nbirth_payload, &prop_metric);
// Create a metric called RPMs which is a member of the UDT definition - note aliases do not apply to UDT members
org_eclipse_tahu_protobuf_Payload_Metric rpms_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t rpms_value = 0;
init_metric(&rpms_metric, "RPMs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &rpms_value, sizeof(rpms_value));
// Create a metric called AMPs which is a member of the UDT definition - note aliases do not apply to UDT members
org_eclipse_tahu_protobuf_Payload_Metric amps_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t amps_value = 0;
init_metric(&s_metric, "AMPs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &s_value, sizeof(amps_value));
// Create a Template/UDT Parameter - this is purely for example of including parameters and is not actually used by UDT instances
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter.name = strdup("Index");
parameter.has_type = true;
parameter.type = PARAMETER_DATA_TYPE_STRING;
parameter.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag;
parameter.value.string_value = strdup("0");
// Create the UDT definition value which includes the UDT members and parameters
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.metrics_count = 2;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(2, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = rpms_metric;
udt_template.metrics[1] = amps_metric;
udt_template.parameters_count = 1;
udt_template.parameters = (org_eclipse_tahu_protobuf_Payload_Template_Parameter *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Template_Parameter));
udt_template.parameters[0] = parameter;
udt_template.template_ref = NULL;
udt_template.has_is_definition = true;
udt_template.is_definition = true;
// Create the root UDT definition and add the UDT definition value which includes the UDT members and parameters
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "_types_/Custom_Motor", false, 0, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
// Add the UDT to the payload
add_metric_to_payload(&nbirth_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload for debug
print_payload(&nbirth_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &nbirth_payload);
// Publish the NBIRTH on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/NBIRTH/C Edge Node 1", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free(row_data);
free_payload(&nbirth_payload);
}
void publish_device_birth(struct mosquitto *mosq) {
// Create the DBIRTH payload
org_eclipse_tahu_protobuf_Payload dbirth_payload;
get_next_payload(&dbirth_payload);
// Add some device metrics
fprintf(stdout, "Adding metric: 'input/Device Metric0'\n");
char dbirth_metric_zero_value[] = "hello device";
add_simple_metric(&dbirth_payload, "input/Device Metric0", true, Device_Metric0, METRIC_DATA_TYPE_STRING, false, false, &dbirth_metric_zero_value, sizeof(dbirth_metric_zero_value));
fprintf(stdout, "Adding metric: 'input/Device Metric1'\n");
bool dbirth_metric_one_value = true;
add_simple_metric(&dbirth_payload, "input/Device Metric1", true, Device_Metric1, METRIC_DATA_TYPE_BOOLEAN, false, false, &dbirth_metric_one_value, sizeof(dbirth_metric_one_value));
fprintf(stdout, "Adding metric: 'output/Device Metric2'\n");
uint32_t dbirth_metric_two_value = 16;
add_simple_metric(&dbirth_payload, "output/Device Metric2", true, Device_Metric2, METRIC_DATA_TYPE_INT16, false, false, &dbirth_metric_two_value, sizeof(dbirth_metric_two_value));
fprintf(stdout, "Adding metric: 'output/Device Metric3'\n");
bool dbirth_metric_three_value = true;
add_simple_metric(&dbirth_payload, "output/Device Metric3", true, Device_Metric3, METRIC_DATA_TYPE_BOOLEAN, false, false, &dbirth_metric_three_value, sizeof(dbirth_metric_three_value));
// Create a metric called RPMs for the UDT instance
org_eclipse_tahu_protobuf_Payload_Metric rpms_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t rpms_value = 123;
init_metric(&rpms_metric, "RPMs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &rpms_value, sizeof(rpms_value));
// Create a metric called AMPs for the UDT instance and create a custom property (milliamps) for it
org_eclipse_tahu_protobuf_Payload_Metric amps_metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
uint32_t amps_value = 456;
init_metric(&s_metric, "AMPs", false, 0, METRIC_DATA_TYPE_INT32, false, false, &s_value, sizeof(amps_value));
org_eclipse_tahu_protobuf_Payload_PropertySet properties = org_eclipse_tahu_protobuf_Payload_PropertySet_init_default;
add_property_to_set(&properties, "engUnit", PROPERTY_DATA_TYPE_STRING, "milliamps", sizeof("milliamps"));
add_propertyset_to_metric(&s_metric, &properties);
// Create a Template/UDT instance Parameter - this is purely for example of including parameters and is not actually used by UDT instances
org_eclipse_tahu_protobuf_Payload_Template_Parameter parameter = org_eclipse_tahu_protobuf_Payload_Template_Parameter_init_default;
parameter.name = strdup("Index");
parameter.has_type = true;
parameter.type = PARAMETER_DATA_TYPE_STRING;
parameter.which_value = org_eclipse_tahu_protobuf_Payload_Template_Parameter_string_value_tag;
parameter.value.string_value = strdup("1");
// Create the UDT instance value which includes the UDT members and parameters
org_eclipse_tahu_protobuf_Payload_Template udt_template = org_eclipse_tahu_protobuf_Payload_Template_init_default;
udt_template.version = NULL;
udt_template.metrics_count = 2;
udt_template.metrics = (org_eclipse_tahu_protobuf_Payload_Metric *)calloc(2, sizeof(org_eclipse_tahu_protobuf_Payload_Metric));
udt_template.metrics[0] = rpms_metric;
udt_template.metrics[1] = amps_metric;
udt_template.parameters_count = 1;
udt_template.parameters = (org_eclipse_tahu_protobuf_Payload_Template_Parameter *)calloc(1, sizeof(org_eclipse_tahu_protobuf_Payload_Template_Parameter));
udt_template.parameters[0] = parameter;
udt_template.template_ref = strdup("Custom_Motor");
udt_template.has_is_definition = true;
udt_template.is_definition = false;
// Create the root UDT instance and add the UDT instance value
org_eclipse_tahu_protobuf_Payload_Metric metric = org_eclipse_tahu_protobuf_Payload_Metric_init_default;
init_metric(&metric, "My_Custom_Motor", true, My_Custom_Motor, METRIC_DATA_TYPE_TEMPLATE, false, false, &udt_template, sizeof(udt_template));
// Add the UDT Instance to the payload
add_metric_to_payload(&dbirth_payload, &metric);
#ifdef SPARKPLUG_DEBUG
// Print the payload
print_payload(&dbirth_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &dbirth_payload);
// Publish the DBIRTH on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DBIRTH/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&dbirth_payload);
}
void publish_ddata_message(struct mosquitto *mosq) {
// Create the DDATA payload
org_eclipse_tahu_protobuf_Payload ddata_payload;
get_next_payload(&ddata_payload);
// Add some device metrics to denote changed values on inputs
fprintf(stdout, "Adding metric: 'input/Device Metric0'\n");
char ddata_metric_zero_value[13];
int i;
for (i = 0; i < 12; ++i) {
ddata_metric_zero_value[i] = '0' + rand() % 72; // starting on '0', ending on '}'
}
ddata_metric_zero_value[12] = 0;
// Note the Metric name 'input/Device Metric0' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, Device_Metric0, METRIC_DATA_TYPE_STRING, false, false, &ddata_metric_zero_value, sizeof(ddata_metric_zero_value));
fprintf(stdout, "Adding metric: 'input/Device Metric1'\n");
bool ddata_metric_one_value = rand() % 2;
// Note the Metric name 'input/Device Metric1' is not needed because we're using aliases
add_simple_metric(&ddata_payload, NULL, true, Device_Metric1, METRIC_DATA_TYPE_BOOLEAN, false, false, &ddata_metric_one_value, sizeof(ddata_metric_one_value));
#ifdef SPARKPLUG_DEBUG
// Print the payload
print_payload(&ddata_payload);
#endif
// Encode the payload into a binary format so it can be published in the MQTT message.
// The binary_buffer must be large enough to hold the contents of the binary payload
size_t buffer_length = 1024;
uint8_t *binary_buffer = (uint8_t *)malloc(buffer_length * sizeof(uint8_t));
size_t message_length = encode_payload(binary_buffer, buffer_length, &ddata_payload);
// Publish the DDATA on the appropriate topic
mosquitto_publish(mosq, NULL, "spBv1.0/Sparkplug B Devices/DDATA/C Edge Node 1/Emulated Device", message_length, binary_buffer, 0, false);
// Free the memory
free(binary_buffer);
free_payload(&ddata_payload);
}
================================================
FILE: c_sharp/core/readme.txt
================================================
# To generate the base protobuf sparkplug_b Java library
protoc --proto_path=../../ --csharp_out=src --csharp_opt=base_namespace=Org.Eclipse.Tahu.Protobuf ../../sparkplug_b/sparkplug_b_c_sharp.proto
================================================
FILE: c_sharp/core/src/SparkplugBCSharp.cs
================================================
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: sparkplug_b/sparkplug_b_c_sharp.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Org.Eclipse.Tahu.Protobuf {
/// Holder for reflection information generated from sparkplug_b/sparkplug_b_c_sharp.proto
public static partial class SparkplugBCSharpReflection {
#region Descriptor
/// File descriptor for sparkplug_b/sparkplug_b_c_sharp.proto
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static SparkplugBCSharpReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"CiVzcGFya3BsdWdfYi9zcGFya3BsdWdfYl9jX3NoYXJwLnByb3RvEhlvcmcu",
"ZWNsaXBzZS50YWh1LnByb3RvYnVmGhlnb29nbGUvcHJvdG9idWYvYW55LnBy",
"b3RvIrEYCgdQYXlsb2FkEhEKCXRpbWVzdGFtcBgBIAEoBBI6CgdtZXRyaWNz",
"GAIgAygLMikub3JnLmVjbGlwc2UudGFodS5wcm90b2J1Zi5QYXlsb2FkLk1l",
"dHJpYxILCgNzZXEYAyABKAQSDAoEdXVpZBgEIAEoCRIMCgRib2R5GAUgASgM",
"EiUKB2RldGFpbHMYBiADKAsyFC5nb29nbGUucHJvdG9idWYuQW55GuMECghU",
"ZW1wbGF0ZRIPCgd2ZXJzaW9uGAEgASgJEjoKB21ldHJpY3MYAiADKAsyKS5v",
"cmcuZWNsaXBzZS50YWh1LnByb3RvYnVmLlBheWxvYWQuTWV0cmljEkkKCnBh",
"cmFtZXRlcnMYAyADKAsyNS5vcmcuZWNsaXBzZS50YWh1LnByb3RvYnVmLlBh",
"eWxvYWQuVGVtcGxhdGUuUGFyYW1ldGVyEhQKDHRlbXBsYXRlX3JlZhgEIAEo",
"CRIVCg1pc19kZWZpbml0aW9uGAUgASgIEiUKB2RldGFpbHMYBiADKAsyFC5n",
"b29nbGUucHJvdG9idWYuQW55GuoCCglQYXJhbWV0ZXISDAoEbmFtZRgBIAEo",
"CRIMCgR0eXBlGAIgASgNEhMKCWludF92YWx1ZRgDIAEoDUgAEhQKCmxvbmdf",
"dmFsdWUYBCABKARIABIVCgtmbG9hdF92YWx1ZRgFIAEoAkgAEhYKDGRvdWJs",
"ZV92YWx1ZRgGIAEoAUgAEhcKDWJvb2xlYW5fdmFsdWUYByABKAhIABIWCgxz",
"dHJpbmdfdmFsdWUYCCABKAlIABJoCg9leHRlbnNpb25fdmFsdWUYCSABKAsy",
"TS5vcmcuZWNsaXBzZS50YWh1LnByb3RvYnVmLlBheWxvYWQuVGVtcGxhdGUu",
"UGFyYW1ldGVyLlBhcmFtZXRlclZhbHVlRXh0ZW5zaW9uSAAaQwoXUGFyYW1l",
"dGVyVmFsdWVFeHRlbnNpb24SKAoKZXh0ZW5zaW9ucxgBIAMoCzIULmdvb2ds",
"ZS5wcm90b2J1Zi5BbnlCBwoFdmFsdWUa7gQKB0RhdGFTZXQSFgoObnVtX29m",
"X2NvbHVtbnMYASABKAQSDwoHY29sdW1ucxgCIAMoCRINCgV0eXBlcxgDIAMo",
"DRI8CgRyb3dzGAQgAygLMi4ub3JnLmVjbGlwc2UudGFodS5wcm90b2J1Zi5Q",
"YXlsb2FkLkRhdGFTZXQuUm93EiUKB2RldGFpbHMYBSADKAsyFC5nb29nbGUu",
"cHJvdG9idWYuQW55GswCCgxEYXRhU2V0VmFsdWUSEwoJaW50X3ZhbHVlGAEg",
"ASgNSAASFAoKbG9uZ192YWx1ZRgCIAEoBEgAEhUKC2Zsb2F0X3ZhbHVlGAMg",
"ASgCSAASFgoMZG91YmxlX3ZhbHVlGAQgASgBSAASFwoNYm9vbGVhbl92YWx1",
"ZRgFIAEoCEgAEhYKDHN0cmluZ192YWx1ZRgGIAEoCUgAEmgKD2V4dGVuc2lv",
"bl92YWx1ZRgHIAEoCzJNLm9yZy5lY2xpcHNlLnRhaHUucHJvdG9idWYuUGF5",
"bG9hZC5EYXRhU2V0LkRhdGFTZXRWYWx1ZS5EYXRhU2V0VmFsdWVFeHRlbnNp",
"b25IABo+ChVEYXRhU2V0VmFsdWVFeHRlbnNpb24SJQoHZGV0YWlscxgBIAMo",
"CzIULmdvb2dsZS5wcm90b2J1Zi5BbnlCBwoFdmFsdWUadwoDUm93EkkKCGVs",
"ZW1lbnRzGAEgAygLMjcub3JnLmVjbGlwc2UudGFodS5wcm90b2J1Zi5QYXls",
"b2FkLkRhdGFTZXQuRGF0YVNldFZhbHVlEiUKB2RldGFpbHMYAiADKAsyFC5n",
"b29nbGUucHJvdG9idWYuQW55GoYECg1Qcm9wZXJ0eVZhbHVlEgwKBHR5cGUY",
"ASABKA0SDwoHaXNfbnVsbBgCIAEoCBITCglpbnRfdmFsdWUYAyABKA1IABIU",
"Cgpsb25nX3ZhbHVlGAQgASgESAASFQoLZmxvYXRfdmFsdWUYBSABKAJIABIW",
"Cgxkb3VibGVfdmFsdWUYBiABKAFIABIXCg1ib29sZWFuX3ZhbHVlGAcgASgI",
"SAASFgoMc3RyaW5nX3ZhbHVlGAggASgJSAASSwoRcHJvcGVydHlzZXRfdmFs",
"dWUYCSABKAsyLi5vcmcuZWNsaXBzZS50YWh1LnByb3RvYnVmLlBheWxvYWQu",
"UHJvcGVydHlTZXRIABJQChJwcm9wZXJ0eXNldHNfdmFsdWUYCiABKAsyMi5v",
"cmcuZWNsaXBzZS50YWh1LnByb3RvYnVmLlBheWxvYWQuUHJvcGVydHlTZXRM",
"aXN0SAASYgoPZXh0ZW5zaW9uX3ZhbHVlGAsgASgLMkcub3JnLmVjbGlwc2Uu",
"dGFodS5wcm90b2J1Zi5QYXlsb2FkLlByb3BlcnR5VmFsdWUuUHJvcGVydHlW",
"YWx1ZUV4dGVuc2lvbkgAGj8KFlByb3BlcnR5VmFsdWVFeHRlbnNpb24SJQoH",
"ZGV0YWlscxgBIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlCBwoFdmFsdWUa",
"hAEKC1Byb3BlcnR5U2V0EgwKBGtleXMYASADKAkSQAoGdmFsdWVzGAIgAygL",
"MjAub3JnLmVjbGlwc2UudGFodS5wcm90b2J1Zi5QYXlsb2FkLlByb3BlcnR5",
"VmFsdWUSJQoHZGV0YWlscxgDIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5Bbnka",
"fQoPUHJvcGVydHlTZXRMaXN0EkMKC3Byb3BlcnR5c2V0GAEgAygLMi4ub3Jn",
"LmVjbGlwc2UudGFodS5wcm90b2J1Zi5QYXlsb2FkLlByb3BlcnR5U2V0EiUK",
"B2RldGFpbHMYAiADKAsyFC5nb29nbGUucHJvdG9idWYuQW55GsEBCghNZXRh",
"RGF0YRIVCg1pc19tdWx0aV9wYXJ0GAEgASgIEhQKDGNvbnRlbnRfdHlwZRgC",
"IAEoCRIMCgRzaXplGAMgASgEEgsKA3NlcRgEIAEoBBIRCglmaWxlX25hbWUY",
"BSABKAkSEQoJZmlsZV90eXBlGAYgASgJEgsKA21kNRgHIAEoCRITCgtkZXNj",
"cmlwdGlvbhgIIAEoCRIlCgdkZXRhaWxzGAkgAygLMhQuZ29vZ2xlLnByb3Rv",
"YnVmLkFueRrcBQoGTWV0cmljEgwKBG5hbWUYASABKAkSDQoFYWxpYXMYAiAB",
"KAQSEQoJdGltZXN0YW1wGAMgASgEEhAKCGRhdGF0eXBlGAQgASgNEhUKDWlz",
"X2hpc3RvcmljYWwYBSABKAgSFAoMaXNfdHJhbnNpZW50GAYgASgIEg8KB2lz",
"X251bGwYByABKAgSPQoIbWV0YWRhdGEYCCABKAsyKy5vcmcuZWNsaXBzZS50",
"YWh1LnByb3RvYnVmLlBheWxvYWQuTWV0YURhdGESQgoKcHJvcGVydGllcxgJ",
"IAEoCzIuLm9yZy5lY2xpcHNlLnRhaHUucHJvdG9idWYuUGF5bG9hZC5Qcm9w",
"ZXJ0eVNldBITCglpbnRfdmFsdWUYCiABKA1IABIUCgpsb25nX3ZhbHVlGAsg",
"ASgESAASFQoLZmxvYXRfdmFsdWUYDCABKAJIABIWCgxkb3VibGVfdmFsdWUY",
"DSABKAFIABIXCg1ib29sZWFuX3ZhbHVlGA4gASgISAASFgoMc3RyaW5nX3Zh",
"bHVlGA8gASgJSAASFQoLYnl0ZXNfdmFsdWUYECABKAxIABJDCg1kYXRhc2V0",
"X3ZhbHVlGBEgASgLMioub3JnLmVjbGlwc2UudGFodS5wcm90b2J1Zi5QYXls",
"b2FkLkRhdGFTZXRIABJFCg50ZW1wbGF0ZV92YWx1ZRgSIAEoCzIrLm9yZy5l",
"Y2xpcHNlLnRhaHUucHJvdG9idWYuUGF5bG9hZC5UZW1wbGF0ZUgAElkKD2V4",
"dGVuc2lvbl92YWx1ZRgTIAEoCzI+Lm9yZy5lY2xpcHNlLnRhaHUucHJvdG9i",
"dWYuUGF5bG9hZC5NZXRyaWMuTWV0cmljVmFsdWVFeHRlbnNpb25IABo9ChRN",
"ZXRyaWNWYWx1ZUV4dGVuc2lvbhIlCgdkZXRhaWxzGAEgAygLMhQuZ29vZ2xl",
"LnByb3RvYnVmLkFueUIHCgV2YWx1ZUIsChlvcmcuZWNsaXBzZS50YWh1LnBy",
"b3RvYnVmQg9TcGFya3BsdWdCUHJvdG9iBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload), global::Org.Eclipse.Tahu.Protobuf.Payload.Parser, new[]{ "Timestamp", "Metrics", "Seq", "Uuid", "Body", "Details" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Parser, new[]{ "Version", "Metrics", "Parameters", "TemplateRef", "IsDefinition", "Details" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Parser, new[]{ "Name", "Type", "IntValue", "LongValue", "FloatValue", "DoubleValue", "BooleanValue", "StringValue", "ExtensionValue" }, new[]{ "Value" }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Types.ParameterValueExtension), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Types.ParameterValueExtension.Parser, new[]{ "Extensions" }, null, null, null)})}),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Parser, new[]{ "NumOfColumns", "Columns", "Types_", "Rows", "Details" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Parser, new[]{ "IntValue", "LongValue", "FloatValue", "DoubleValue", "BooleanValue", "StringValue", "ExtensionValue" }, new[]{ "Value" }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Types.DataSetValueExtension), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Types.DataSetValueExtension.Parser, new[]{ "Details" }, null, null, null)}),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.Row), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.Row.Parser, new[]{ "Elements", "Details" }, null, null, null)}),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Parser, new[]{ "Type", "IsNull", "IntValue", "LongValue", "FloatValue", "DoubleValue", "BooleanValue", "StringValue", "PropertysetValue", "PropertysetsValue", "ExtensionValue" }, new[]{ "Value" }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Types.PropertyValueExtension), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Types.PropertyValueExtension.Parser, new[]{ "Details" }, null, null, null)}),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet.Parser, new[]{ "Keys", "Values", "Details" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySetList), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySetList.Parser, new[]{ "Propertyset", "Details" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.MetaData), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.MetaData.Parser, new[]{ "IsMultiPart", "ContentType", "Size", "Seq", "FileName", "FileType", "Md5", "Description", "Details" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Parser, new[]{ "Name", "Alias", "Timestamp", "Datatype", "IsHistorical", "IsTransient", "IsNull", "Metadata", "Properties", "IntValue", "LongValue", "FloatValue", "DoubleValue", "BooleanValue", "StringValue", "BytesValue", "DatasetValue", "TemplateValue", "ExtensionValue" }, new[]{ "Value" }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Types.MetricValueExtension), global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Types.MetricValueExtension.Parser, new[]{ "Details" }, null, null, null)})})
}));
}
#endregion
}
#region Messages
///
///
///// Indexes of Data Types
///// Unknown placeholder for future expansion.
///Unknown = 0;
///// Basic Types
///Int8 = 1;
///Int16 = 2;
///Int32 = 3;
///Int64 = 4;
///UInt8 = 5;
///UInt16 = 6;
///UInt32 = 7;
///UInt64 = 8;
///Float = 9;
///Double = 10;
///Boolean = 11;
///String = 12;
///DateTime = 13;
///Text = 14;
///// Additional Metric Types
///UUID = 15;
///DataSet = 16;
///Bytes = 17;
///File = 18;
///Template = 19;
///// Additional PropertyValue Types
///PropertySet = 20;
///PropertySetList = 21;
///
public sealed partial class Payload : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Payload());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.SparkplugBCSharpReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Payload() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Payload(Payload other) : this() {
timestamp_ = other.timestamp_;
metrics_ = other.metrics_.Clone();
seq_ = other.seq_;
uuid_ = other.uuid_;
body_ = other.body_;
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Payload Clone() {
return new Payload(this);
}
/// Field number for the "timestamp" field.
public const int TimestampFieldNumber = 1;
private ulong timestamp_;
///
/// Timestamp at message sending time
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong Timestamp {
get { return timestamp_; }
set {
timestamp_ = value;
}
}
/// Field number for the "metrics" field.
public const int MetricsFieldNumber = 2;
private static readonly pb::FieldCodec _repeated_metrics_codec
= pb::FieldCodec.ForMessage(18, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Parser);
private readonly pbc::RepeatedField metrics_ = new pbc::RepeatedField();
///
/// Repeated forever - no limit in Google Protobufs
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Metrics {
get { return metrics_; }
}
/// Field number for the "seq" field.
public const int SeqFieldNumber = 3;
private ulong seq_;
///
/// Sequence number
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong Seq {
get { return seq_; }
set {
seq_ = value;
}
}
/// Field number for the "uuid" field.
public const int UuidFieldNumber = 4;
private string uuid_ = "";
///
/// UUID to track message type in terms of schema definitions
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Uuid {
get { return uuid_; }
set {
uuid_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "body" field.
public const int BodyFieldNumber = 5;
private pb::ByteString body_ = pb::ByteString.Empty;
///
/// To optionally bypass the whole definition above
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pb::ByteString Body {
get { return body_; }
set {
body_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 6;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Payload);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Payload other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Timestamp != other.Timestamp) return false;
if(!metrics_.Equals(other.metrics_)) return false;
if (Seq != other.Seq) return false;
if (Uuid != other.Uuid) return false;
if (Body != other.Body) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Timestamp != 0UL) hash ^= Timestamp.GetHashCode();
hash ^= metrics_.GetHashCode();
if (Seq != 0UL) hash ^= Seq.GetHashCode();
if (Uuid.Length != 0) hash ^= Uuid.GetHashCode();
if (Body.Length != 0) hash ^= Body.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Timestamp != 0UL) {
output.WriteRawTag(8);
output.WriteUInt64(Timestamp);
}
metrics_.WriteTo(output, _repeated_metrics_codec);
if (Seq != 0UL) {
output.WriteRawTag(24);
output.WriteUInt64(Seq);
}
if (Uuid.Length != 0) {
output.WriteRawTag(34);
output.WriteString(Uuid);
}
if (Body.Length != 0) {
output.WriteRawTag(42);
output.WriteBytes(Body);
}
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Timestamp != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Timestamp);
}
size += metrics_.CalculateSize(_repeated_metrics_codec);
if (Seq != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Seq);
}
if (Uuid.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Uuid);
}
if (Body.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeBytesSize(Body);
}
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Payload other) {
if (other == null) {
return;
}
if (other.Timestamp != 0UL) {
Timestamp = other.Timestamp;
}
metrics_.Add(other.metrics_);
if (other.Seq != 0UL) {
Seq = other.Seq;
}
if (other.Uuid.Length != 0) {
Uuid = other.Uuid;
}
if (other.Body.Length != 0) {
Body = other.Body;
}
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
Timestamp = input.ReadUInt64();
break;
}
case 18: {
metrics_.AddEntriesFrom(input, _repeated_metrics_codec);
break;
}
case 24: {
Seq = input.ReadUInt64();
break;
}
case 34: {
Uuid = input.ReadString();
break;
}
case 42: {
Body = input.ReadBytes();
break;
}
case 50: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the Payload message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class Template : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Template());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Template() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Template(Template other) : this() {
version_ = other.version_;
metrics_ = other.metrics_.Clone();
parameters_ = other.parameters_.Clone();
templateRef_ = other.templateRef_;
isDefinition_ = other.isDefinition_;
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Template Clone() {
return new Template(this);
}
/// Field number for the "version" field.
public const int VersionFieldNumber = 1;
private string version_ = "";
///
/// The version of the Template to prevent mismatches
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Version {
get { return version_; }
set {
version_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "metrics" field.
public const int MetricsFieldNumber = 2;
private static readonly pb::FieldCodec _repeated_metrics_codec
= pb::FieldCodec.ForMessage(18, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Parser);
private readonly pbc::RepeatedField metrics_ = new pbc::RepeatedField();
///
/// Each metric is the name of the metric and the datatype of the member but does not contain a value
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Metrics {
get { return metrics_; }
}
/// Field number for the "parameters" field.
public const int ParametersFieldNumber = 3;
private static readonly pb::FieldCodec _repeated_parameters_codec
= pb::FieldCodec.ForMessage(26, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Parser);
private readonly pbc::RepeatedField parameters_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Parameters {
get { return parameters_; }
}
/// Field number for the "template_ref" field.
public const int TemplateRefFieldNumber = 4;
private string templateRef_ = "";
///
/// Reference to a template if this is extending a Template or an instance - must exist if an instance
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string TemplateRef {
get { return templateRef_; }
set {
templateRef_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "is_definition" field.
public const int IsDefinitionFieldNumber = 5;
private bool isDefinition_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool IsDefinition {
get { return isDefinition_; }
set {
isDefinition_ = value;
}
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 6;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Template);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Template other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Version != other.Version) return false;
if(!metrics_.Equals(other.metrics_)) return false;
if(!parameters_.Equals(other.parameters_)) return false;
if (TemplateRef != other.TemplateRef) return false;
if (IsDefinition != other.IsDefinition) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Version.Length != 0) hash ^= Version.GetHashCode();
hash ^= metrics_.GetHashCode();
hash ^= parameters_.GetHashCode();
if (TemplateRef.Length != 0) hash ^= TemplateRef.GetHashCode();
if (IsDefinition != false) hash ^= IsDefinition.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Version.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Version);
}
metrics_.WriteTo(output, _repeated_metrics_codec);
parameters_.WriteTo(output, _repeated_parameters_codec);
if (TemplateRef.Length != 0) {
output.WriteRawTag(34);
output.WriteString(TemplateRef);
}
if (IsDefinition != false) {
output.WriteRawTag(40);
output.WriteBool(IsDefinition);
}
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Version.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Version);
}
size += metrics_.CalculateSize(_repeated_metrics_codec);
size += parameters_.CalculateSize(_repeated_parameters_codec);
if (TemplateRef.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(TemplateRef);
}
if (IsDefinition != false) {
size += 1 + 1;
}
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Template other) {
if (other == null) {
return;
}
if (other.Version.Length != 0) {
Version = other.Version;
}
metrics_.Add(other.metrics_);
parameters_.Add(other.parameters_);
if (other.TemplateRef.Length != 0) {
TemplateRef = other.TemplateRef;
}
if (other.IsDefinition != false) {
IsDefinition = other.IsDefinition;
}
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
Version = input.ReadString();
break;
}
case 18: {
metrics_.AddEntriesFrom(input, _repeated_metrics_codec);
break;
}
case 26: {
parameters_.AddEntriesFrom(input, _repeated_parameters_codec);
break;
}
case 34: {
TemplateRef = input.ReadString();
break;
}
case 40: {
IsDefinition = input.ReadBool();
break;
}
case 50: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the Template message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class Parameter : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Parameter());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Parameter() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Parameter(Parameter other) : this() {
name_ = other.name_;
type_ = other.type_;
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue.Clone();
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Parameter Clone() {
return new Parameter(this);
}
/// Field number for the "name" field.
public const int NameFieldNumber = 1;
private string name_ = "";
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Name {
get { return name_; }
set {
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "type" field.
public const int TypeFieldNumber = 2;
private uint type_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint Type {
get { return type_; }
set {
type_ = value;
}
}
/// Field number for the "int_value" field.
public const int IntValueFieldNumber = 3;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint IntValue {
get { return valueCase_ == ValueOneofCase.IntValue ? (uint) value_ : 0; }
set {
value_ = value;
valueCase_ = ValueOneofCase.IntValue;
}
}
/// Field number for the "long_value" field.
public const int LongValueFieldNumber = 4;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong LongValue {
get { return valueCase_ == ValueOneofCase.LongValue ? (ulong) value_ : 0UL; }
set {
value_ = value;
valueCase_ = ValueOneofCase.LongValue;
}
}
/// Field number for the "float_value" field.
public const int FloatValueFieldNumber = 5;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public float FloatValue {
get { return valueCase_ == ValueOneofCase.FloatValue ? (float) value_ : 0F; }
set {
value_ = value;
valueCase_ = ValueOneofCase.FloatValue;
}
}
/// Field number for the "double_value" field.
public const int DoubleValueFieldNumber = 6;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public double DoubleValue {
get { return valueCase_ == ValueOneofCase.DoubleValue ? (double) value_ : 0D; }
set {
value_ = value;
valueCase_ = ValueOneofCase.DoubleValue;
}
}
/// Field number for the "boolean_value" field.
public const int BooleanValueFieldNumber = 7;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool BooleanValue {
get { return valueCase_ == ValueOneofCase.BooleanValue ? (bool) value_ : false; }
set {
value_ = value;
valueCase_ = ValueOneofCase.BooleanValue;
}
}
/// Field number for the "string_value" field.
public const int StringValueFieldNumber = 8;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string StringValue {
get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.StringValue;
}
}
/// Field number for the "extension_value" field.
public const int ExtensionValueFieldNumber = 9;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Types.ParameterValueExtension ExtensionValue {
get { return valueCase_ == ValueOneofCase.ExtensionValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Types.ParameterValueExtension) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.ExtensionValue;
}
}
private object value_;
/// Enum of possible cases for the "value" oneof.
public enum ValueOneofCase {
None = 0,
IntValue = 3,
LongValue = 4,
FloatValue = 5,
DoubleValue = 6,
BooleanValue = 7,
StringValue = 8,
ExtensionValue = 9,
}
private ValueOneofCase valueCase_ = ValueOneofCase.None;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ValueOneofCase ValueCase {
get { return valueCase_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void ClearValue() {
valueCase_ = ValueOneofCase.None;
value_ = null;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Parameter);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Parameter other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Name != other.Name) return false;
if (Type != other.Type) return false;
if (IntValue != other.IntValue) return false;
if (LongValue != other.LongValue) return false;
if (FloatValue != other.FloatValue) return false;
if (DoubleValue != other.DoubleValue) return false;
if (BooleanValue != other.BooleanValue) return false;
if (StringValue != other.StringValue) return false;
if (!object.Equals(ExtensionValue, other.ExtensionValue)) return false;
if (ValueCase != other.ValueCase) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (Type != 0) hash ^= Type.GetHashCode();
if (valueCase_ == ValueOneofCase.IntValue) hash ^= IntValue.GetHashCode();
if (valueCase_ == ValueOneofCase.LongValue) hash ^= LongValue.GetHashCode();
if (valueCase_ == ValueOneofCase.FloatValue) hash ^= FloatValue.GetHashCode();
if (valueCase_ == ValueOneofCase.DoubleValue) hash ^= DoubleValue.GetHashCode();
if (valueCase_ == ValueOneofCase.BooleanValue) hash ^= BooleanValue.GetHashCode();
if (valueCase_ == ValueOneofCase.StringValue) hash ^= StringValue.GetHashCode();
if (valueCase_ == ValueOneofCase.ExtensionValue) hash ^= ExtensionValue.GetHashCode();
hash ^= (int) valueCase_;
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Name.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Name);
}
if (Type != 0) {
output.WriteRawTag(16);
output.WriteUInt32(Type);
}
if (valueCase_ == ValueOneofCase.IntValue) {
output.WriteRawTag(24);
output.WriteUInt32(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
output.WriteRawTag(32);
output.WriteUInt64(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
output.WriteRawTag(45);
output.WriteFloat(FloatValue);
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
output.WriteRawTag(49);
output.WriteDouble(DoubleValue);
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
output.WriteRawTag(56);
output.WriteBool(BooleanValue);
}
if (valueCase_ == ValueOneofCase.StringValue) {
output.WriteRawTag(66);
output.WriteString(StringValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
output.WriteRawTag(74);
output.WriteMessage(ExtensionValue);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Name.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
}
if (Type != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Type);
}
if (valueCase_ == ValueOneofCase.IntValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
size += 1 + 4;
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
size += 1 + 8;
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
size += 1 + 1;
}
if (valueCase_ == ValueOneofCase.StringValue) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExtensionValue);
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Parameter other) {
if (other == null) {
return;
}
if (other.Name.Length != 0) {
Name = other.Name;
}
if (other.Type != 0) {
Type = other.Type;
}
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue;
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
break;
}
case 16: {
Type = input.ReadUInt32();
break;
}
case 24: {
IntValue = input.ReadUInt32();
break;
}
case 32: {
LongValue = input.ReadUInt64();
break;
}
case 45: {
FloatValue = input.ReadFloat();
break;
}
case 49: {
DoubleValue = input.ReadDouble();
break;
}
case 56: {
BooleanValue = input.ReadBool();
break;
}
case 66: {
StringValue = input.ReadString();
break;
}
case 74: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Types.ParameterValueExtension subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Types.ParameterValueExtension();
if (valueCase_ == ValueOneofCase.ExtensionValue) {
subBuilder.MergeFrom(ExtensionValue);
}
input.ReadMessage(subBuilder);
ExtensionValue = subBuilder;
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the Parameter message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class ParameterValueExtension : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ParameterValueExtension());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template.Types.Parameter.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ParameterValueExtension() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ParameterValueExtension(ParameterValueExtension other) : this() {
extensions_ = other.extensions_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ParameterValueExtension Clone() {
return new ParameterValueExtension(this);
}
/// Field number for the "extensions" field.
public const int ExtensionsFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_extensions_codec
= pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField extensions_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Extensions {
get { return extensions_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ParameterValueExtension);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(ParameterValueExtension other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!extensions_.Equals(other.extensions_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= extensions_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
extensions_.WriteTo(output, _repeated_extensions_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += extensions_.CalculateSize(_repeated_extensions_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(ParameterValueExtension other) {
if (other == null) {
return;
}
extensions_.Add(other.extensions_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
extensions_.AddEntriesFrom(input, _repeated_extensions_codec);
break;
}
}
}
}
}
}
#endregion
}
}
#endregion
}
public sealed partial class DataSet : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DataSet());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSet() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSet(DataSet other) : this() {
numOfColumns_ = other.numOfColumns_;
columns_ = other.columns_.Clone();
types_ = other.types_.Clone();
rows_ = other.rows_.Clone();
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSet Clone() {
return new DataSet(this);
}
/// Field number for the "num_of_columns" field.
public const int NumOfColumnsFieldNumber = 1;
private ulong numOfColumns_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong NumOfColumns {
get { return numOfColumns_; }
set {
numOfColumns_ = value;
}
}
/// Field number for the "columns" field.
public const int ColumnsFieldNumber = 2;
private static readonly pb::FieldCodec _repeated_columns_codec
= pb::FieldCodec.ForString(18);
private readonly pbc::RepeatedField columns_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Columns {
get { return columns_; }
}
/// Field number for the "types" field.
public const int Types_FieldNumber = 3;
private static readonly pb::FieldCodec _repeated_types_codec
= pb::FieldCodec.ForUInt32(26);
private readonly pbc::RepeatedField types_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Types_ {
get { return types_; }
}
/// Field number for the "rows" field.
public const int RowsFieldNumber = 4;
private static readonly pb::FieldCodec _repeated_rows_codec
= pb::FieldCodec.ForMessage(34, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.Row.Parser);
private readonly pbc::RepeatedField rows_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Rows {
get { return rows_; }
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 5;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(42, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DataSet);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DataSet other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (NumOfColumns != other.NumOfColumns) return false;
if(!columns_.Equals(other.columns_)) return false;
if(!types_.Equals(other.types_)) return false;
if(!rows_.Equals(other.rows_)) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (NumOfColumns != 0UL) hash ^= NumOfColumns.GetHashCode();
hash ^= columns_.GetHashCode();
hash ^= types_.GetHashCode();
hash ^= rows_.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (NumOfColumns != 0UL) {
output.WriteRawTag(8);
output.WriteUInt64(NumOfColumns);
}
columns_.WriteTo(output, _repeated_columns_codec);
types_.WriteTo(output, _repeated_types_codec);
rows_.WriteTo(output, _repeated_rows_codec);
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (NumOfColumns != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(NumOfColumns);
}
size += columns_.CalculateSize(_repeated_columns_codec);
size += types_.CalculateSize(_repeated_types_codec);
size += rows_.CalculateSize(_repeated_rows_codec);
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DataSet other) {
if (other == null) {
return;
}
if (other.NumOfColumns != 0UL) {
NumOfColumns = other.NumOfColumns;
}
columns_.Add(other.columns_);
types_.Add(other.types_);
rows_.Add(other.rows_);
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
NumOfColumns = input.ReadUInt64();
break;
}
case 18: {
columns_.AddEntriesFrom(input, _repeated_columns_codec);
break;
}
case 26:
case 24: {
types_.AddEntriesFrom(input, _repeated_types_codec);
break;
}
case 34: {
rows_.AddEntriesFrom(input, _repeated_rows_codec);
break;
}
case 42: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the DataSet message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class DataSetValue : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DataSetValue());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSetValue() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSetValue(DataSetValue other) : this() {
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue.Clone();
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSetValue Clone() {
return new DataSetValue(this);
}
/// Field number for the "int_value" field.
public const int IntValueFieldNumber = 1;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint IntValue {
get { return valueCase_ == ValueOneofCase.IntValue ? (uint) value_ : 0; }
set {
value_ = value;
valueCase_ = ValueOneofCase.IntValue;
}
}
/// Field number for the "long_value" field.
public const int LongValueFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong LongValue {
get { return valueCase_ == ValueOneofCase.LongValue ? (ulong) value_ : 0UL; }
set {
value_ = value;
valueCase_ = ValueOneofCase.LongValue;
}
}
/// Field number for the "float_value" field.
public const int FloatValueFieldNumber = 3;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public float FloatValue {
get { return valueCase_ == ValueOneofCase.FloatValue ? (float) value_ : 0F; }
set {
value_ = value;
valueCase_ = ValueOneofCase.FloatValue;
}
}
/// Field number for the "double_value" field.
public const int DoubleValueFieldNumber = 4;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public double DoubleValue {
get { return valueCase_ == ValueOneofCase.DoubleValue ? (double) value_ : 0D; }
set {
value_ = value;
valueCase_ = ValueOneofCase.DoubleValue;
}
}
/// Field number for the "boolean_value" field.
public const int BooleanValueFieldNumber = 5;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool BooleanValue {
get { return valueCase_ == ValueOneofCase.BooleanValue ? (bool) value_ : false; }
set {
value_ = value;
valueCase_ = ValueOneofCase.BooleanValue;
}
}
/// Field number for the "string_value" field.
public const int StringValueFieldNumber = 6;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string StringValue {
get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.StringValue;
}
}
/// Field number for the "extension_value" field.
public const int ExtensionValueFieldNumber = 7;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Types.DataSetValueExtension ExtensionValue {
get { return valueCase_ == ValueOneofCase.ExtensionValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Types.DataSetValueExtension) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.ExtensionValue;
}
}
private object value_;
/// Enum of possible cases for the "value" oneof.
public enum ValueOneofCase {
None = 0,
IntValue = 1,
LongValue = 2,
FloatValue = 3,
DoubleValue = 4,
BooleanValue = 5,
StringValue = 6,
ExtensionValue = 7,
}
private ValueOneofCase valueCase_ = ValueOneofCase.None;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ValueOneofCase ValueCase {
get { return valueCase_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void ClearValue() {
valueCase_ = ValueOneofCase.None;
value_ = null;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DataSetValue);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DataSetValue other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (IntValue != other.IntValue) return false;
if (LongValue != other.LongValue) return false;
if (FloatValue != other.FloatValue) return false;
if (DoubleValue != other.DoubleValue) return false;
if (BooleanValue != other.BooleanValue) return false;
if (StringValue != other.StringValue) return false;
if (!object.Equals(ExtensionValue, other.ExtensionValue)) return false;
if (ValueCase != other.ValueCase) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (valueCase_ == ValueOneofCase.IntValue) hash ^= IntValue.GetHashCode();
if (valueCase_ == ValueOneofCase.LongValue) hash ^= LongValue.GetHashCode();
if (valueCase_ == ValueOneofCase.FloatValue) hash ^= FloatValue.GetHashCode();
if (valueCase_ == ValueOneofCase.DoubleValue) hash ^= DoubleValue.GetHashCode();
if (valueCase_ == ValueOneofCase.BooleanValue) hash ^= BooleanValue.GetHashCode();
if (valueCase_ == ValueOneofCase.StringValue) hash ^= StringValue.GetHashCode();
if (valueCase_ == ValueOneofCase.ExtensionValue) hash ^= ExtensionValue.GetHashCode();
hash ^= (int) valueCase_;
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (valueCase_ == ValueOneofCase.IntValue) {
output.WriteRawTag(8);
output.WriteUInt32(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
output.WriteRawTag(16);
output.WriteUInt64(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
output.WriteRawTag(29);
output.WriteFloat(FloatValue);
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
output.WriteRawTag(33);
output.WriteDouble(DoubleValue);
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
output.WriteRawTag(40);
output.WriteBool(BooleanValue);
}
if (valueCase_ == ValueOneofCase.StringValue) {
output.WriteRawTag(50);
output.WriteString(StringValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
output.WriteRawTag(58);
output.WriteMessage(ExtensionValue);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (valueCase_ == ValueOneofCase.IntValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
size += 1 + 4;
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
size += 1 + 8;
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
size += 1 + 1;
}
if (valueCase_ == ValueOneofCase.StringValue) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExtensionValue);
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DataSetValue other) {
if (other == null) {
return;
}
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue;
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
IntValue = input.ReadUInt32();
break;
}
case 16: {
LongValue = input.ReadUInt64();
break;
}
case 29: {
FloatValue = input.ReadFloat();
break;
}
case 33: {
DoubleValue = input.ReadDouble();
break;
}
case 40: {
BooleanValue = input.ReadBool();
break;
}
case 50: {
StringValue = input.ReadString();
break;
}
case 58: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Types.DataSetValueExtension subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Types.DataSetValueExtension();
if (valueCase_ == ValueOneofCase.ExtensionValue) {
subBuilder.MergeFrom(ExtensionValue);
}
input.ReadMessage(subBuilder);
ExtensionValue = subBuilder;
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the DataSetValue message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class DataSetValueExtension : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DataSetValueExtension());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSetValueExtension() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSetValueExtension(DataSetValueExtension other) : this() {
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DataSetValueExtension Clone() {
return new DataSetValueExtension(this);
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DataSetValueExtension);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DataSetValueExtension other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DataSetValueExtension other) {
if (other == null) {
return;
}
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
}
#endregion
}
public sealed partial class Row : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Row());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Descriptor.NestedTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Row() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Row(Row other) : this() {
elements_ = other.elements_.Clone();
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Row Clone() {
return new Row(this);
}
/// Field number for the "elements" field.
public const int ElementsFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_elements_codec
= pb::FieldCodec.ForMessage(10, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet.Types.DataSetValue.Parser);
private readonly pbc::RepeatedField elements_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Elements {
get { return elements_; }
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 2;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Row);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Row other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!elements_.Equals(other.elements_)) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= elements_.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
elements_.WriteTo(output, _repeated_elements_codec);
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += elements_.CalculateSize(_repeated_elements_codec);
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Row other) {
if (other == null) {
return;
}
elements_.Add(other.elements_);
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
elements_.AddEntriesFrom(input, _repeated_elements_codec);
break;
}
case 18: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
}
#endregion
}
public sealed partial class PropertyValue : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PropertyValue());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[2]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertyValue() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertyValue(PropertyValue other) : this() {
type_ = other.type_;
isNull_ = other.isNull_;
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.PropertysetValue:
PropertysetValue = other.PropertysetValue.Clone();
break;
case ValueOneofCase.PropertysetsValue:
PropertysetsValue = other.PropertysetsValue.Clone();
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue.Clone();
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertyValue Clone() {
return new PropertyValue(this);
}
/// Field number for the "type" field.
public const int TypeFieldNumber = 1;
private uint type_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint Type {
get { return type_; }
set {
type_ = value;
}
}
/// Field number for the "is_null" field.
public const int IsNullFieldNumber = 2;
private bool isNull_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool IsNull {
get { return isNull_; }
set {
isNull_ = value;
}
}
/// Field number for the "int_value" field.
public const int IntValueFieldNumber = 3;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint IntValue {
get { return valueCase_ == ValueOneofCase.IntValue ? (uint) value_ : 0; }
set {
value_ = value;
valueCase_ = ValueOneofCase.IntValue;
}
}
/// Field number for the "long_value" field.
public const int LongValueFieldNumber = 4;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong LongValue {
get { return valueCase_ == ValueOneofCase.LongValue ? (ulong) value_ : 0UL; }
set {
value_ = value;
valueCase_ = ValueOneofCase.LongValue;
}
}
/// Field number for the "float_value" field.
public const int FloatValueFieldNumber = 5;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public float FloatValue {
get { return valueCase_ == ValueOneofCase.FloatValue ? (float) value_ : 0F; }
set {
value_ = value;
valueCase_ = ValueOneofCase.FloatValue;
}
}
/// Field number for the "double_value" field.
public const int DoubleValueFieldNumber = 6;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public double DoubleValue {
get { return valueCase_ == ValueOneofCase.DoubleValue ? (double) value_ : 0D; }
set {
value_ = value;
valueCase_ = ValueOneofCase.DoubleValue;
}
}
/// Field number for the "boolean_value" field.
public const int BooleanValueFieldNumber = 7;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool BooleanValue {
get { return valueCase_ == ValueOneofCase.BooleanValue ? (bool) value_ : false; }
set {
value_ = value;
valueCase_ = ValueOneofCase.BooleanValue;
}
}
/// Field number for the "string_value" field.
public const int StringValueFieldNumber = 8;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string StringValue {
get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.StringValue;
}
}
/// Field number for the "propertyset_value" field.
public const int PropertysetValueFieldNumber = 9;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet PropertysetValue {
get { return valueCase_ == ValueOneofCase.PropertysetValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.PropertysetValue;
}
}
/// Field number for the "propertysets_value" field.
public const int PropertysetsValueFieldNumber = 10;
///
/// List of Property Values
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySetList PropertysetsValue {
get { return valueCase_ == ValueOneofCase.PropertysetsValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySetList) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.PropertysetsValue;
}
}
/// Field number for the "extension_value" field.
public const int ExtensionValueFieldNumber = 11;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Types.PropertyValueExtension ExtensionValue {
get { return valueCase_ == ValueOneofCase.ExtensionValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Types.PropertyValueExtension) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.ExtensionValue;
}
}
private object value_;
/// Enum of possible cases for the "value" oneof.
public enum ValueOneofCase {
None = 0,
IntValue = 3,
LongValue = 4,
FloatValue = 5,
DoubleValue = 6,
BooleanValue = 7,
StringValue = 8,
PropertysetValue = 9,
PropertysetsValue = 10,
ExtensionValue = 11,
}
private ValueOneofCase valueCase_ = ValueOneofCase.None;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ValueOneofCase ValueCase {
get { return valueCase_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void ClearValue() {
valueCase_ = ValueOneofCase.None;
value_ = null;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as PropertyValue);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(PropertyValue other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Type != other.Type) return false;
if (IsNull != other.IsNull) return false;
if (IntValue != other.IntValue) return false;
if (LongValue != other.LongValue) return false;
if (FloatValue != other.FloatValue) return false;
if (DoubleValue != other.DoubleValue) return false;
if (BooleanValue != other.BooleanValue) return false;
if (StringValue != other.StringValue) return false;
if (!object.Equals(PropertysetValue, other.PropertysetValue)) return false;
if (!object.Equals(PropertysetsValue, other.PropertysetsValue)) return false;
if (!object.Equals(ExtensionValue, other.ExtensionValue)) return false;
if (ValueCase != other.ValueCase) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Type != 0) hash ^= Type.GetHashCode();
if (IsNull != false) hash ^= IsNull.GetHashCode();
if (valueCase_ == ValueOneofCase.IntValue) hash ^= IntValue.GetHashCode();
if (valueCase_ == ValueOneofCase.LongValue) hash ^= LongValue.GetHashCode();
if (valueCase_ == ValueOneofCase.FloatValue) hash ^= FloatValue.GetHashCode();
if (valueCase_ == ValueOneofCase.DoubleValue) hash ^= DoubleValue.GetHashCode();
if (valueCase_ == ValueOneofCase.BooleanValue) hash ^= BooleanValue.GetHashCode();
if (valueCase_ == ValueOneofCase.StringValue) hash ^= StringValue.GetHashCode();
if (valueCase_ == ValueOneofCase.PropertysetValue) hash ^= PropertysetValue.GetHashCode();
if (valueCase_ == ValueOneofCase.PropertysetsValue) hash ^= PropertysetsValue.GetHashCode();
if (valueCase_ == ValueOneofCase.ExtensionValue) hash ^= ExtensionValue.GetHashCode();
hash ^= (int) valueCase_;
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Type != 0) {
output.WriteRawTag(8);
output.WriteUInt32(Type);
}
if (IsNull != false) {
output.WriteRawTag(16);
output.WriteBool(IsNull);
}
if (valueCase_ == ValueOneofCase.IntValue) {
output.WriteRawTag(24);
output.WriteUInt32(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
output.WriteRawTag(32);
output.WriteUInt64(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
output.WriteRawTag(45);
output.WriteFloat(FloatValue);
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
output.WriteRawTag(49);
output.WriteDouble(DoubleValue);
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
output.WriteRawTag(56);
output.WriteBool(BooleanValue);
}
if (valueCase_ == ValueOneofCase.StringValue) {
output.WriteRawTag(66);
output.WriteString(StringValue);
}
if (valueCase_ == ValueOneofCase.PropertysetValue) {
output.WriteRawTag(74);
output.WriteMessage(PropertysetValue);
}
if (valueCase_ == ValueOneofCase.PropertysetsValue) {
output.WriteRawTag(82);
output.WriteMessage(PropertysetsValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
output.WriteRawTag(90);
output.WriteMessage(ExtensionValue);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Type != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Type);
}
if (IsNull != false) {
size += 1 + 1;
}
if (valueCase_ == ValueOneofCase.IntValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
size += 1 + 4;
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
size += 1 + 8;
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
size += 1 + 1;
}
if (valueCase_ == ValueOneofCase.StringValue) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
}
if (valueCase_ == ValueOneofCase.PropertysetValue) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(PropertysetValue);
}
if (valueCase_ == ValueOneofCase.PropertysetsValue) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(PropertysetsValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExtensionValue);
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(PropertyValue other) {
if (other == null) {
return;
}
if (other.Type != 0) {
Type = other.Type;
}
if (other.IsNull != false) {
IsNull = other.IsNull;
}
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.PropertysetValue:
PropertysetValue = other.PropertysetValue;
break;
case ValueOneofCase.PropertysetsValue:
PropertysetsValue = other.PropertysetsValue;
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue;
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
Type = input.ReadUInt32();
break;
}
case 16: {
IsNull = input.ReadBool();
break;
}
case 24: {
IntValue = input.ReadUInt32();
break;
}
case 32: {
LongValue = input.ReadUInt64();
break;
}
case 45: {
FloatValue = input.ReadFloat();
break;
}
case 49: {
DoubleValue = input.ReadDouble();
break;
}
case 56: {
BooleanValue = input.ReadBool();
break;
}
case 66: {
StringValue = input.ReadString();
break;
}
case 74: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet();
if (valueCase_ == ValueOneofCase.PropertysetValue) {
subBuilder.MergeFrom(PropertysetValue);
}
input.ReadMessage(subBuilder);
PropertysetValue = subBuilder;
break;
}
case 82: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySetList subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySetList();
if (valueCase_ == ValueOneofCase.PropertysetsValue) {
subBuilder.MergeFrom(PropertysetsValue);
}
input.ReadMessage(subBuilder);
PropertysetsValue = subBuilder;
break;
}
case 90: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Types.PropertyValueExtension subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Types.PropertyValueExtension();
if (valueCase_ == ValueOneofCase.ExtensionValue) {
subBuilder.MergeFrom(ExtensionValue);
}
input.ReadMessage(subBuilder);
ExtensionValue = subBuilder;
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the PropertyValue message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class PropertyValueExtension : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PropertyValueExtension());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertyValueExtension() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertyValueExtension(PropertyValueExtension other) : this() {
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertyValueExtension Clone() {
return new PropertyValueExtension(this);
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as PropertyValueExtension);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(PropertyValueExtension other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(PropertyValueExtension other) {
if (other == null) {
return;
}
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
}
#endregion
}
public sealed partial class PropertySet : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PropertySet());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[3]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertySet() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertySet(PropertySet other) : this() {
keys_ = other.keys_.Clone();
values_ = other.values_.Clone();
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertySet Clone() {
return new PropertySet(this);
}
/// Field number for the "keys" field.
public const int KeysFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_keys_codec
= pb::FieldCodec.ForString(10);
private readonly pbc::RepeatedField keys_ = new pbc::RepeatedField();
///
/// Names of the properties
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Keys {
get { return keys_; }
}
/// Field number for the "values" field.
public const int ValuesFieldNumber = 2;
private static readonly pb::FieldCodec _repeated_values_codec
= pb::FieldCodec.ForMessage(18, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertyValue.Parser);
private readonly pbc::RepeatedField values_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Values {
get { return values_; }
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 3;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as PropertySet);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(PropertySet other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!keys_.Equals(other.keys_)) return false;
if(!values_.Equals(other.values_)) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= keys_.GetHashCode();
hash ^= values_.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
keys_.WriteTo(output, _repeated_keys_codec);
values_.WriteTo(output, _repeated_values_codec);
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += keys_.CalculateSize(_repeated_keys_codec);
size += values_.CalculateSize(_repeated_values_codec);
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(PropertySet other) {
if (other == null) {
return;
}
keys_.Add(other.keys_);
values_.Add(other.values_);
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
keys_.AddEntriesFrom(input, _repeated_keys_codec);
break;
}
case 18: {
values_.AddEntriesFrom(input, _repeated_values_codec);
break;
}
case 26: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
public sealed partial class PropertySetList : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PropertySetList());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[4]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertySetList() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertySetList(PropertySetList other) : this() {
propertyset_ = other.propertyset_.Clone();
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PropertySetList Clone() {
return new PropertySetList(this);
}
/// Field number for the "propertyset" field.
public const int PropertysetFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_propertyset_codec
= pb::FieldCodec.ForMessage(10, global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet.Parser);
private readonly pbc::RepeatedField propertyset_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Propertyset {
get { return propertyset_; }
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 2;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as PropertySetList);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(PropertySetList other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!propertyset_.Equals(other.propertyset_)) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= propertyset_.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
propertyset_.WriteTo(output, _repeated_propertyset_codec);
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += propertyset_.CalculateSize(_repeated_propertyset_codec);
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(PropertySetList other) {
if (other == null) {
return;
}
propertyset_.Add(other.propertyset_);
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
propertyset_.AddEntriesFrom(input, _repeated_propertyset_codec);
break;
}
case 18: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
public sealed partial class MetaData : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MetaData());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[5]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public MetaData() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public MetaData(MetaData other) : this() {
isMultiPart_ = other.isMultiPart_;
contentType_ = other.contentType_;
size_ = other.size_;
seq_ = other.seq_;
fileName_ = other.fileName_;
fileType_ = other.fileType_;
md5_ = other.md5_;
description_ = other.description_;
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public MetaData Clone() {
return new MetaData(this);
}
/// Field number for the "is_multi_part" field.
public const int IsMultiPartFieldNumber = 1;
private bool isMultiPart_;
///
/// Bytes specific metadata
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool IsMultiPart {
get { return isMultiPart_; }
set {
isMultiPart_ = value;
}
}
/// Field number for the "content_type" field.
public const int ContentTypeFieldNumber = 2;
private string contentType_ = "";
///
/// General metadata
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string ContentType {
get { return contentType_; }
set {
contentType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "size" field.
public const int SizeFieldNumber = 3;
private ulong size_;
///
/// File size, String size, Multi-part size, etc
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong Size {
get { return size_; }
set {
size_ = value;
}
}
/// Field number for the "seq" field.
public const int SeqFieldNumber = 4;
private ulong seq_;
///
/// Sequence number for multi-part messages
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong Seq {
get { return seq_; }
set {
seq_ = value;
}
}
/// Field number for the "file_name" field.
public const int FileNameFieldNumber = 5;
private string fileName_ = "";
///
/// File metadata
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string FileName {
get { return fileName_; }
set {
fileName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "file_type" field.
public const int FileTypeFieldNumber = 6;
private string fileType_ = "";
///
/// File type (i.e. xml, json, txt, cpp, etc)
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string FileType {
get { return fileType_; }
set {
fileType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "md5" field.
public const int Md5FieldNumber = 7;
private string md5_ = "";
///
/// md5 of data
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Md5 {
get { return md5_; }
set {
md5_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "description" field.
public const int DescriptionFieldNumber = 8;
private string description_ = "";
///
/// Catchalls and future expansion
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Description {
get { return description_; }
set {
description_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 9;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as MetaData);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(MetaData other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (IsMultiPart != other.IsMultiPart) return false;
if (ContentType != other.ContentType) return false;
if (Size != other.Size) return false;
if (Seq != other.Seq) return false;
if (FileName != other.FileName) return false;
if (FileType != other.FileType) return false;
if (Md5 != other.Md5) return false;
if (Description != other.Description) return false;
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (IsMultiPart != false) hash ^= IsMultiPart.GetHashCode();
if (ContentType.Length != 0) hash ^= ContentType.GetHashCode();
if (Size != 0UL) hash ^= Size.GetHashCode();
if (Seq != 0UL) hash ^= Seq.GetHashCode();
if (FileName.Length != 0) hash ^= FileName.GetHashCode();
if (FileType.Length != 0) hash ^= FileType.GetHashCode();
if (Md5.Length != 0) hash ^= Md5.GetHashCode();
if (Description.Length != 0) hash ^= Description.GetHashCode();
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (IsMultiPart != false) {
output.WriteRawTag(8);
output.WriteBool(IsMultiPart);
}
if (ContentType.Length != 0) {
output.WriteRawTag(18);
output.WriteString(ContentType);
}
if (Size != 0UL) {
output.WriteRawTag(24);
output.WriteUInt64(Size);
}
if (Seq != 0UL) {
output.WriteRawTag(32);
output.WriteUInt64(Seq);
}
if (FileName.Length != 0) {
output.WriteRawTag(42);
output.WriteString(FileName);
}
if (FileType.Length != 0) {
output.WriteRawTag(50);
output.WriteString(FileType);
}
if (Md5.Length != 0) {
output.WriteRawTag(58);
output.WriteString(Md5);
}
if (Description.Length != 0) {
output.WriteRawTag(66);
output.WriteString(Description);
}
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (IsMultiPart != false) {
size += 1 + 1;
}
if (ContentType.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(ContentType);
}
if (Size != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Size);
}
if (Seq != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Seq);
}
if (FileName.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(FileName);
}
if (FileType.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(FileType);
}
if (Md5.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Md5);
}
if (Description.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Description);
}
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(MetaData other) {
if (other == null) {
return;
}
if (other.IsMultiPart != false) {
IsMultiPart = other.IsMultiPart;
}
if (other.ContentType.Length != 0) {
ContentType = other.ContentType;
}
if (other.Size != 0UL) {
Size = other.Size;
}
if (other.Seq != 0UL) {
Seq = other.Seq;
}
if (other.FileName.Length != 0) {
FileName = other.FileName;
}
if (other.FileType.Length != 0) {
FileType = other.FileType;
}
if (other.Md5.Length != 0) {
Md5 = other.Md5;
}
if (other.Description.Length != 0) {
Description = other.Description;
}
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
IsMultiPart = input.ReadBool();
break;
}
case 18: {
ContentType = input.ReadString();
break;
}
case 24: {
Size = input.ReadUInt64();
break;
}
case 32: {
Seq = input.ReadUInt64();
break;
}
case 42: {
FileName = input.ReadString();
break;
}
case 50: {
FileType = input.ReadString();
break;
}
case 58: {
Md5 = input.ReadString();
break;
}
case 66: {
Description = input.ReadString();
break;
}
case 74: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
public sealed partial class Metric : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Metric());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Descriptor.NestedTypes[6]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Metric() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Metric(Metric other) : this() {
name_ = other.name_;
alias_ = other.alias_;
timestamp_ = other.timestamp_;
datatype_ = other.datatype_;
isHistorical_ = other.isHistorical_;
isTransient_ = other.isTransient_;
isNull_ = other.isNull_;
Metadata = other.metadata_ != null ? other.Metadata.Clone() : null;
Properties = other.properties_ != null ? other.Properties.Clone() : null;
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.BytesValue:
BytesValue = other.BytesValue;
break;
case ValueOneofCase.DatasetValue:
DatasetValue = other.DatasetValue.Clone();
break;
case ValueOneofCase.TemplateValue:
TemplateValue = other.TemplateValue.Clone();
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue.Clone();
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Metric Clone() {
return new Metric(this);
}
/// Field number for the "name" field.
public const int NameFieldNumber = 1;
private string name_ = "";
///
/// Metric name - should only be included on birth
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Name {
get { return name_; }
set {
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// Field number for the "alias" field.
public const int AliasFieldNumber = 2;
private ulong alias_;
///
/// Metric alias - tied to name on birth and included in all later DATA messages
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong Alias {
get { return alias_; }
set {
alias_ = value;
}
}
/// Field number for the "timestamp" field.
public const int TimestampFieldNumber = 3;
private ulong timestamp_;
///
/// Timestamp associated with data acquisition time
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong Timestamp {
get { return timestamp_; }
set {
timestamp_ = value;
}
}
/// Field number for the "datatype" field.
public const int DatatypeFieldNumber = 4;
private uint datatype_;
///
/// DataType of the metric/tag value
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint Datatype {
get { return datatype_; }
set {
datatype_ = value;
}
}
/// Field number for the "is_historical" field.
public const int IsHistoricalFieldNumber = 5;
private bool isHistorical_;
///
/// If this is historical data and should not update real time tag
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool IsHistorical {
get { return isHistorical_; }
set {
isHistorical_ = value;
}
}
/// Field number for the "is_transient" field.
public const int IsTransientFieldNumber = 6;
private bool isTransient_;
///
/// Tells consuming clients such as MQTT Engine to not store this as a tag
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool IsTransient {
get { return isTransient_; }
set {
isTransient_ = value;
}
}
/// Field number for the "is_null" field.
public const int IsNullFieldNumber = 7;
private bool isNull_;
///
/// If this is null - explicitly say so rather than using -1, false, etc for some datatypes.
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool IsNull {
get { return isNull_; }
set {
isNull_ = value;
}
}
/// Field number for the "metadata" field.
public const int MetadataFieldNumber = 8;
private global::Org.Eclipse.Tahu.Protobuf.Payload.Types.MetaData metadata_;
///
/// Metadata for the payload
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.MetaData Metadata {
get { return metadata_; }
set {
metadata_ = value;
}
}
/// Field number for the "properties" field.
public const int PropertiesFieldNumber = 9;
private global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet properties_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet Properties {
get { return properties_; }
set {
properties_ = value;
}
}
/// Field number for the "int_value" field.
public const int IntValueFieldNumber = 10;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint IntValue {
get { return valueCase_ == ValueOneofCase.IntValue ? (uint) value_ : 0; }
set {
value_ = value;
valueCase_ = ValueOneofCase.IntValue;
}
}
/// Field number for the "long_value" field.
public const int LongValueFieldNumber = 11;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ulong LongValue {
get { return valueCase_ == ValueOneofCase.LongValue ? (ulong) value_ : 0UL; }
set {
value_ = value;
valueCase_ = ValueOneofCase.LongValue;
}
}
/// Field number for the "float_value" field.
public const int FloatValueFieldNumber = 12;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public float FloatValue {
get { return valueCase_ == ValueOneofCase.FloatValue ? (float) value_ : 0F; }
set {
value_ = value;
valueCase_ = ValueOneofCase.FloatValue;
}
}
/// Field number for the "double_value" field.
public const int DoubleValueFieldNumber = 13;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public double DoubleValue {
get { return valueCase_ == ValueOneofCase.DoubleValue ? (double) value_ : 0D; }
set {
value_ = value;
valueCase_ = ValueOneofCase.DoubleValue;
}
}
/// Field number for the "boolean_value" field.
public const int BooleanValueFieldNumber = 14;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool BooleanValue {
get { return valueCase_ == ValueOneofCase.BooleanValue ? (bool) value_ : false; }
set {
value_ = value;
valueCase_ = ValueOneofCase.BooleanValue;
}
}
/// Field number for the "string_value" field.
public const int StringValueFieldNumber = 15;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string StringValue {
get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.StringValue;
}
}
/// Field number for the "bytes_value" field.
public const int BytesValueFieldNumber = 16;
///
/// Bytes, File
///
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pb::ByteString BytesValue {
get { return valueCase_ == ValueOneofCase.BytesValue ? (pb::ByteString) value_ : pb::ByteString.Empty; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.BytesValue;
}
}
/// Field number for the "dataset_value" field.
public const int DatasetValueFieldNumber = 17;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet DatasetValue {
get { return valueCase_ == ValueOneofCase.DatasetValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.DatasetValue;
}
}
/// Field number for the "template_value" field.
public const int TemplateValueFieldNumber = 18;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template TemplateValue {
get { return valueCase_ == ValueOneofCase.TemplateValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.TemplateValue;
}
}
/// Field number for the "extension_value" field.
public const int ExtensionValueFieldNumber = 19;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Types.MetricValueExtension ExtensionValue {
get { return valueCase_ == ValueOneofCase.ExtensionValue ? (global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Types.MetricValueExtension) value_ : null; }
set {
value_ = value;
valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.ExtensionValue;
}
}
private object value_;
/// Enum of possible cases for the "value" oneof.
public enum ValueOneofCase {
None = 0,
IntValue = 10,
LongValue = 11,
FloatValue = 12,
DoubleValue = 13,
BooleanValue = 14,
StringValue = 15,
BytesValue = 16,
DatasetValue = 17,
TemplateValue = 18,
ExtensionValue = 19,
}
private ValueOneofCase valueCase_ = ValueOneofCase.None;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ValueOneofCase ValueCase {
get { return valueCase_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void ClearValue() {
valueCase_ = ValueOneofCase.None;
value_ = null;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Metric);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Metric other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Name != other.Name) return false;
if (Alias != other.Alias) return false;
if (Timestamp != other.Timestamp) return false;
if (Datatype != other.Datatype) return false;
if (IsHistorical != other.IsHistorical) return false;
if (IsTransient != other.IsTransient) return false;
if (IsNull != other.IsNull) return false;
if (!object.Equals(Metadata, other.Metadata)) return false;
if (!object.Equals(Properties, other.Properties)) return false;
if (IntValue != other.IntValue) return false;
if (LongValue != other.LongValue) return false;
if (FloatValue != other.FloatValue) return false;
if (DoubleValue != other.DoubleValue) return false;
if (BooleanValue != other.BooleanValue) return false;
if (StringValue != other.StringValue) return false;
if (BytesValue != other.BytesValue) return false;
if (!object.Equals(DatasetValue, other.DatasetValue)) return false;
if (!object.Equals(TemplateValue, other.TemplateValue)) return false;
if (!object.Equals(ExtensionValue, other.ExtensionValue)) return false;
if (ValueCase != other.ValueCase) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (Alias != 0UL) hash ^= Alias.GetHashCode();
if (Timestamp != 0UL) hash ^= Timestamp.GetHashCode();
if (Datatype != 0) hash ^= Datatype.GetHashCode();
if (IsHistorical != false) hash ^= IsHistorical.GetHashCode();
if (IsTransient != false) hash ^= IsTransient.GetHashCode();
if (IsNull != false) hash ^= IsNull.GetHashCode();
if (metadata_ != null) hash ^= Metadata.GetHashCode();
if (properties_ != null) hash ^= Properties.GetHashCode();
if (valueCase_ == ValueOneofCase.IntValue) hash ^= IntValue.GetHashCode();
if (valueCase_ == ValueOneofCase.LongValue) hash ^= LongValue.GetHashCode();
if (valueCase_ == ValueOneofCase.FloatValue) hash ^= FloatValue.GetHashCode();
if (valueCase_ == ValueOneofCase.DoubleValue) hash ^= DoubleValue.GetHashCode();
if (valueCase_ == ValueOneofCase.BooleanValue) hash ^= BooleanValue.GetHashCode();
if (valueCase_ == ValueOneofCase.StringValue) hash ^= StringValue.GetHashCode();
if (valueCase_ == ValueOneofCase.BytesValue) hash ^= BytesValue.GetHashCode();
if (valueCase_ == ValueOneofCase.DatasetValue) hash ^= DatasetValue.GetHashCode();
if (valueCase_ == ValueOneofCase.TemplateValue) hash ^= TemplateValue.GetHashCode();
if (valueCase_ == ValueOneofCase.ExtensionValue) hash ^= ExtensionValue.GetHashCode();
hash ^= (int) valueCase_;
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Name.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Name);
}
if (Alias != 0UL) {
output.WriteRawTag(16);
output.WriteUInt64(Alias);
}
if (Timestamp != 0UL) {
output.WriteRawTag(24);
output.WriteUInt64(Timestamp);
}
if (Datatype != 0) {
output.WriteRawTag(32);
output.WriteUInt32(Datatype);
}
if (IsHistorical != false) {
output.WriteRawTag(40);
output.WriteBool(IsHistorical);
}
if (IsTransient != false) {
output.WriteRawTag(48);
output.WriteBool(IsTransient);
}
if (IsNull != false) {
output.WriteRawTag(56);
output.WriteBool(IsNull);
}
if (metadata_ != null) {
output.WriteRawTag(66);
output.WriteMessage(Metadata);
}
if (properties_ != null) {
output.WriteRawTag(74);
output.WriteMessage(Properties);
}
if (valueCase_ == ValueOneofCase.IntValue) {
output.WriteRawTag(80);
output.WriteUInt32(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
output.WriteRawTag(88);
output.WriteUInt64(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
output.WriteRawTag(101);
output.WriteFloat(FloatValue);
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
output.WriteRawTag(105);
output.WriteDouble(DoubleValue);
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
output.WriteRawTag(112);
output.WriteBool(BooleanValue);
}
if (valueCase_ == ValueOneofCase.StringValue) {
output.WriteRawTag(122);
output.WriteString(StringValue);
}
if (valueCase_ == ValueOneofCase.BytesValue) {
output.WriteRawTag(130, 1);
output.WriteBytes(BytesValue);
}
if (valueCase_ == ValueOneofCase.DatasetValue) {
output.WriteRawTag(138, 1);
output.WriteMessage(DatasetValue);
}
if (valueCase_ == ValueOneofCase.TemplateValue) {
output.WriteRawTag(146, 1);
output.WriteMessage(TemplateValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
output.WriteRawTag(154, 1);
output.WriteMessage(ExtensionValue);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Name.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
}
if (Alias != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Alias);
}
if (Timestamp != 0UL) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Timestamp);
}
if (Datatype != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Datatype);
}
if (IsHistorical != false) {
size += 1 + 1;
}
if (IsTransient != false) {
size += 1 + 1;
}
if (IsNull != false) {
size += 1 + 1;
}
if (metadata_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Metadata);
}
if (properties_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Properties);
}
if (valueCase_ == ValueOneofCase.IntValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(IntValue);
}
if (valueCase_ == ValueOneofCase.LongValue) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(LongValue);
}
if (valueCase_ == ValueOneofCase.FloatValue) {
size += 1 + 4;
}
if (valueCase_ == ValueOneofCase.DoubleValue) {
size += 1 + 8;
}
if (valueCase_ == ValueOneofCase.BooleanValue) {
size += 1 + 1;
}
if (valueCase_ == ValueOneofCase.StringValue) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
}
if (valueCase_ == ValueOneofCase.BytesValue) {
size += 2 + pb::CodedOutputStream.ComputeBytesSize(BytesValue);
}
if (valueCase_ == ValueOneofCase.DatasetValue) {
size += 2 + pb::CodedOutputStream.ComputeMessageSize(DatasetValue);
}
if (valueCase_ == ValueOneofCase.TemplateValue) {
size += 2 + pb::CodedOutputStream.ComputeMessageSize(TemplateValue);
}
if (valueCase_ == ValueOneofCase.ExtensionValue) {
size += 2 + pb::CodedOutputStream.ComputeMessageSize(ExtensionValue);
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Metric other) {
if (other == null) {
return;
}
if (other.Name.Length != 0) {
Name = other.Name;
}
if (other.Alias != 0UL) {
Alias = other.Alias;
}
if (other.Timestamp != 0UL) {
Timestamp = other.Timestamp;
}
if (other.Datatype != 0) {
Datatype = other.Datatype;
}
if (other.IsHistorical != false) {
IsHistorical = other.IsHistorical;
}
if (other.IsTransient != false) {
IsTransient = other.IsTransient;
}
if (other.IsNull != false) {
IsNull = other.IsNull;
}
if (other.metadata_ != null) {
if (metadata_ == null) {
metadata_ = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.MetaData();
}
Metadata.MergeFrom(other.Metadata);
}
if (other.properties_ != null) {
if (properties_ == null) {
properties_ = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet();
}
Properties.MergeFrom(other.Properties);
}
switch (other.ValueCase) {
case ValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
case ValueOneofCase.LongValue:
LongValue = other.LongValue;
break;
case ValueOneofCase.FloatValue:
FloatValue = other.FloatValue;
break;
case ValueOneofCase.DoubleValue:
DoubleValue = other.DoubleValue;
break;
case ValueOneofCase.BooleanValue:
BooleanValue = other.BooleanValue;
break;
case ValueOneofCase.StringValue:
StringValue = other.StringValue;
break;
case ValueOneofCase.BytesValue:
BytesValue = other.BytesValue;
break;
case ValueOneofCase.DatasetValue:
DatasetValue = other.DatasetValue;
break;
case ValueOneofCase.TemplateValue:
TemplateValue = other.TemplateValue;
break;
case ValueOneofCase.ExtensionValue:
ExtensionValue = other.ExtensionValue;
break;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
break;
}
case 16: {
Alias = input.ReadUInt64();
break;
}
case 24: {
Timestamp = input.ReadUInt64();
break;
}
case 32: {
Datatype = input.ReadUInt32();
break;
}
case 40: {
IsHistorical = input.ReadBool();
break;
}
case 48: {
IsTransient = input.ReadBool();
break;
}
case 56: {
IsNull = input.ReadBool();
break;
}
case 66: {
if (metadata_ == null) {
metadata_ = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.MetaData();
}
input.ReadMessage(metadata_);
break;
}
case 74: {
if (properties_ == null) {
properties_ = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.PropertySet();
}
input.ReadMessage(properties_);
break;
}
case 80: {
IntValue = input.ReadUInt32();
break;
}
case 88: {
LongValue = input.ReadUInt64();
break;
}
case 101: {
FloatValue = input.ReadFloat();
break;
}
case 105: {
DoubleValue = input.ReadDouble();
break;
}
case 112: {
BooleanValue = input.ReadBool();
break;
}
case 122: {
StringValue = input.ReadString();
break;
}
case 130: {
BytesValue = input.ReadBytes();
break;
}
case 138: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.DataSet();
if (valueCase_ == ValueOneofCase.DatasetValue) {
subBuilder.MergeFrom(DatasetValue);
}
input.ReadMessage(subBuilder);
DatasetValue = subBuilder;
break;
}
case 146: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Template();
if (valueCase_ == ValueOneofCase.TemplateValue) {
subBuilder.MergeFrom(TemplateValue);
}
input.ReadMessage(subBuilder);
TemplateValue = subBuilder;
break;
}
case 154: {
global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Types.MetricValueExtension subBuilder = new global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Types.MetricValueExtension();
if (valueCase_ == ValueOneofCase.ExtensionValue) {
subBuilder.MergeFrom(ExtensionValue);
}
input.ReadMessage(subBuilder);
ExtensionValue = subBuilder;
break;
}
}
}
}
#region Nested types
/// Container for nested types declared in the Metric message type.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class MetricValueExtension : pb::IMessage {
private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MetricValueExtension());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::Org.Eclipse.Tahu.Protobuf.Payload.Types.Metric.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public MetricValueExtension() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public MetricValueExtension(MetricValueExtension other) : this() {
details_ = other.details_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public MetricValueExtension Clone() {
return new MetricValueExtension(this);
}
/// Field number for the "details" field.
public const int DetailsFieldNumber = 1;
private static readonly pb::FieldCodec _repeated_details_codec
= pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Any.Parser);
private readonly pbc::RepeatedField details_ = new pbc::RepeatedField();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField Details {
get { return details_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as MetricValueExtension);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(MetricValueExtension other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!details_.Equals(other.details_)) return false;
return true;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= details_.GetHashCode();
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
details_.WriteTo(output, _repeated_details_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += details_.CalculateSize(_repeated_details_codec);
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(MetricValueExtension other) {
if (other == null) {
return;
}
details_.Add(other.details_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
details_.AddEntriesFrom(input, _repeated_details_codec);
break;
}
}
}
}
}
}
#endregion
}
}
#endregion
}
#endregion
}
#endregion Designer generated code
================================================
FILE: edl-v10.html
================================================
Eclipse Distribution License - v 1.0
Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: epl-v20.html
================================================
Eclipse Public License - Version 2.0
Eclipse Public License - v 2.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION
OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
“Contribution” means:
- a) in the case of the initial Contributor, the initial content
Distributed under this Agreement, and
-
b) in the case of each subsequent Contributor:
- i) changes to the Program, and
- ii) additions to the Program;
where such changes and/or additions to the Program originate from
and are Distributed by that particular Contributor. A Contribution
“originates” from a Contributor if it was added to the Program by such
Contributor itself or anyone acting on such Contributor's behalf.
Contributions do not include changes or additions to the Program that
are not Modified Works.
“Contributor” means any person or entity that Distributes the Program.
“Licensed Patents” mean patent claims licensable by a Contributor which
are necessarily infringed by the use or sale of its Contribution alone
or when combined with the Program.
“Program” means the Contributions Distributed in accordance with this
Agreement.
“Recipient” means anyone who receives the Program under this Agreement
or any Secondary License (as applicable), including Contributors.
“Derivative Works” shall mean any work, whether in Source Code or other
form, that is based on (or derived from) the Program and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship.
“Modified Works” shall mean any work in Source Code or other form that
results from an addition to, deletion from, or modification of the
contents of the Program, including, for purposes of clarity any new file
in Source Code form that contains any contents of the Program. Modified
Works shall not include works that contain only declarations, interfaces,
types, classes, structures, or files of the Program solely in each case
in order to link to, bind by name, or subclass the Program or Modified
Works thereof.
“Distribute” means the acts of a) distributing or b) making available
in any manner that enables the transfer of a copy.
“Source Code” means the form of a Program preferred for making
modifications, including but not limited to software source code,
documentation source, and configuration files.
“Secondary License” means either the GNU General Public License,
Version 2.0, or any later versions of that license, including any
exceptions or additional permissions as identified by the initial
Contributor.
2. GRANT OF RIGHTS
- a) Subject to the terms of this Agreement, each Contributor hereby
grants Recipient a non-exclusive, worldwide, royalty-free copyright
license to reproduce, prepare Derivative Works of, publicly display,
publicly perform, Distribute and sublicense the Contribution of such
Contributor, if any, and such Derivative Works.
- b) Subject to the terms of this Agreement, each Contributor hereby
grants Recipient a non-exclusive, worldwide, royalty-free patent
license under Licensed Patents to make, use, sell, offer to sell,
import and otherwise transfer the Contribution of such Contributor,
if any, in Source Code or other form. This patent license shall
apply to the combination of the Contribution and the Program if,
at the time the Contribution is added by the Contributor, such
addition of the Contribution causes such combination to be covered
by the Licensed Patents. The patent license shall not apply to any
other combinations which include the Contribution. No hardware per
se is licensed hereunder.
- c) Recipient understands that although each Contributor grants the
licenses to its Contributions set forth herein, no assurances are
provided by any Contributor that the Program does not infringe the
patent or other intellectual property rights of any other entity.
Each Contributor disclaims any liability to Recipient for claims
brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights
and licenses granted hereunder, each Recipient hereby assumes sole
responsibility to secure any other intellectual property rights needed,
if any. For example, if a third party patent license is required to
allow Recipient to Distribute the Program, it is Recipient's
responsibility to acquire that license before distributing the Program.
- d) Each Contributor represents that to its knowledge it has sufficient
copyright rights in its Contribution, if any, to grant the copyright
license set forth in this Agreement.
- e) Notwithstanding the terms of any Secondary License, no Contributor
makes additional grants to any Recipient (other than those set forth
in this Agreement) as a result of such Recipient's receipt of the
Program under the terms of a Secondary License (if permitted under
the terms of Section 3).
3. REQUIREMENTS
3.1 If a Contributor Distributes the Program in any form, then:
- a) the Program must also be made available as Source Code, in
accordance with section 3.2, and the Contributor must accompany
the Program with a statement that the Source Code for the Program
is available under this Agreement, and informs Recipients how to
obtain it in a reasonable manner on or through a medium customarily
used for software exchange; and
-
b) the Contributor may Distribute the Program under a license
different than this Agreement, provided that such license:
- i) effectively disclaims on behalf of all other Contributors all
warranties and conditions, express and implied, including warranties
or conditions of title and non-infringement, and implied warranties
or conditions of merchantability and fitness for a particular purpose;
- ii) effectively excludes on behalf of all other Contributors all
liability for damages, including direct, indirect, special, incidental
and consequential damages, such as lost profits;
- iii) does not attempt to limit or alter the recipients' rights in the
Source Code under section 3.2; and
- iv) requires any subsequent distribution of the Program by any party
to be under a license that satisfies the requirements of this section 3.
3.2 When the Program is Distributed as Source Code:
- a) it must be made available under this Agreement, or if the Program (i)
is combined with other material in a separate file or files made available
under a Secondary License, and (ii) the initial Contributor attached to
the Source Code the notice described in Exhibit A of this Agreement,
then the Program may be made available under the terms of such
Secondary Licenses, and
- b) a copy of this Agreement must be included with each copy of the Program.
3.3 Contributors may not remove or alter any copyright, patent, trademark,
attribution notices, disclaimers of warranty, or limitations of liability
(‘notices’) contained within the Program from any copy of the Program which
they Distribute, provided that Contributors may add their own appropriate
notices.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities
with respect to end users, business partners and the like. While this
license is intended to facilitate the commercial use of the Program, the
Contributor who includes the Program in a commercial product offering should
do so in a manner which does not create potential liability for other
Contributors. Therefore, if a Contributor includes the Program in a
commercial product offering, such Contributor (“Commercial Contributor”)
hereby agrees to defend and indemnify every other Contributor
(“Indemnified Contributor”) against any losses, damages and costs
(collectively “Losses”) arising from claims, lawsuits and other legal actions
brought by a third party against the Indemnified Contributor to the extent
caused by the acts or omissions of such Commercial Contributor in connection
with its distribution of the Program in a commercial product offering.
The obligations in this section do not apply to any claims or Losses relating
to any actual or alleged intellectual property infringement. In order to
qualify, an Indemnified Contributor must: a) promptly notify the
Commercial Contributor in writing of such claim, and b) allow the Commercial
Contributor to control, and cooperate with the Commercial Contributor in,
the defense and any related settlement negotiations. The Indemnified
Contributor may participate in any such claim at its own expense.
For example, a Contributor might include the Program
in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims
and warranties are such Commercial Contributor's responsibility alone.
Under this section, the Commercial Contributor would have to defend claims
against the other Contributors related to those performance claims and
warranties, and if a court requires any other Contributor to pay any damages
as a result, the Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED
BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
solely responsible for determining the appropriateness of using and
distributing the Program and assumes all risks associated with its
exercise of rights under this Agreement, including but not limited to the
risks and costs of program errors, compliance with applicable laws, damage
to or loss of data, programs or equipment, and unavailability or
interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED
BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY
LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of the
remainder of the terms of this Agreement, and without further action by the
parties hereto, such provision shall be reformed to the minimum extent
necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Program itself
(excluding combinations of the Program with other software or hardware)
infringes such Recipient's patent(s), then such Recipient's rights granted
under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to
comply with any of the material terms or conditions of this Agreement and
does not cure such failure in a reasonable period of time after becoming
aware of such noncompliance. If all Recipient's rights under this Agreement
terminate, Recipient agrees to cease use and distribution of the Program
as soon as reasonably practicable. However, Recipient's obligations under
this Agreement and any licenses granted by Recipient relating to the
Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement,
but in order to avoid inconsistency the Agreement is copyrighted and may
only be modified in the following manner. The Agreement Steward reserves
the right to publish new versions (including revisions) of this Agreement
from time to time. No one other than the Agreement Steward has the right
to modify this Agreement. The Eclipse Foundation is the initial Agreement
Steward. The Eclipse Foundation may assign the responsibility to serve as
the Agreement Steward to a suitable separate entity. Each new version of
the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be Distributed subject to the version
of the Agreement under which it was received. In addition, after a new
version of the Agreement is published, Contributor may elect to Distribute
the Program (including its Contributions) under the new version.
Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
receives no rights or licenses to the intellectual property of any
Contributor under this Agreement, whether expressly, by implication,
estoppel or otherwise. All rights in the Program not expressly granted
under this Agreement are reserved. Nothing in this Agreement is intended
to be enforceable by any entity that is not a Contributor or Recipient.
No third-party beneficiary rights are created under this Agreement.
Exhibit A – Form of Secondary Licenses Notice
“This Source Code may also be made available under the following
Secondary Licenses when the conditions for such availability set forth
in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
version(s), and exceptions or additional permissions here}.”
Simply including a copy of this Agreement, including this Exhibit A
is not sufficient to license the Source Code under Secondary Licenses.
If it is not possible or desirable to put the notice in a particular file,
then You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for
such a notice.
You may add additional accurate notices of copyright ownership.
================================================
FILE: java/.gitignore
================================================
DEPENDENCIES
examples/DEPENDENCIES
================================================
FILE: java/README.md
================================================
# Tahu Java Libraries and Implementations
These are the Java based Eclipse Sparkplug libraries, implementations, and examples.
# Building
From the git root directory run the following commands
```
cd java
mvn clean install
```
# Eclipse Tahu Java Libraries
The Tahu Java implementation provides the following libraries. These can be used for developing custom Java based Sparkplug applications.
* org.eclipse.tahu:tahu-core
* This is the core Sparklplug library to use for modeling, encoding, and decoding of Sparkplug topics and payloads
* org.eclipse.tahu:tahu-edge
* This is the core Sparkplug library to use for implementing Sparkplug Edge Node Applications
* org.eclipse.tahu:tahu-host
* This is the core Sparkplug library to use for implementing Sparkplug Host Applications
# Eclipse Tahu Java Applications
The Tahu Java implementation provides the following Sparkplug compatible implementations. These are complete implementations that fully pass the Eclipse Sparkplug TCK here: https://github.com/eclipse-sparkplug/sparkplug/blob/master/tck/README.md.
* org.eclipse.tahu:tahu-edge-compat
* This is a fully compliant Spark plug Edge Node Application that passes the Sparkplug TCK. It uses the RandomDataSimulator implementation of the DataSimulator interface to initially publish BIRTH messages and then periodically send DATA messages to an MQTT Server.
* To run:
```
java -jar compat_impl/edge/target/tahu-edge-compat-1.0.1-SNAPSHOT.jar
```
* The following config options exist for the Tahu Edge Node in compat_impl/edge/src/main/java/org/eclipse/tahu/edge/SparkplugEdgeNode.java
```
private static final String COMMAND_LISTENER_DIRECTORY = "/tmp/commands";
private static final long COMMAND_LISTENER_POLL_RATE = 50L;
private static final String GROUP_ID = "G1";
private static final String EDGE_NODE_ID = "E1";
private static final EdgeNodeDescriptor EDGE_NODE_DESCRIPTOR = new EdgeNodeDescriptor(GROUP_ID, EDGE_NODE_ID);
private static final List DEVICE_IDS = Arrays.asList("D1");
private static final String PRIMARY_HOST_ID = "IamHost";
private static final boolean USE_ALIASES = true;
private static final Long REBIRTH_DEBOUNCE_DELAY = 5000L;
private static final MqttServerName MQTT_SERVER_NAME_1 = new MqttServerName("Mqtt Server One");
private static final String MQTT_CLIENT_ID_1 = "Sparkplug-Tahu-Compatible-Impl-One";
private static final MqttServerUrl MQTT_SERVER_URL_1 = new MqttServerUrl("tcp://localhost:1883");
private static final String USERNAME_1 = "admin";
private static final String PASSWORD_1 = "changeme";
private static final MqttServerName MQTT_SERVER_NAME_2 = new MqttServerName("Mqtt Server Two");
private static final String MQTT_CLIENT_ID_2 = "Sparkplug-Tahu-Compatible-Impl-Two";
private static final MqttServerUrl MQTT_SERVER_URL_2 = new MqttServerUrl("tcp://localhost:1884");
private static final String USERNAME_2 = "admin";
private static final String PASSWORD_2 = "changeme";
private static final int KEEP_ALIVE_TIMEOUT = 30;
private static final Topic NDEATH_TOPIC = new Topic(SparkplugMeta.SPARKPLUG_B_TOPIC_PREFIX, GROUP_ID, EDGE_NODE_ID, MessageType.NDEATH);
```
* org.eclipse.tahu:tahu-host-compat
* This is a fully compliant Sparkplug Host Application that passes the Sparkplug TCK. It receives BIRTH and DATA messages and logs them to the console. It also handles message reordering and will send 'Node Control/Rebirth' requests in the event of invalid or out of order messages.
* To run:
```
java -jar compat_impl/host/target/tahu-host-compat-1.0.1-SNAPSHOT.jar
```
* The following config options exist for the Tahu Edge Node in compat_impl/host/src/main/java/org/eclipse/tahu/host/SparkplugHostApplication.java
```
private static final String COMMAND_LISTENER_DIRECTORY = "/tmp/commands";
private static final long COMMAND_LISTENER_POLL_RATE = 50L;
private static final String HOST_ID = "IamHost";
private static final String MQTT_SERVER_NAME_1 = "Mqtt Server One";
private static final String MQTT_CLIENT_ID_1 = "Tahu_Host_Application";
private static final String MQTT_SERVER_URL_1 = "tcp://localhost:1883";
private static final String USERNAME_1 = "admin";
private static final String PASSWORD_1 = "changeme";
private static final String MQTT_SERVER_NAME_2 = "Mqtt Server Two";
private static final String MQTT_CLIENT_ID_2 = "Tahu_Host_Application";
private static final String MQTT_SERVER_URL_2 = "tcp://localhost:1884";
private static final String USERNAME_2 = null;
private static final String PASSWORD_2 = null;
private static final int KEEP_ALIVE_TIMEOUT = 30;
```
* The Sparkplug Tahu Host compatible implementation is capable of sending CMD messages to Edge Nodes. This is done using the filesystem and the configuration. By default, the Tahu Host Application looks for files in the '/tmp/commands' directory for files that fit a format to convert into a CMD message. This file location can be changed using the 'COMMAND_LISTENER_DIRECTORY' static variable. If this directory location is left unchanged, the following Linux scripts can used to send CMD messages.
* Send an Edge Node 'Node Control/Rebirth' request
```console
#!/bin/sh
TIMESTAMP=`date +%s`
TIMESTAMP=${TIMESTAMP}000
echo ${TIMESTAMP}
PAYLOAD="{\"topic\":{\"namespace\":\"spBv1.0\",\"edgeNodeDescriptor\":\"G1/E1\",\"groupId\":\"G1\",\"edgeNodeId\":\"E1\",\"type\":\"NCMD\"},\"payload\":{\"timestamp\":"${TIMESTAMP}",\"metrics\":[{\"name\":\"Node Control/Rebirth\",\"timestamp\": "${TIMESTAMP}",\"dataType\":\"Boolean\",\"value\":true}]}}"
echo ${PAYLOAD}
echo ${PAYLOAD} > /tmp/commands/rebirth.json
```
* Send an Edge Node NCMD message
```console
#!/bin/sh
TIMESTAMP=`date +%s`
TIMESTAMP=${TIMESTAMP}000
echo ${TIMESTAMP}
PAYLOAD="{\"topic\":{\"namespace\":\"spBv1.0\",\"edgeNodeDescriptor\":\"G1/E1\",\"groupId\":\"G1\",\"edgeNodeId\":\"E1\",\"type\":\"NCMD\"},\"payload\":{\"timestamp\":"${TIMESTAMP}",\"metrics\":[{\"name\":\"TCK_metric/Boolean\",\"timestamp\": "${TIMESTAMP}",\"dataType\":\"Boolean\",\"value\":true}]}}"
echo ${PAYLOAD}
echo ${PAYLOAD} > /tmp/commands/edge_metric.json
```
* Send an Device Rebirth request message
```console
#!/bin/sh
TIMESTAMP=`date +%s`
TIMESTAMP=${TIMESTAMP}000
echo ${TIMESTAMP}
PAYLOAD="{\"topic\":{\"namespace\":\"spBv1.0\",\"edgeNodeDescriptor\":\"G1/E1\",\"groupId\":\"G1\",\"edgeNodeId\":\"E1\",\"deviceId\":\"D1\",\"type\":\"DCMD\"},\"payload\":{\"timestamp\":"${TIMESTAMP}",\"metrics\":[{\"name\":\"Device Control/Rebirth\",\"timestamp\": "${TIMESTAMP}",\"dataType\":\"Boolean\",\"value\":true}]}}"
echo ${PAYLOAD}
echo ${PAYLOAD} > /tmp/commands/rebirth.json
```
* Send an Device Rebirth request message
```console
#!/bin/sh
TIMESTAMP=`date +%s`
TIMESTAMP=${TIMESTAMP}000
echo ${TIMESTAMP}
PAYLOAD="{\"topic\":{\"namespace\":\"spBv1.0\",\"edgeNodeDescriptor\":\"G1/E1\",\"groupId\":\"G1\",\"edgeNodeId\":\"E1\",\"deviceId\":\"D1\",\"type\":\"DCMD\"},\"payload\":{\"timestamp\":"${TIMESTAMP}",\"metrics\":[{\"name\":\"Inputs/0\",\"timestamp\": "${TIMESTAMP}",\"dataType\":\"Boolean\",\"value\":true}]}}"
echo ${PAYLOAD}
echo ${PAYLOAD} > /tmp/commands/edge_metric.json
```
================================================
FILE: java/compat_impl/edge/pom.xml
================================================
4.0.0
org.eclipse.tahu
tahu
1.0.7
../../pom.xml
tahu-edge-compat
bundle
Tahu Edge Compatible Implementaton
org.eclipse.tahu
tahu-core
${project.version}
org.eclipse.tahu
tahu-edge
${project.version}
org.apache.commons
commons-lang3
3.12.0
javax.xml.bind
jaxb-api
2.3.0
org.sonatype.plugins
nexus-staging-maven-plugin
false
org.codehaus.mojo
license-maven-plugin
1.8
add-third-party
package
add-third-party
download-licenses
true
test
(org.eclipse.tahu*)
The Apache Software License, Version
2.0|Apache License, Version 2.0|Apache Public License
2.0|Apache License 2.0|Apache Software License -
Version 2.0
org.apache.felix
maven-bundle-plugin
${maven.bundle.version}
true
org.eclipse.tahu.*
*;resolution:=optional
bundle-manifest
process-classes
manifest
org.apache.maven.plugins
maven-shade-plugin
3.2.2
false
package
shade
*:*
META-INF/*.SF
META-INF/*.DSA
META-INF/*.RSA
org.eclipse.tahu.edge.SparkplugEdgeNode
${project.version}
${timestamp}
================================================
FILE: java/compat_impl/edge/src/main/java/org/eclipse/tahu/edge/CommandCallback.java
================================================
/********************************************************************************
* Copyright (c) 2022 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
package org.eclipse.tahu.edge;
public interface CommandCallback {
public void setDeviceOffline(String deviceId);
public void setDeviceOnline(String deviceId);
}
================================================
FILE: java/compat_impl/edge/src/main/java/org/eclipse/tahu/edge/CommandListener.java
================================================
/********************************************************************************
* Copyright (c) 2022 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
package org.eclipse.tahu.edge;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
import org.eclipse.tahu.exception.TahuErrorCode;
import org.eclipse.tahu.exception.TahuException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CommandListener implements Runnable {
private static Logger logger = LoggerFactory.getLogger(CommandListener.class.getName());
private static final String SET_DEVICE_OFFLINE = "Set device offline ";
private static final String SET_DEVICE_ONLINE = "Set device online ";
private ScheduledExecutorService executor;
private CommandCallback commandCallback;
private File fileDirectory;
private long scanRate;
public CommandListener(CommandCallback commandCallback, String fileDirectoryPath, long scanRate) {
this.commandCallback = commandCallback;
this.fileDirectory = new File(fileDirectoryPath);
this.scanRate = scanRate;
}
public void start() throws TahuException {
if (!fileDirectory.exists()) {
logger.info("Creating file command listener directory at {}", fileDirectory.getPath());
fileDirectory.mkdirs();
} else if (!fileDirectory.isDirectory()) {
throw new TahuException(TahuErrorCode.INVALID_ARGUMENT, "The specified directory '{}' is not a directory");
}
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleWithFixedDelay(this, 0, scanRate, TimeUnit.MILLISECONDS);
}
public void shutdown() {
executor.shutdownNow();
executor = null;
}
@Override
public void run() {
try {
Set fileNames = Stream.of(fileDirectory.listFiles()).filter(file -> !file.isDirectory())
.map(File::getName).collect(Collectors.toSet());
if (fileNames != null && !fileNames.isEmpty()) {
for (String fileName : fileNames) {
fileName = fileDirectory.getAbsolutePath() + FileSystems.getDefault().getSeparator() + fileName;
logger.info("Found file: {}", fileName);
File commandFile = new File(fileName);
String fileContents = FileUtils.readFileToString(commandFile, StandardCharsets.UTF_8);
if (fileContents != null && fileContents.startsWith(SET_DEVICE_OFFLINE)) {
String deviceId = fileContents.replace(SET_DEVICE_OFFLINE, "");
commandCallback.setDeviceOffline(deviceId);
commandFile.delete();
} else if (fileContents != null && fileContents.startsWith(SET_DEVICE_ONLINE)) {
String deviceId = fileContents.replace(SET_DEVICE_ONLINE, "");
commandCallback.setDeviceOnline(deviceId);
commandFile.delete();
} else {
logger.error("Failed to handle input file {}", fileName);
}
}
}
} catch (Exception e) {
logger.error("File scanning in the Comamnd Worker failed", e);
}
}
}
================================================
FILE: java/compat_impl/edge/src/main/java/org/eclipse/tahu/edge/PeriodicPublisher.java
================================================
/********************************************************************************
* Copyright (c) 2022 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
package org.eclipse.tahu.edge;
import java.util.List;
import org.eclipse.tahu.edge.sim.DataSimulator;
import org.eclipse.tahu.message.model.DeviceDescriptor;
import org.eclipse.tahu.message.model.EdgeNodeDescriptor;
import org.eclipse.tahu.message.model.SparkplugBPayload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PeriodicPublisher implements Runnable {
private static Logger logger = LoggerFactory.getLogger(PeriodicPublisher.class.getName());
private final long period;
private final DataSimulator dataSimulator;
private final EdgeClient edgeClient;
private final EdgeNodeDescriptor edgeNodeDescriptor;
private final List deviceDescriptors;
private volatile boolean stayRunning;
public PeriodicPublisher(long period, DataSimulator dataSimulator, EdgeClient edgeClient,
EdgeNodeDescriptor edgeNodeDescriptor, List deviceDescriptors) {
this.period = period;
this.dataSimulator = dataSimulator;
this.edgeClient = edgeClient;
this.edgeNodeDescriptor = edgeNodeDescriptor;
this.deviceDescriptors = deviceDescriptors;
this.stayRunning = true;
}
@Override
public void run() {
try {
while (stayRunning) {
// Sleep a bit
Thread.sleep(period);
SparkplugBPayload nDataPayload = dataSimulator.getNodeDataPayload(edgeNodeDescriptor);
edgeClient.publishNodeData(nDataPayload);
for (DeviceDescriptor deviceDescriptor : deviceDescriptors) {
SparkplugBPayload dDataPayload = dataSimulator.getDeviceDataPayload(deviceDescriptor);
edgeClient.publishDeviceData(deviceDescriptor.getDeviceId(), dDataPayload);
}
}
} catch (InterruptedException e) {
logger.error("Failed to continue periodic publishing");
}
}
public void shutdown() {
stayRunning = false;
}
}
================================================
FILE: java/compat_impl/edge/src/main/java/org/eclipse/tahu/edge/SparkplugEdgeNode.java
================================================
/********************************************************************************
* Copyright (c) 2022 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
package org.eclipse.tahu.edge;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.tahu.SparkplugInvalidTypeException;
import org.eclipse.tahu.SparkplugParsingException;
import org.eclipse.tahu.edge.api.MetricHandler;
import org.eclipse.tahu.edge.sim.DataSimulator;
import org.eclipse.tahu.edge.sim.RandomDataSimulator;
import org.eclipse.tahu.message.DefaultBdSeqManager;
import org.eclipse.tahu.message.PayloadDecoder;
import org.eclipse.tahu.message.SparkplugBPayloadDecoder;
import org.eclipse.tahu.message.SparkplugBPayloadEncoder;
import org.eclipse.tahu.message.model.DeviceDescriptor;
import org.eclipse.tahu.message.model.EdgeNodeDescriptor;
import org.eclipse.tahu.message.model.MessageType;
import org.eclipse.tahu.message.model.Metric;
import org.eclipse.tahu.message.model.Metric.MetricBuilder;
import org.eclipse.tahu.message.model.MetricDataType;
import org.eclipse.tahu.message.model.SparkplugBPayload;
import org.eclipse.tahu.message.model.SparkplugBPayload.SparkplugBPayloadBuilder;
import org.eclipse.tahu.message.model.SparkplugBPayloadMap;
import org.eclipse.tahu.message.model.SparkplugBPayloadMap.SparkplugBPayloadMapBuilder;
import org.eclipse.tahu.message.model.SparkplugDescriptor;
import org.eclipse.tahu.message.model.SparkplugMeta;
import org.eclipse.tahu.message.model.StatePayload;
import org.eclipse.tahu.message.model.Topic;
import org.eclipse.tahu.model.MqttServerDefinition;
import org.eclipse.tahu.mqtt.ClientCallback;
import org.eclipse.tahu.mqtt.MqttClientId;
import org.eclipse.tahu.mqtt.MqttServerName;
import org.eclipse.tahu.mqtt.MqttServerUrl;
import org.eclipse.tahu.util.SparkplugUtil;
import org.eclipse.tahu.util.TopicUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SparkplugEdgeNode implements Runnable, MetricHandler, ClientCallback, CommandCallback {
private static Logger logger = LoggerFactory.getLogger(SparkplugEdgeNode.class.getName());
private static final String COMMAND_LISTENER_DIRECTORY = "/tmp/commands";
private static final long COMMAND_LISTENER_POLL_RATE = 50L;
private static final String GROUP_ID = "G2";
private static final String EDGE_NODE_ID = "E2";
private static final EdgeNodeDescriptor EDGE_NODE_DESCRIPTOR = new EdgeNodeDescriptor(GROUP_ID, EDGE_NODE_ID);
private static final List DEVICE_IDS = Arrays.asList("D2");
private static final List DEVICE_DESCRIPTORS =
Arrays.asList(new DeviceDescriptor(EDGE_NODE_DESCRIPTOR, "D2"));
private static final String PRIMARY_HOST_ID = "IamHost";
private static final boolean USE_ALIASES = false;
private static final Long REBIRTH_DEBOUNCE_DELAY = 5000L;
private static final MqttServerName MQTT_SERVER_NAME_1 = new MqttServerName("Mqtt Server One");
private static final String MQTT_CLIENT_ID_1 = "Sparkplug-Tahu-Compatible-Impl-One";
private static final MqttServerUrl MQTT_SERVER_URL_1 = MqttServerUrl.getMqttServerUrlSafe("tcp://localhost:1883");
private static final String USERNAME_1 = "admin";
private static final String PASSWORD_1 = "changeme";
private static final MqttServerName MQTT_SERVER_NAME_2 = new MqttServerName("Mqtt Server Two");
private static final String MQTT_CLIENT_ID_2 = "Sparkplug-Tahu-Compatible-Impl-Two";
private static final MqttServerUrl MQTT_SERVER_URL_2 = MqttServerUrl.getMqttServerUrlSafe("tcp://localhost:1884");
private static final String USERNAME_2 = "admin";
private static final String PASSWORD_2 = "changeme";
private static final int KEEP_ALIVE_TIMEOUT = 30;
private static final Topic NDEATH_TOPIC =
new Topic(SparkplugMeta.SPARKPLUG_B_TOPIC_PREFIX, GROUP_ID, EDGE_NODE_ID, MessageType.NDEATH);
private static final List mqttServerDefinitions = new ArrayList<>();
private CommandListener commandListener;
/*
* Next Birth BD sequence number - same as last deathBdSeq
*/
private long birthBdSeq;
/*
* Next Death BD sequence number
*/
private long deathBdSeq;
private final DataSimulator dataSimulator =
new RandomDataSimulator(10, new HashMap() {
private static final long serialVersionUID = 1L;
{
for (DeviceDescriptor deviceDescriptor : DEVICE_DESCRIPTORS) {
put(deviceDescriptor, 50);
}
}
});
/*
* Lock for manipulating the sequence number
*/
private Object clientLock = new Object();
public static void main(String[] arg) {
try {
mqttServerDefinitions
.add(new MqttServerDefinition(MQTT_SERVER_NAME_1, new MqttClientId(MQTT_CLIENT_ID_1, false),
MQTT_SERVER_URL_1, USERNAME_1, PASSWORD_1, KEEP_ALIVE_TIMEOUT, NDEATH_TOPIC));
// mqttServerDefinitions
// .add(new MqttServerDefinition(MQTT_SERVER_NAME_2, new MqttClientId(MQTT_CLIENT_ID_2, false),
// MQTT_SERVER_URL_2, USERNAME_2, PASSWORD_2, KEEP_ALIVE_TIMEOUT, NDEATH_TOPIC));
System.out.println("Starting the Sparkplug Edge Node");
System.out.println("\tGroup ID: " + GROUP_ID);
System.out.println("\tEdge Node ID: " + EDGE_NODE_ID);
System.out.println("\tDevice IDs: " + DEVICE_IDS);
System.out.println("\tPrimary Host ID: " + PRIMARY_HOST_ID);
System.out.println("\tUsing Aliases: " + USE_ALIASES);
System.out.println("\tRebirth Debounce Delay: " + REBIRTH_DEBOUNCE_DELAY);
for (MqttServerDefinition mqttServerDefinition : mqttServerDefinitions) {
System.out.println("\tMQTT Server Name: " + mqttServerDefinition.getMqttServerName());
System.out.println("\tMQTT Client ID: " + mqttServerDefinition.getMqttClientId());
System.out.println("\tMQTT Server URL: " + mqttServerDefinition.getMqttServerUrl());
System.out.println("\tUsername: " + mqttServerDefinition.getUsername());
System.out.println("\tPassword: ********");
System.out.println("\tKeep Alive Timeout: " + mqttServerDefinition.getKeepAliveTimeout());
}
SparkplugEdgeNode sparkplugEdgeNode = new SparkplugEdgeNode();
Thread edgeNodeThread = new Thread(sparkplugEdgeNode);
edgeNodeThread.start();
// Run for a while and shutdown
Thread.sleep(360000);
sparkplugEdgeNode.shutdown();
} catch (Exception e) {
logger.error("Failed to run the Edge Node", e);
}
}
private EdgeClient edgeClient;
private Thread edgeClientThread;
private PeriodicPublisher periodicPublisher;
private DefaultBdSeqManager defaultBdSeqManager;
private Thread periodicPublisherThread;
public SparkplugEdgeNode() {
try {
defaultBdSeqManager = new DefaultBdSeqManager("SparkplugEdgeNode");
deathBdSeq = defaultBdSeqManager.getNextDeathBdSeqNum();
birthBdSeq = deathBdSeq;
edgeClient = new EdgeClient(this, EDGE_NODE_DESCRIPTOR, DEVICE_IDS, PRIMARY_HOST_ID, USE_ALIASES,
REBIRTH_DEBOUNCE_DELAY, mqttServerDefinitions, this, null);
} catch (Exception e) {
logger.error("Failed to create the Sparkplug Edge Client", e);
}
}
@Override
public void run() {
try {
commandListener = new CommandListener(this, COMMAND_LISTENER_DIRECTORY, COMMAND_LISTENER_POLL_RATE);
commandListener.start();
edgeClientThread = new Thread(edgeClient);
edgeClientThread.start();
} catch (Exception e) {
logger.error("Failed to start", e);
}
}
// MetricHandler API
@Override
public Topic getDeathTopic() {
return NDEATH_TOPIC;
}
// MetricHandler API
@Override
public byte[] getDeathPayloadBytes() throws Exception {
SparkplugBPayload nDeathPayload = new SparkplugBPayloadBuilder().setTimestamp(new Date()).createPayload();
addDeathSeqNum(nDeathPayload);
return new SparkplugBPayloadEncoder().getBytes(nDeathPayload, true);
}
// MetricHandler API
@Override
public void publishBirthSequence() {
try {
SparkplugBPayloadMap nBirthPayload = dataSimulator.getNodeBirthPayload(EDGE_NODE_DESCRIPTOR);
nBirthPayload = addBirthSeqNum(nBirthPayload);
edgeClient.publishNodeBirth(nBirthPayload);
for (String deviceId : DEVICE_IDS) {
SparkplugBPayload dBirthPayload =
dataSimulator.getDeviceBirthPayload(new DeviceDescriptor(EDGE_NODE_DESCRIPTOR, deviceId));
edgeClient.publishDeviceBirth(deviceId, dBirthPayload);
}
// The BIRTH sequence has been published - set up a periodic publisher
periodicPublisher =
new PeriodicPublisher(5000, dataSimulator, edgeClient, EDGE_NODE_DESCRIPTOR, DEVICE_DESCRIPTORS);
periodicPublisherThread = new Thread(periodicPublisher);
periodicPublisherThread.start();
} catch (Exception e) {
logger.error("Failed to publish the BIRTH sequence", e);
}
}
// MetricHandler API
@Override
public boolean hasMetric(SparkplugDescriptor sparkplugDescriptor, String metricName) {
return dataSimulator.hasMetric(sparkplugDescriptor, metricName);
}
// ClientCallback API
@Override
public void shutdown() {
logger.info("ClientCallback shutdown");
if (commandListener != null) {
commandListener.shutdown();
commandListener = null;
}
if (periodicPublisher != null) {
periodicPublisher.shutdown();
periodicPublisher = null;
}
if (periodicPublisherThread != null) {
periodicPublisherThread.interrupt();
periodicPublisherThread = null;
}
if (edgeClient != null) {
edgeClient.shutdown();
edgeClient = null;
edgeClientThread = null;
}
}
// ClientCallback API
@Override
public void messageArrived(MqttServerName mqttServerName, MqttServerUrl mqttServerUrl, MqttClientId clientId,
String rawTopic, MqttMessage message) {
logger.info("{}: ClientCallback messageArrived on topic={}", clientId, rawTopic);
final Topic topic;
try {
topic = TopicUtil.parseTopic(rawTopic);
} catch (SparkplugParsingException e) {
logger.error("Error parsing Sparkplug topic {}", rawTopic, e);
return;
}
if (rawTopic.startsWith("spBv1.0/STATE/")) {
try {
logger.info("Got STATE message: {} :: {}", rawTopic, new String(message.getPayload()));
ObjectMapper mapper = new ObjectMapper();
StatePayload statePayload = mapper.readValue(message.getPayload(), StatePayload.class);
edgeClient.handleStateMessage(topic.getHostApplicationId(), statePayload);
} catch (Exception e) {
logger.error("Failed to handle STATE message with topic={} and payload={}", rawTopic,
new String(message.getPayload()));
}
return;
} else if (!SparkplugMeta.SPARKPLUG_B_TOPIC_PREFIX.equals(TopicUtil.getSplitTopic(rawTopic)[0])) {
logger.warn("Message received on erroneous topic: {}", rawTopic);
return;
} else {
// Sparkplug message!
final SparkplugBPayload payload;
try {
// Handling case where the MQTT Server publishes an LWT on our behalf but we're actually online.
if (MessageType.NDEATH.equals(topic.getType()) && topic.getGroupId().equals(GROUP_ID)
&& topic.getEdgeNodeId().equals(EDGE_NODE_ID)) {
if (!edgeClient.isDisconnectedOrDisconnecting()) {
if (edgeClient.isConnectedToPrimaryHost()) {
// Parse out the bdSeq number
payload = new SparkplugBPayloadDecoder().buildFromByteArray(message.getPayload(), null);
// SparkplugUtils.decodePayload(message.getPayload());
long incomingBdSeq = SparkplugUtil.getBdSequenceNumber(payload);
try {
if (birthBdSeq == incomingBdSeq) {
// This is an LWT - but we're online and the bdSeq number matched - correct the
// error by treating it as a rebirth
logger.info("Got unexpected LWT for {} - publishing BIRTH sequence",
EDGE_NODE_DESCRIPTOR);
edgeClient.handleRebirthRequest(true);
}
} catch (Exception e) {
logger.warn("Got unexpected LWT but failed to publish a new BIRTH sequence for {}",
EDGE_NODE_DESCRIPTOR);
}
} else {
logger.debug("Got unexpected LWT but not connected to primary host - ignoring");
}
} else {
logger.debug("Got expected LWT for {}", EDGE_NODE_DESCRIPTOR);
}
return;
}
} catch (Exception e) {
logger.error("Failed to handle NDEATH when connected on {}", topic, e);
return;
}
if (!MessageType.NCMD.equals(topic.getType()) && !MessageType.DCMD.equals(topic.getType())) {
logger.debug("Ignoring unexpected incoming Sparkplug message of type {}", topic.getType());
return;
}
try {
logger.debug("Decoding Sparkplug Payload");
PayloadDecoder decoder = new SparkplugBPayloadDecoder();
payload = decoder.buildFromByteArray(message.getPayload(), null);
logger.debug("Message Timestamp: {}", payload.getTimestamp());
} catch (Exception e) {
logger.error("Failed to parse message - not acting on it", e);
return;
}
if (MessageType.NCMD.equals(topic.getType())) {
try {
final List receivedMetrics = payload.getMetrics();
final List responseMetrics = new ArrayList<>();
if (receivedMetrics != null && !receivedMetrics.isEmpty()) {
// Prep the payload
Date now = new Date();
SparkplugBPayloadMapBuilder payloadBuilder = new SparkplugBPayloadMapBuilder();
payloadBuilder.setTimestamp(now);
// Add the metrics
for (Metric metric : receivedMetrics) {
String name = metric.getName();
logger.debug("Node Metric Name: {}", name);
Object value = metric.getValue();
logger.debug("Metric: {} :: {} :: {}", name, value, metric.getDataType());
if (SparkplugMeta.METRIC_NODE_REBIRTH.equals(name) && value.equals(true)) {
edgeClient.handleRebirthRequest(true);
} else {
Metric writtenMetric = dataSimulator.handleMetricWrite(EDGE_NODE_DESCRIPTOR, metric);
if (writtenMetric != null) {
responseMetrics.add(writtenMetric);
}
}
}
if (!responseMetrics.isEmpty()) {
// Publish the response NDATA message
logger.debug("Publishing NDATA based on NCMD message for {}", EDGE_NODE_DESCRIPTOR);
payloadBuilder.addMetrics(responseMetrics);
edgeClient.publishNodeData(payloadBuilder.createPayload());
} else {
logger.warn("Received NCMD with no valid metrics to write for {}", EDGE_NODE_DESCRIPTOR);
}
}
} catch (Exception e) {
logger.error("Error parsing NCMD", e);
}
} else if (MessageType.DCMD.equals(topic.getType())) {
try {
final List receivedMetrics = payload.getMetrics();
final List responseMetrics = new ArrayList<>();
if (receivedMetrics != null && !receivedMetrics.isEmpty()) {
// Prep the payload
Date now = new Date();
SparkplugBPayloadMapBuilder payloadBuilder = new SparkplugBPayloadMapBuilder();
payloadBuilder.setTimestamp(now);
// Add the metrics
for (Metric metric : receivedMetrics) {
String name = metric.getName();
logger.debug("Device Metric Name: {}", name);
Object value = metric.getValue();
logger.debug("Metric: {} :: {} :: {}", name, value, metric.getDataType());
Metric writtenMetric = dataSimulator.handleMetricWrite(
new DeviceDescriptor(EDGE_NODE_DESCRIPTOR, topic.getDeviceId()), metric);
if (writtenMetric != null) {
responseMetrics.add(writtenMetric);
}
}
if (!responseMetrics.isEmpty()) {
// Publish the response NDATA message
logger.debug("Publishing DDATA based on DCMD message for {}/{}", EDGE_NODE_DESCRIPTOR,
topic.getDeviceId());
payloadBuilder.addMetrics(responseMetrics);
edgeClient.publishDeviceData(topic.getDeviceId(), payloadBuilder.createPayload());
} else {
logger.warn("Received DCMD with no valid metrics to write for {}/{}", EDGE_NODE_DESCRIPTOR,
topic.getDeviceId());
}
}
} catch (Throwable t) {
logger.error("Error parsing DCMD", t);
}
}
}
}
// ClientCallback API
@Override
public void connectionLost(MqttServerName mqttServerName, MqttServerUrl mqttServerUrl, MqttClientId clientId,
Throwable cause) {
logger.info("{}: ClientCallback connectionLost", clientId);
}
// ClientCallback API
@Override
public void connectComplete(boolean reconnect, MqttServerName mqttServerName, MqttServerUrl mqttServerUrl,
MqttClientId clientId) {
logger.info("{}: ClientCallback connectComplete", clientId);
}
// CommandCallback API
@Override
public void setDeviceOffline(String deviceId) {
edgeClient.publishDeviceDeath(deviceId);
}
// CommandCallback API
@Override
public void setDeviceOnline(String deviceId) {
SparkplugBPayload dBirthPayload =
dataSimulator.getDeviceBirthPayload(new DeviceDescriptor(EDGE_NODE_DESCRIPTOR, deviceId));
edgeClient.publishDeviceBirth(deviceId, dBirthPayload);
}
/*
* Used to add the death sequence number
*/
private SparkplugBPayload addDeathSeqNum(SparkplugBPayload payload) {
synchronized (clientLock) {
if (payload == null) {
payload = new SparkplugBPayloadBuilder().createPayload();
}
if (deathBdSeq == 256) {
deathBdSeq = 0;
}
logger.trace("Death bdSeq(before) = {}", deathBdSeq);
try {
logger.trace("Set bdSeq number in NDEATH to {}", deathBdSeq);
payload.addMetric(new MetricBuilder("bdSeq", MetricDataType.Int64, deathBdSeq).createMetric());
// Increment sequence numbers in preparation for the next new connect
birthBdSeq = deathBdSeq;
deathBdSeq++;
defaultBdSeqManager.storeNextDeathBdSeqNum(deathBdSeq);
} catch (SparkplugInvalidTypeException e) {
logger.error("Failed to create death payload", e);
return null;
}
logger.trace("Death bdSeq(after) = {}", deathBdSeq);
return payload;
}
}
/*
* Used to add the birth sequence number
*/
private SparkplugBPayloadMap addBirthSeqNum(SparkplugBPayloadMap nBirthPayload) {
synchronized (clientLock) {
if (nBirthPayload == null) {
nBirthPayload = new SparkplugBPayloadMapBuilder().createPayload();
}
logger.trace("Birth bdSeq(before) = {}", birthBdSeq);
try {
logger.trace("Set bdSeq number in NBIRTH to {}", birthBdSeq);
nBirthPayload.addMetric(new MetricBuilder("bdSeq", MetricDataType.Int64, birthBdSeq).createMetric());
} catch (SparkplugInvalidTypeException e) {
logger.error("Failed to create birth payload", e);
return null;
}
logger.trace("Birth bdSeq(after) = {}", birthBdSeq);
return nBirthPayload;
}
}
}
================================================
FILE: java/compat_impl/edge/src/main/java/org/eclipse/tahu/edge/sim/DataSimulator.java
================================================
/********************************************************************************
* Copyright (c) 2022 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
package org.eclipse.tahu.edge.sim;
import org.eclipse.tahu.message.model.DeviceDescriptor;
import org.eclipse.tahu.message.model.EdgeNodeDescriptor;
import org.eclipse.tahu.message.model.Metric;
import org.eclipse.tahu.message.model.SparkplugBPayload;
import org.eclipse.tahu.message.model.SparkplugBPayloadMap;
import org.eclipse.tahu.message.model.SparkplugDescriptor;
public interface DataSimulator {
/**
* Getting for fetching a NBIRTH {@link SparkplugBPayloadMap}
*
* @param sparkplugDescriptor the {@link EdgeNodeDescriptor} to use when fetching the {@link SparkplugBPayloadMap}
*
* @return a {@link SparkplugBPayloadMap} representing an NBIRTH payload
*/
public SparkplugBPayloadMap getNodeBirthPayload(EdgeNodeDescriptor edgeNodeDescriptor);
/**
* Getting for fetching a NDATA {@link SparkplugBPayload}
*
* @param sparkplugDescriptor the {@link EdgeNodeDescriptor} to use when fetching the {@link SparkplugBPayloadMap}
*
* @return a {@link SparkplugBPayload} representing an NDATA payload
*/
public SparkplugBPayload getNodeDataPayload(EdgeNodeDescriptor edgeNodeDescriptor);
/**
* Getting for fetching a DBIRTH {@link SparkplugBPayload}
*
* @param deviceDescriptor the {@link DeviceDescriptor} to use when fetching the {@link SparkplugBPayload}
*
* @return a {@link SparkplugBPayload} representing an DBIRTH payload
*/
public SparkplugBPayload getDeviceBirthPayload(DeviceDescriptor deviceDescriptor);
/**
* Getting for fetching a DDATA {@link SparkplugBPayload}
*
* @param deviceDescriptor the {@link DeviceDescriptor} to use when fetching the {@link SparkplugBPayload}
*
* @return a {@link SparkplugBPayload} representing an DDATA payload
*/
public SparkplugBPayload getDeviceDataPayload(DeviceDescriptor deviceDescriptor);
/**
*
* @param sparkplugDescriptor
* @param metricName
* @return
*/
public boolean hasMetric(SparkplugDescriptor sparkplugDescriptor, String metricName);
public Metric handleMetricWrite(SparkplugDescriptor sparkplugDescriptor, Metric metric);
}
================================================
FILE: java/compat_impl/edge/src/main/java/org/eclipse/tahu/edge/sim/RandomDataSimulator.java
================================================
/********************************************************************************
* Copyright (c) 2022 Cirrus Link Solutions and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cirrus Link Solutions - initial implementation
********************************************************************************/
package org.eclipse.tahu.edge.sim;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.tahu.SparkplugException;
import org.eclipse.tahu.message.model.DataSet;
import org.eclipse.tahu.message.model.DataSet.DataSetBuilder;
import org.eclipse.tahu.message.model.DataSetDataType;
import org.eclipse.tahu.message.model.DeviceDescriptor;
import org.eclipse.tahu.message.model.EdgeNodeDescriptor;
import org.eclipse.tahu.message.model.File;
import org.eclipse.tahu.message.model.MetaData;
import org.eclipse.tahu.message.model.MetaData.MetaDataBuilder;
import org.eclipse.tahu.message.model.Metric;
import org.eclipse.tahu.message.model.Metric.MetricBuilder;
import org.eclipse.tahu.message.model.MetricDataType;
import org.eclipse.tahu.message.model.Parameter;
import org.eclipse.tahu.message.model.ParameterDataType;
import org.eclipse.tahu.message.model.Row.RowBuilder;
import org.eclipse.tahu.message.model.SparkplugBPayload;
import org.eclipse.tahu.message.model.SparkplugBPayload.SparkplugBPayloadBuilder;
import org.eclipse.tahu.message.model.SparkplugBPayloadMap;
import org.eclipse.tahu.message.model.SparkplugBPayloadMap.SparkplugBPayloadMapBuilder;
import org.eclipse.tahu.message.model.SparkplugDescriptor;
import org.eclipse.tahu.message.model.Template;
import org.eclipse.tahu.message.model.Template.TemplateBuilder;
import org.eclipse.tahu.message.model.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RandomDataSimulator implements DataSimulator {
private static Logger logger = LoggerFactory.getLogger(RandomDataSimulator.class.getName());
private final int numNodeMetrics;
private final Map numDeviceMetrics;
private final Random random = new Random();
private final Map> metricMaps = new HashMap<>();
private final Map lastUpdateMap = new HashMap<>();
public RandomDataSimulator(int numNodeMetrics, Map numDeviceMetrics) {
this.numNodeMetrics = numNodeMetrics;
this.numDeviceMetrics = numDeviceMetrics;
}
// DataSimulator API
@Override
public SparkplugBPayloadMap getNodeBirthPayload(EdgeNodeDescriptor edgeNodeDescriptor) {
try {
Date now = new Date();
Map metricMap = new HashMap<>();
SparkplugBPayloadMapBuilder payloadBuilder = new SparkplugBPayloadMapBuilder();
payloadBuilder.setTimestamp(now);
// Add the Template definitions
payloadBuilder
.addMetric(new MetricBuilder("simpleType", MetricDataType.Template, newSimpleTemplate(true, null))
.createMetric());
payloadBuilder.addMetrics(newComplexTemplateDefs());
// Add some random metrics
for (int i = 0; i < numNodeMetrics; i++) {
Metric metric = getRandomMetric("NT", i, true);
metricMap.put(metric.getName(), metric);
payloadBuilder.addMetric(metric);
}
metricMaps.put(edgeNodeDescriptor, metricMap);
lastUpdateMap.put(edgeNodeDescriptor, now.getTime());
return payloadBuilder.createPayload();
} catch (Exception e) {
logger.error("Failed to get the NBIRTH", e);
return null;
}
}
// DataSimulator API
@Override
public SparkplugBPayload getNodeDataPayload(EdgeNodeDescriptor edgeNodeDescriptor) {
try {
Date now = new Date();
Map metricMap = new HashMap<>();
SparkplugBPayloadBuilder payloadBuilder = new SparkplugBPayloadBuilder();
payloadBuilder.setTimestamp(now);
logger.info("Getting number of metrics for {}", edgeNodeDescriptor);
for (int i = 0; i < numNodeMetrics; i++) {
Metric metric = getRandomMetric("NT", i, true);
if (metric != null) {
metricMap.put(metric.getName(), metric);
payloadBuilder.addMetric(metric);
}
}
metricMaps.put(edgeNodeDescriptor, metricMap);
lastUpdateMap.put(edgeNodeDescriptor, now.getTime());
return payloadBuilder.createPayload();
} catch (Exception e) {
logger.error("Failed to get the NDATA", e);
return null;
}
}
// DataSimulator API
@Override
public SparkplugBPayload getDeviceBirthPayload(DeviceDescriptor deviceDescriptor) {
try {
Date now = new Date();
Map metricMap = new HashMap<>();
SparkplugBPayloadBuilder payloadBuilder = new SparkplugBPayloadBuilder();
payloadBuilder.setTimestamp(now);
logger.info("Getting number of metrics for {}", deviceDescriptor);
for (int i = 0; i < numDeviceMetrics.get(deviceDescriptor); i++) {
Metric metric = getRandomMetric("DT", i, true);
if (metric != null) {
metricMap.put(metric.getName(), metric);
payloadBuilder.addMetric(metric);
}
}
metricMaps.put(deviceDescriptor, metricMap);
lastUpdateMap.put(deviceDescriptor, now.getTime());
return payloadBuilder.createPayload();
} catch (Exception e) {
logger.error("Failed to get the DBIRTH", e);
return null;
}
}
// DataSimulator API
@Override
public SparkplugBPayload getDeviceDataPayload(DeviceDescriptor deviceDescriptor) {
try {
Date now = new Date();
Map metricMap = new HashMap<>();
SparkplugBPayloadBuilder payloadBuilder = new SparkplugBPayloadBuilder();
payloadBuilder.setTimestamp(now);
logger.info("Getting number of metrics for {}", deviceDescriptor);
for (int i = 0; i < numDeviceMetrics.get(deviceDescriptor); i++) {
Metric metric = getRandomMetric("DT", i, true);
if (metric != null) {
metricMap.put(metric.getName(), metric);
payloadBuilder.addMetric(metric);
}
}
metricMaps.put(deviceDescriptor, metricMap);
lastUpdateMap.put(deviceDescriptor, now.getTime());
return payloadBuilder.createPayload();
} catch (Exception e) {
logger.error("Failed to get the DDATA", e);
return null;
}
}
// DataSimulator API
@Override
public boolean hasMetric(SparkplugDescriptor sparkplugDescriptor, String metricName) {
if (metricMaps.containsKey(sparkplugDescriptor)
&& metricMaps.get(sparkplugDescriptor).get(metricName) != null) {
return true;
} else {
return false;
}
}
// DataSimulator API
@Override
public Metric handleMetricWrite(SparkplugDescriptor sparkplugDescriptor, Metric metric) {
// No-op for this simulator - just return the metric as though the value was 'written'
return null;
}
private Metric getRandomMetric(String namePrefix, int index, boolean isBirth) throws Exception {
int remainder = index % 34;
int dataType = remainder + 1;
// These are not valid MetricDataTypes - return an standard Int32
if (dataType == 20 || dataType == 21) {
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int32, getRandomInt32()).createMetric();
}
switch (dataType) {
case 1:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int8, getRandomInt8()).createMetric();
case 2:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int16, getRandomInt16())
.createMetric();
case 3:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int32, getRandomInt32())
.createMetric();
case 4:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int64, getRandomInt64())
.createMetric();
case 5:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt8, getRandomUInt8())
.createMetric();
case 6:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt16, getRandomUInt16())
.createMetric();
case 7:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt32, getRandomUInt32())
.createMetric();
case 8:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt64, getRandomUInt64())
.createMetric();
case 9:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Float, random.nextFloat())
.createMetric();
case 10:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Double, random.nextDouble())
.createMetric();
case 11:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Boolean, random.nextBoolean())
.createMetric();
case 12:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.String, getRandomString(8))
.createMetric();
case 13:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.DateTime, new Date(random.nextLong()))
.createMetric();
case 14:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Text, getRandomString(8))
.createMetric();
case 15:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UUID, UUID.randomUUID().toString())
.createMetric();
case 16:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.DataSet, newDataSet()).createMetric();
case 17:
byte[] byteArray = new byte[10];
random.nextBytes(byteArray);
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Bytes, byteArray).createMetric();
case 18:
byte[] fileDataArray = new byte[10];
random.nextBytes(fileDataArray);
byte[] md5 = MessageDigest.getInstance("MD5").digest(fileDataArray);
String hashString = DatatypeConverter.printHexBinary(md5);
MetaData metaData = new MetaDataBuilder().fileName("Fake_File.bin").md5(hashString).fileType("bin")
.createMetaData();
File file = new File("Fake_File.bin", fileDataArray);
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.File, file).metaData(metaData)
.createMetric();
case 19:
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Template,
newComplexTemplateInstance()).createMetric();
case 22:
Byte[] int8ArrayValue = new Byte[5];
for (int i = 0; i < 5; i++) {
int8ArrayValue[i] = getRandomInt8();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int8Array, int8ArrayValue)
.createMetric();
case 23:
Short[] int16ArrayValue = new Short[5];
for (int i = 0; i < 5; i++) {
int16ArrayValue[i] = getRandomInt16();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int16Array, int16ArrayValue)
.createMetric();
case 24:
Integer[] int32ArrayValue = new Integer[5];
for (int i = 0; i < 5; i++) {
int32ArrayValue[i] = getRandomInt32();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int32Array, int32ArrayValue)
.createMetric();
case 25:
Long[] int64ArrayValue = new Long[5];
for (int i = 0; i < 5; i++) {
int64ArrayValue[i] = getRandomInt64();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.Int64Array, int64ArrayValue)
.createMetric();
case 26:
Short[] uInt8ArrayValue = new Short[5];
for (int i = 0; i < 5; i++) {
uInt8ArrayValue[i] = getRandomUInt8();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt8Array, uInt8ArrayValue)
.createMetric();
case 27:
Integer[] uInt16rrayValue = new Integer[5];
for (int i = 0; i < 5; i++) {
uInt16rrayValue[i] = getRandomUInt16();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt16Array, uInt16rrayValue)
.createMetric();
case 28:
Long[] uInt32ArrayValue = new Long[5];
for (int i = 0; i < 5; i++) {
uInt32ArrayValue[i] = getRandomUInt32();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt32Array, uInt32ArrayValue)
.createMetric();
case 29:
BigInteger[] uInt64ArrayValue = new BigInteger[5];
for (int i = 0; i < 5; i++) {
uInt64ArrayValue[i] = getRandomUInt64();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.UInt64Array, uInt64ArrayValue)
.createMetric();
case 30:
Float[] floatArrayValue = new Float[5];
for (int i = 0; i < 5; i++) {
floatArrayValue[i] = random.nextFloat();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.FloatArray, floatArrayValue)
.createMetric();
case 31:
Double[] doubleArrayValue = new Double[5];
for (int i = 0; i < 5; i++) {
doubleArrayValue[i] = random.nextDouble();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.DoubleArray, doubleArrayValue)
.createMetric();
case 32:
Boolean[] booleanArrayValue = new Boolean[5];
for (int i = 0; i < 5; i++) {
booleanArrayValue[i] = random.nextBoolean();
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.BooleanArray, booleanArrayValue)
.createMetric();
case 33:
String[] stringArrayValue = new String[5];
for (int i = 0; i < 5; i++) {
stringArrayValue[i] = getRandomString(8);
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.StringArray, stringArrayValue)
.createMetric();
case 34:
Date[] dateTimeArrayValue = new Date[5];
for (int i = 0; i < 5; i++) {
dateTimeArrayValue[i] = new Date(getRandomInt64());
}
return new MetricBuilder(namePrefix + "-" + index, MetricDataType.DateTimeArray, dateTimeArrayValue)
.createMetric();
default:
logger.error("Failed to get a metric for dataType {}", dataType);
return null;
}
}
private DataSet newDataSet() throws SparkplugException {
return new DataSetBuilder(14).addColumnName("Int8s").addColumnName("Int16s").addColumnName("Int32s")
.addColumnName("Int64s").addColumnName("UInt8s").addColumnName("UInt16s").addColumnName("UInt32s")
.addColumnName("UInt64s").addColumnName("Floats").addColumnName("Doubles").addColumnName("Booleans")
.addColumnName("Strings").addColumnName("Dates").addColumnName("Texts").addType(DataSetDataType.Int8)
.addType(DataSetDataType.Int16).addType(DataSetDataType.Int32).addType(DataSetDataType.Int64)
.addType(DataSetDataType.UInt8).addType(DataSetDataType.UInt16).addType(DataSetDataType.UInt32)
.addType(DataSetDataType.UInt64).addType(DataSetDataType.Float).addType(DataSetDataType.Double)
.addType(DataSetDataType.Boolean).addType(DataSetDataType.String).addType(DataSetDataType.DateTime)
.addType(DataSetDataType.Text)
.addRow(new RowBuilder().addValue(new Value(DataSetDataType.Int8, getRandomInt8()))
.addValue(new Value(DataSetDataType.Int16, getRandomInt16()))
.addValue(new Value(DataSetDataType.Int32, getRandomInt32()))
.addValue(new Value(DataSetDataType.Int64, getRandomInt64()))
.addValue(new Value(DataSetDataType.UInt8, getRandomUInt8()))
.addValue(new Value(DataSetDataType.UInt16, getRandomUInt16()))
.addValue(new Value(DataSetDataType.UInt32, getRandomUInt32()))
.addValue(new Value(DataSetDataType.UInt64, getRandomUInt64()))
.addValue(new Value(DataSetDataType.Float, random.nextFloat()))
.addValue(new Value(DataSetDataType.Double, random.nextDouble()))
.addValue(new Value(DataSetDataType.Boolean, random.nextBoolean()))
.addValue(new Value(DataSetDataType.String, UUID.randomUUID().toString()))
.addValue(new Value(DataSetDataType.DateTime, new Date()))
.addValue(new Value(DataSetDataType.Text, UUID.randomUUID().toString())).createRow())
.addRow(new RowBuilder().addValue(new Value(DataSetDataType.Int8, getRandomInt8()))
.addValue(new Value(DataSetDataType.Int16, getRandomInt16()))
.addValue(new Value(DataSetDataType.Int32, getRandomInt32()))
.addValue(new Value(DataSetDataType.Int64, getRandomInt64()))
.addValue(new Value(DataSetDataType.UInt8, getRandomUInt8()))
.addValue(new Value(DataSetDataType.UInt16, getRandomUInt16()))
.addValue(new Value(DataSetDataType.UInt32, getRandomUInt32()))
.addValue(new Value(DataSetDataType.UInt64, getRandomUInt64()))
.addValue(new Value(DataSetDataType.Float, random.nextFloat()))
.addValue(new Value(DataSetDataType.Double, random.nextDouble()))
.addValue(new Value(DataSetDataType.Boolean, random.nextBoolean()))
.addValue(new Value(DataSetDataType.String, UUID.randomUUID().toString()))
.addValue(new Value(DataSetDataType.DateTime, new Date()))
.addValue(new Value(DataSetDataType.Text, UUID.randomUUID().toString())).createRow())
.createDataSet();
}
private Template newSimpleTemplate(boolean isDef, String templatRef) throws SparkplugException {
List metrics = new ArrayList();
metrics.add(new MetricBuilder("MyInt8", MetricDataType.Int8, getRandomInt8()).createMetric());
metrics.add(new MetricBuilder("MyInt16", MetricDataType.Int16, getRandomInt16()).createMetric());
metrics.add(new MetricBuilder("MyInt32", MetricDataType.Int32, getRandomInt32()).createMetric());
metrics.add(new MetricBuilder("MyInt64", MetricDataType.Int64, getRandomInt64()).createMetric());
metrics.add(new MetricBuilder("MyUInt8", MetricDataType.UInt8, getRandomUInt8()).createMetric());
metrics.add(new MetricBuilder("MyUInt16", MetricDataType.UInt16, getRandomUInt16()).createMetric());
metrics.add(new MetricBuilder("MyUInt32", MetricDataType.UInt32, getRandomUInt32()).createMetric());
metrics.add(new MetricBuilder("MyUInt64", MetricDataType.UInt64, getRandomUInt64()).createMetric());
metrics.add(new MetricBuilder("MyFloat", MetricDataType.Float, random.nextFloat()).createMetric());
metrics.add(new MetricBuilder("MyDouble", MetricDataType.Double, random.nextDouble()).createMetric());
metrics.add(new MetricBuilder("MyBoolean", MetricDataType.Boolean, random.nextBoolean()).createMetric());
metrics.add(new MetricBuilder("MyString", MetricDataType.String, getRandomString(10)).createMetric());
metrics.add(new MetricBuilder("MyDateTime", MetricDataType.DateTime, new Date()).createMetric());
metrics.add(new MetricBuilder("MyText", MetricDataType.Text, getRandomString(10)).createMetric());
metrics.add(new MetricBuilder("MyUUID", MetricDataType.UUID, UUID.randomUUID().toString()).createMetric());
return new TemplateBuilder().version("v1.0").templateRef(templatRef).definition(isDef)
.addParameters(newParams()).addMetrics(metrics).createTemplate();
}
private List newParams() throws SparkplugException {
Random random = new Random();
List params = new ArrayList();
params.add(new Parameter("ParamInt32", ParameterDataType.Int32, random.nextInt()));
params.add(new Parameter("ParamFloat", ParameterDataType.Float, random.nextFloat()));
params.add(new Parameter("ParamDouble", ParameterDataType.Double, random.nextDouble()));
params.add(new Parameter("ParamBoolean", ParameterDataType.Boolean, random.nextBoolean()));
params.add(new Parameter("ParamString", ParameterDataType.String, UUID.randomUUID().toString()));
return params;
}
private List