11#if PC_ENABLE_SPARKPLUG
17#define SPB_PL_TIMESTAMP 1
18#define SPB_PL_METRICS 2
23#define SPB_MET_ALIAS 2
24#define SPB_MET_TIMESTAMP 3
25#define SPB_MET_DATATYPE 4
27#define SPB_MET_LONG 11
28#define SPB_MET_FLOAT 12
29#define SPB_MET_DOUBLE 13
30#define SPB_MET_BOOL 14
31#define SPB_MET_STRING 15
33size_t pc_spb_build_topic(
char *buf,
size_t cap,
const char *group,
const char *message_type,
const char *edge_node,
36 if (!buf || !group || !message_type || !edge_node)
41 size_t need = 8 + strnlen(group, cap) + 1 + strnlen(message_type, cap) + 1 + strnlen(edge_node, cap);
44 need += 1 + strnlen(device, cap);
51 const char *prefix =
"spBv1.0/";
52 memcpy(buf + p, prefix, 8);
54 size_t n = strnlen(group, cap);
55 memcpy(buf + p, group, n);
58 n = strnlen(message_type, cap);
59 memcpy(buf + p, message_type, n);
62 n = strnlen(edge_node, cap);
63 memcpy(buf + p, edge_node, n);
68 n = strnlen(device, cap);
69 memcpy(buf + p, device, n);
76size_t pc_spb_build_metric(uint8_t *buf,
size_t cap,
const SpbMetric *m)
83 pc_pb_writer_init(&w, buf, cap);
86 pc_pb_string(&w, SPB_MET_NAME, m->name);
90 pc_pb_uint64(&w, SPB_MET_ALIAS, m->alias);
94 pc_pb_uint64(&w, SPB_MET_TIMESTAMP, m->timestamp);
96 pc_pb_uint64(&w, SPB_MET_DATATYPE, m->datatype);
99 case SpbMetricKind::SPB_M_INT:
100 pc_pb_uint64(&w, SPB_MET_INT, m->int_value);
102 case SpbMetricKind::SPB_M_LONG:
103 pc_pb_uint64(&w, SPB_MET_LONG, m->long_value);
105 case SpbMetricKind::SPB_M_FLOAT:
106 pc_pb_float(&w, SPB_MET_FLOAT, m->float_value);
108 case SpbMetricKind::SPB_M_DOUBLE:
109 pc_pb_double(&w, SPB_MET_DOUBLE, m->double_value);
111 case SpbMetricKind::SPB_M_BOOL:
112 pc_pb_bool(&w, SPB_MET_BOOL, m->bool_value);
114 case SpbMetricKind::SPB_M_STRING:
117 pc_pb_string(&w, SPB_MET_STRING, m->string_value);
121 return pc_pb_writer_finish(&w);
124size_t pc_spb_build_payload(uint8_t *buf,
size_t cap, uint64_t timestamp, uint64_t seq,
const SpbMetric *metrics,
127 if (!buf || (n && !metrics))
132 pc_pb_writer_init(&w, buf, cap);
133 pc_pb_uint64(&w, SPB_PL_TIMESTAMP, timestamp);
134 for (
size_t i = 0; i < n; i++)
140 size_t mlen = pc_spb_build_metric(metric,
sizeof(metric), &metrics[i]);
145 pc_pb_bytes(&w, SPB_PL_METRICS, metric, mlen);
147 pc_pb_uint64(&w, SPB_PL_SEQ, seq);
148 return pc_pb_writer_finish(&w);
151bool pc_spb_parse_payload(
const uint8_t *buf,
size_t len, SpbPayloadHeader *out)
157 memset(out, 0,
sizeof(*out));
162 if (!pc_pb_read_field(buf, len, &pos, &f))
166 if (f.field_number == SPB_PL_TIMESTAMP && f.wire_type == PB_WT_VARINT)
168 out->has_timestamp =
true;
169 out->timestamp = f.value;
171 else if (f.field_number == SPB_PL_SEQ && f.wire_type == PB_WT_VARINT)
181bool pc_spb_payload_next_metric(
const uint8_t *buf,
size_t len,
size_t *pos,
const uint8_t **metric,
size_t *metric_len)
183 if (!buf || !pos || !metric || !metric_len)
190 if (!pc_pb_read_field(buf, len, pos, &f))
194 if (f.field_number == SPB_PL_METRICS && f.wire_type == PB_WT_LEN)
205static void spb_apply_meta_field(SpbMetricDecoded *out,
const PbField *f)
207 switch (f->field_number)
210 if (f->wire_type == PB_WT_LEN)
212 out->name = (
const char *)f->data;
213 out->name_len = f->len;
217 if (f->wire_type == PB_WT_VARINT)
219 out->has_alias =
true;
220 out->alias = f->value;
223 case SPB_MET_TIMESTAMP:
224 if (f->wire_type == PB_WT_VARINT)
226 out->has_timestamp =
true;
227 out->timestamp = f->value;
230 case SPB_MET_DATATYPE:
231 if (f->wire_type == PB_WT_VARINT)
233 out->datatype = (uint32_t)f->value;
242static void spb_apply_value_field(SpbMetricDecoded *out,
const PbField *f)
244 switch (f->field_number)
247 if (f->wire_type == PB_WT_VARINT)
249 out->has_value =
true;
250 out->kind = SpbMetricKind::SPB_M_INT;
251 out->int_value = (uint32_t)f->value;
255 if (f->wire_type == PB_WT_VARINT)
257 out->has_value =
true;
258 out->kind = SpbMetricKind::SPB_M_LONG;
259 out->long_value = f->value;
263 if (f->wire_type == PB_WT_I32)
265 out->has_value =
true;
266 out->kind = SpbMetricKind::SPB_M_FLOAT;
267 out->float_value = pc_pb_float_bits((uint32_t)f->value);
271 if (f->wire_type == PB_WT_I64)
273 out->has_value =
true;
274 out->kind = SpbMetricKind::SPB_M_DOUBLE;
275 out->double_value = pc_pb_double_bits(f->value);
279 if (f->wire_type == PB_WT_VARINT)
281 out->has_value =
true;
282 out->kind = SpbMetricKind::SPB_M_BOOL;
283 out->bool_value = f->value != 0;
287 if (f->wire_type == PB_WT_LEN)
289 out->has_value =
true;
290 out->kind = SpbMetricKind::SPB_M_STRING;
291 out->string_value = (
const char *)f->data;
292 out->string_value_len = f->len;
300bool pc_spb_parse_metric(
const uint8_t *buf,
size_t len, SpbMetricDecoded *out)
306 memset(out, 0,
sizeof(*out));
311 if (!pc_pb_read_field(buf, len, &pos, &f))
315 spb_apply_meta_field(out, &f);
316 spb_apply_value_field(out, &f);
Protocol Buffers wire codec (PC_ENABLE_PROTOBUF) - zero-heap streaming writer.
#define PC_SPB_METRIC_MAX
Max serialized size of one Sparkplug B metric submessage (stack temp, bytes).
Sparkplug B payload + topic codec (PC_ENABLE_SPARKPLUG) - zero-heap builder for the Eclipse Sparkplug...