18void put_json_str(
pc_sb *b,
const char *s)
21 for (
const char *p = s ? s :
""; *p; p++)
23 if (*p ==
'"' || *p ==
'\\')
25 char esc[3] = {
'\\', *p,
'\0'};
45void put_u64(
pc_sb *b, uint64_t v)
51 tmp[n++] = (char)(
'0' + (
int)(v % 10));
55 for (
int i = 0; i < n; i++)
57 out[i] = tmp[n - 1 - i];
64void put_double(
pc_sb *b,
double v)
72 uint64_t scaled = (uint64_t)(v * 1000.0 + 0.5);
73 uint64_t whole = scaled / 1000;
74 uint32_t frac = (uint32_t)(scaled % 1000);
78 char f[4] = {(char)(
'0' + (frac / 100) % 10), (
char)(
'0' + (frac / 10) % 10), (char)(
'0' + frac % 10),
'\0'};
83size_t pc_openadr_event(
const char *program_id,
const char *event_name,
const OpenAdrInterval *intervals,
size_t count,
84 char *out,
size_t cap)
86 if (!out || (count && !intervals))
90 pc_sb b = {out, cap, 0, cap > 0};
91 pc_sb_put(&b,
"{\"objectType\":\"EVENT\",\"programID\":");
92 put_json_str(&b, program_id);
94 put_json_str(&b, event_name);
96 for (
size_t i = 0; i < count; i++)
104 pc_sb_put(&b,
",\"interval\":{\"start\":");
105 put_u64(&b, intervals[i].start);
107 put_u64(&b, intervals[i].duration);
108 pc_sb_put(&b,
"},\"payloads\":[{\"type\":");
109 put_json_str(&b, intervals[i].type);
111 put_double(&b, intervals[i].value);
118size_t pc_openadr_report(
const char *program_id,
const char *event_id,
const char *resource_name,
double value,
119 uint32_t timestamp,
char *out,
size_t cap)
125 pc_sb b2 = {out, cap, 0, cap > 0};
126 pc_sb_put(&b2,
"{\"objectType\":\"REPORT\",\"programID\":");
127 put_json_str(&b2, program_id);
129 put_json_str(&b2, event_id);
130 pc_sb_put(&b2,
",\"resources\":[{\"resourceName\":");
131 put_json_str(&b2, resource_name);
132 pc_sb_put(&b2,
",\"intervals\":[{\"interval\":{\"start\":");
133 put_u64(&b2, timestamp);
134 pc_sb_put(&b2,
"},\"payloads\":[{\"type\":\"READING\",\"values\":[");
135 put_double(&b2, value);
OpenADR 3.0 (Open Automated Demand Response) JSON codec (PC_ENABLE_OPENADR).
Bounded no-heap string builder that fails closed on overflow (one shared copy).
size_t pc_sb_finish(pc_sb *b)
NUL-terminate and return the built length, or 0 if the build overflowed.
void pc_sb_put(pc_sb *b, const char *s)
Append NUL-terminated s; leaves the buffer untouched and clears ok if it would not fit.
Bump-append target; ok latches false once an append would overflow cap.