1 /*
2 * Copyright (c) 2025 Linumiz GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "ocpp_i.h"
8 #include "ocpp_j.h"
9 #include <zephyr/data/json.h>
10 #include <zephyr/random/random.h>
11
extract_string_field(char * out_buf,int outlen,char * token)12 static int extract_string_field(char *out_buf, int outlen, char *token)
13 {
14 char *end;
15
16 if (out_buf == NULL || token == NULL) {
17 return -EINVAL;
18 }
19
20 strncpy(out_buf, token + 1, outlen - 1);
21 end = strchr(out_buf, '"');
22 if (end != NULL) {
23 *end = '\0';
24 }
25
26 return 0;
27 }
28
extract_payload(char * msg,int msglen)29 static int extract_payload(char *msg, int msglen)
30 {
31 size_t len;
32 char *start = strchr(msg, '{');
33 char *end = strrchr(msg, '}');
34
35 if (start == NULL || end == NULL || end < start) {
36 return -EINVAL;
37 }
38
39 len = end - start + 1;
40 if (len >= msglen) {
41 return -ENOMEM;
42 }
43
44 memmove(msg, start, len);
45 msg[len] = '\0';
46
47 return 0;
48 }
49
frame_rpc_call_req(char * rpcbuf,int len,int pdu,uint32_t ses,char * pdumsg)50 static int frame_rpc_call_req(char *rpcbuf, int len, int pdu,
51 uint32_t ses, char *pdumsg)
52 {
53 int ret;
54 char uid[JSON_MSG_BUF_128];
55 const char *action;
56 uint32_t rnd = sys_rand32_get();
57
58 snprintk(uid, sizeof(uid), "%u-%d-%u", ses, pdu, rnd);
59
60 action = ocpp_get_pdu_literal(pdu);
61 if (action == NULL) {
62 return -EINVAL;
63 }
64
65 /* Encode OCPP Call Request msg: [2,"<UID>","<Action>",<Payload>] */
66 ret = snprintk(rpcbuf, len,
67 "[2,\"%s\",\"%s\",%s]",
68 uid, action, pdumsg);
69
70 if (ret < 0 || ret >= len) {
71 return -ENOMEM;
72 }
73
74 return 0;
75 }
76
frame_rpc_call_res(char * rpcbuf,int len,char * uid,char * pdumsg)77 static int frame_rpc_call_res(char *rpcbuf, int len,
78 char *uid, char *pdumsg)
79 {
80 int ret;
81
82 /* Encode OCPP Call Result msg: [3,"<UID>",<Payload>] */
83 ret = snprintk(rpcbuf, len, "[3,\"%s\",%s]", uid, pdumsg);
84
85 if (ret < 0 || ret >= len) {
86 return -ENOMEM;
87 }
88
89 return 0;
90 }
91
frame_authorize_msg(char * buf,int len,struct ocpp_session * ses)92 static int frame_authorize_msg(char *buf, int len,
93 struct ocpp_session *ses)
94 {
95 int ret;
96 char auth_obj[JSON_MSG_BUF_128];
97
98 struct json_obj_descr authorize_descr[] = {
99 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "idTag",
100 val1, JSON_TOK_STRING),
101 };
102
103 struct json_common_payload_field_str payload = {
104 .val1 = ses->idtag,
105 };
106
107 ret = json_obj_encode_buf(authorize_descr,
108 ARRAY_SIZE(authorize_descr),
109 &payload,
110 auth_obj,
111 sizeof(auth_obj));
112 if (ret < 0) {
113 return ret;
114 }
115
116 ret = frame_rpc_call_req(buf, len, PDU_AUTHORIZE,
117 (uintptr_t)ses, auth_obj);
118 if (ret < 0) {
119 return ret;
120 }
121
122 return 0;
123 }
124
frame_heartbeat_msg(char * buf,int len,struct ocpp_session * ses)125 static int frame_heartbeat_msg(char *buf, int len, struct ocpp_session *ses)
126 {
127 int ret;
128 char tmp_buf[8] = "{}";
129
130 ret = frame_rpc_call_req(buf, len, PDU_HEARTBEAT,
131 (uintptr_t)ses, tmp_buf);
132 if (ret < 0) {
133 return ret;
134 }
135
136 return 0;
137 }
138
frame_bootnotif_msg(char * buf,int len,struct ocpp_session * ses,struct ocpp_cp_info * cpi)139 static int frame_bootnotif_msg(char *buf, int len,
140 struct ocpp_session *ses,
141 struct ocpp_cp_info *cpi)
142 {
143 int ret;
144 uint8_t descr_count = BOOTNOTIF_MIN_FIELDS;
145 char tmp_buf[JSON_MSG_BUF_512];
146
147 struct json_ocpp_bootnotif_msg msg = {
148 .charge_point_model = cpi->model,
149 .charge_point_vendor = cpi->vendor,
150 .charge_box_serial_number = cpi->box_sl_no ? cpi->box_sl_no : NULL,
151 .charge_point_serial_number = cpi->sl_no ? cpi->sl_no : NULL,
152 .firmware_version = cpi->fw_ver ? cpi->fw_ver : NULL,
153 .iccid = cpi->iccid ? cpi->iccid : NULL,
154 .imsi = cpi->imsi ? cpi->imsi : NULL,
155 .meter_serial_number = cpi->meter_sl_no ? cpi->meter_sl_no : NULL,
156 .meter_type = cpi->meter_type ? cpi->meter_type : NULL,
157 };
158
159 struct json_obj_descr bootnotif_descr[BOOTNOTIF_MAX_FIELDS] = {
160 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointModel",
161 charge_point_model, JSON_TOK_STRING),
162 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointVendor",
163 charge_point_vendor, JSON_TOK_STRING),
164 };
165
166 if (msg.charge_box_serial_number != NULL) {
167 bootnotif_descr[descr_count++] = (struct json_obj_descr)
168 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargeBoxSerialNumber",
169 charge_box_serial_number, JSON_TOK_STRING);
170 }
171
172 if (msg.charge_point_serial_number != NULL) {
173 bootnotif_descr[descr_count++] = (struct json_obj_descr)
174 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointSerialNumber",
175 charge_point_serial_number, JSON_TOK_STRING);
176 }
177
178 if (msg.firmware_version != NULL) {
179 bootnotif_descr[descr_count++] = (struct json_obj_descr)
180 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "firmwareVersion",
181 firmware_version, JSON_TOK_STRING);
182 }
183
184 if (msg.iccid != NULL) {
185 bootnotif_descr[descr_count++] = (struct json_obj_descr)
186 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "iccid",
187 iccid, JSON_TOK_STRING);
188 }
189
190 if (msg.imsi != NULL) {
191 bootnotif_descr[descr_count++] = (struct json_obj_descr)
192 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "imsi",
193 imsi, JSON_TOK_STRING);
194 }
195
196 if (msg.meter_serial_number != NULL) {
197 bootnotif_descr[descr_count++] = (struct json_obj_descr)
198 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "meterSerialNumber",
199 meter_serial_number, JSON_TOK_STRING);
200 }
201
202 if (msg.meter_type != NULL) {
203 bootnotif_descr[descr_count++] = (struct json_obj_descr)
204 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "meterType",
205 meter_type, JSON_TOK_STRING);
206 }
207
208 ret = json_obj_encode_buf(bootnotif_descr, descr_count,
209 &msg, tmp_buf, sizeof(tmp_buf));
210 if (ret < 0) {
211 return ret;
212 }
213
214 ret = frame_rpc_call_req(buf, len, PDU_BOOTNOTIFICATION,
215 (uintptr_t)ses, tmp_buf);
216 if (ret < 0) {
217 return ret;
218 }
219
220 return 0;
221 }
222
frame_meter_val_msg(char * buf,int len,struct ocpp_session * ses,char * timestamp,char * val,char * measurand,char * unit)223 static int frame_meter_val_msg(char *buf, int len, struct ocpp_session *ses, char *timestamp,
224 char *val, char *measurand, char *unit)
225 {
226 int ret;
227 char tmp_buf[JSON_MSG_BUF_512];
228 uint8_t descr_count = SAMPLED_VALUE_MIN_FIELDS;
229
230 struct json_ocpp_meter_val_msg msg = {
231 .connector_id = ses ? ses->idcon : 0,
232 .transaction_id = ses ? ses->idtxn : 0,
233 .meter_value = {{
234 .timestamp = timestamp,
235 .sampled_value = {{
236 .measurand = measurand,
237 .value = val,
238 .unit = unit ? unit : NULL,
239 }},
240 .sampled_value_len = 1,
241 }},
242 .meter_value_len = 1,
243 };
244
245 struct json_obj_descr sampled_value_descr[SAMPLED_VALUE_MAX_FIELDS] = {
246 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "measurand",
247 measurand, JSON_TOK_STRING),
248 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "value",
249 value, JSON_TOK_STRING),
250 };
251
252 if (msg.meter_value[0].sampled_value[0].unit != NULL) {
253 sampled_value_descr[descr_count++] = (struct json_obj_descr)
254 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "unit",
255 unit, JSON_TOK_STRING);
256 }
257
258 struct json_obj_descr meter_value_descr[] = {
259 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val, "timestamp",
260 timestamp, JSON_TOK_STRING),
261 JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_meter_val, "sampledValue",
262 sampled_value, 1, sampled_value_len,
263 sampled_value_descr,
264 descr_count),
265 };
266
267 struct json_obj_descr meter_val_msg_descr[] = {
268 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val_msg, "connectorId",
269 connector_id, JSON_TOK_NUMBER),
270 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val_msg, "transactionId",
271 transaction_id, JSON_TOK_NUMBER),
272 JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_meter_val_msg, "meterValue",
273 meter_value, 1, meter_value_len,
274 meter_value_descr,
275 ARRAY_SIZE(meter_value_descr)),
276 };
277
278 ret = json_obj_encode_buf(meter_val_msg_descr,
279 ARRAY_SIZE(meter_val_msg_descr),
280 &msg, tmp_buf, sizeof(tmp_buf));
281 if (ret < 0) {
282 return ret;
283 }
284
285 ret = frame_rpc_call_req(buf, len, PDU_METER_VALUES,
286 (uintptr_t)ses, tmp_buf);
287 if (ret < 0) {
288 return ret;
289 }
290
291 return 0;
292 }
293
frame_stop_txn_msg(char * buf,int len,struct ocpp_session * ses,int Wh,char * reason,char * timestamp)294 static int frame_stop_txn_msg(char *buf, int len, struct ocpp_session *ses,
295 int Wh, char *reason, char *timestamp)
296 {
297 int ret;
298 char tmp_buf[JSON_MSG_BUF_256];
299 uint8_t descr_count = STOP_TXN_MIN_FIELDS;
300
301 struct json_ocpp_stop_txn_msg msg = {
302 .transaction_id = ses->idtxn,
303 .meter_stop = Wh,
304 .timestamp = timestamp,
305 .reason = reason ? reason : NULL,
306 .id_tag = ses->idtag[0] ? ses->idtag : NULL,
307 };
308
309 struct json_obj_descr descr[STOP_TXN_MAX_FIELDS] = {
310 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "transactionId",
311 transaction_id, JSON_TOK_NUMBER),
312 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "meterStop",
313 meter_stop, JSON_TOK_NUMBER),
314 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "timestamp",
315 timestamp, JSON_TOK_STRING),
316 };
317
318 if (msg.reason != NULL) {
319 descr[descr_count++] = (struct json_obj_descr)
320 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "reason",
321 reason, JSON_TOK_STRING);
322 }
323
324 if (msg.id_tag != NULL) {
325 descr[descr_count++] = (struct json_obj_descr)
326 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "idTag",
327 id_tag, JSON_TOK_STRING);
328 }
329
330 ret = json_obj_encode_buf(descr, descr_count, &msg,
331 tmp_buf, sizeof(tmp_buf));
332 if (ret < 0) {
333 return ret;
334 }
335
336 ret = frame_rpc_call_req(buf, len, PDU_STOP_TRANSACTION,
337 (uintptr_t)ses, tmp_buf);
338 if (ret < 0) {
339 return ret;
340 }
341
342 return 0;
343 }
344
frame_start_txn_msg(char * buf,int len,struct ocpp_session * ses,int Wh,int reserv_id,char * timestamp)345 static int frame_start_txn_msg(char *buf, int len, struct ocpp_session *ses,
346 int Wh, int reserv_id, char *timestamp)
347 {
348 int ret;
349 char tmp_buf[JSON_MSG_BUF_256];
350 uint8_t descr_count = START_TXN_MIN_FIELDS;
351
352 struct json_ocpp_start_txn_msg msg = {
353 .connector_id = ses->idcon,
354 .id_tag = ses->idtag,
355 .meter_start = Wh,
356 .timestamp = timestamp,
357 .reservation_id = (reserv_id >= 0) ? reserv_id : -1,
358 };
359
360 struct json_obj_descr descr[START_TXN_MAX_FIELDS] = {
361 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "connectorId",
362 connector_id, JSON_TOK_NUMBER),
363 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "idTag",
364 id_tag, JSON_TOK_STRING),
365 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "meterStart",
366 meter_start, JSON_TOK_NUMBER),
367 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "timestamp",
368 timestamp, JSON_TOK_STRING),
369 };
370
371 if (msg.reservation_id != -1) {
372 descr[descr_count++] = (struct json_obj_descr)
373 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "reservationId",
374 reservation_id, JSON_TOK_NUMBER);
375 }
376
377 ret = json_obj_encode_buf(descr, descr_count, &msg,
378 tmp_buf, sizeof(tmp_buf));
379 if (ret < 0) {
380 return ret;
381 }
382
383 ret = frame_rpc_call_req(buf, len, PDU_START_TRANSACTION,
384 (uintptr_t)ses, tmp_buf);
385 if (ret < 0) {
386 return ret;
387 }
388
389 return 0;
390 }
391
frame_getconfig_msg(char * buf,int len,char * key,char * val,bool is_rw,char * uid)392 static int frame_getconfig_msg(char *buf, int len, char *key, char *val,
393 bool is_rw, char *uid)
394 {
395 int ret;
396 char tmp_buf[JSON_MSG_BUF_128];
397
398 struct json_ocpp_getconfig_msg msg = { 0 };
399
400 if (val != NULL) {
401 msg.configuration_key[0].key = key;
402 msg.configuration_key[0].readonly = !is_rw;
403 msg.configuration_key[0].value = val;
404 msg.configuration_key_len = 1;
405 } else {
406 msg.unknown_key = key;
407 }
408
409 struct json_obj_descr keyval_descr[] = {
410 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "key",
411 key, JSON_TOK_STRING),
412 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "readonly",
413 readonly, JSON_TOK_NUMBER),
414 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "value",
415 value, JSON_TOK_STRING),
416 };
417
418 struct json_obj_descr config_descr[GET_CFG_MAX_FIELDS] = {
419 JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_getconfig_msg, "configurationKey",
420 configuration_key, 1, configuration_key_len,
421 keyval_descr, ARRAY_SIZE(keyval_descr))
422 };
423
424 if (val == NULL) {
425 config_descr[0] = (struct json_obj_descr)
426 JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_getconfig_msg, "unknownKey",
427 unknown_key, JSON_TOK_STRING);
428 }
429
430 ret = json_obj_encode_buf(config_descr, GET_CFG_MAX_FIELDS, &msg,
431 tmp_buf, sizeof(tmp_buf));
432 if (ret < 0) {
433 return ret;
434 }
435
436 ret = frame_rpc_call_res(buf, len, uid, tmp_buf);
437 if (ret < 0) {
438 return ret;
439 }
440
441 return 0;
442 }
443
frame_status_resp_msg(char * buf,int len,char * res,char * uid)444 static int frame_status_resp_msg(char *buf, int len, char *res, char *uid)
445 {
446 int ret;
447 char tmp_buf[JSON_MSG_BUF_128];
448
449 struct json_obj_descr descr[] = {
450 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "status",
451 val1, JSON_TOK_STRING),
452 };
453
454 struct json_common_payload_field_str msg = {
455 .val1 = res,
456 };
457
458 ret = json_obj_encode_buf(descr, ARRAY_SIZE(descr), &msg,
459 tmp_buf, sizeof(tmp_buf));
460 if (ret < 0) {
461 return ret;
462 }
463
464 ret = frame_rpc_call_res(buf, len, uid, tmp_buf);
465 if (ret < 0) {
466 return ret;
467 }
468
469 return 0;
470 }
471
472 /* parse msg from server */
parse_rpc_msg(char * msg,int msglen,char * uid,int uidlen,int * pdu,bool * is_rsp)473 int parse_rpc_msg(char *msg, int msglen, char *uid, int uidlen,
474 int *pdu, bool *is_rsp)
475 {
476 int ret;
477 char local_buf[JSON_MSG_BUF_512];
478 char action[JSON_MSG_BUF_128];
479 char *token;
480 char *saveptr = NULL;
481 int rpc_id = -1;
482
483 if (msg == NULL || uid == NULL || pdu == NULL || is_rsp == NULL) {
484 return -EINVAL;
485 }
486
487 memcpy(local_buf, msg + 1, sizeof(local_buf) - 1);
488 local_buf[sizeof(local_buf) - 1] = '\0';
489
490 token = strtok_r(local_buf, ",", &saveptr);
491 if (token == NULL) {
492 return -EINVAL;
493 }
494
495 rpc_id = *token - '0';
496
497 token = strtok_r(NULL, ",", &saveptr);
498 if (token == NULL) {
499 return -EINVAL;
500 }
501
502 ret = extract_string_field(uid, uidlen, token);
503 if (ret < 0) {
504 return ret;
505 }
506
507 switch (rpc_id + '0') {
508 case OCPP_WAMP_RPC_REQ:
509 token = strtok_r(NULL, ",", &saveptr);
510 if (token == NULL) {
511 return -EINVAL;
512 }
513
514 ret = extract_string_field(action, sizeof(action), token);
515 if (ret < 0) {
516 return ret;
517 }
518 *pdu = ocpp_find_pdu_from_literal(action);
519 __fallthrough;
520
521 case OCPP_WAMP_RPC_RESP:
522 *is_rsp = rpc_id - 2;
523 ret = extract_payload(msg, msglen);
524 if (ret < 0) {
525 return ret;
526 }
527 break;
528
529 case OCPP_WAMP_RPC_ERR:
530 __fallthrough;
531
532 default:
533 return -EINVAL;
534 }
535
536 return 0;
537 }
538
parse_idtag_info(char * json,struct ocpp_idtag_info * idtag_info)539 static int parse_idtag_info(char *json, struct ocpp_idtag_info *idtag_info)
540 {
541 int ret;
542 char *status;
543
544 struct json_obj_descr inner_descr[] = {
545 JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "status",
546 json_id_tag_info.status, JSON_TOK_STRING),
547 JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "parentIdTag",
548 json_id_tag_info.parent_id_tag, JSON_TOK_STRING),
549 JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "expiryDate",
550 json_id_tag_info.expiry_date, JSON_TOK_STRING),
551 };
552
553 struct json_obj_descr root_descr[] = {
554 JSON_OBJ_DESCR_OBJECT_NAMED(struct json_idtag_info_root, "idTagInfo",
555 json_id_tag_info, inner_descr),
556 };
557
558 struct json_idtag_info_root parsed = { 0 };
559
560 ret = json_obj_parse(json, strlen(json), root_descr,
561 ARRAY_SIZE(root_descr), &parsed);
562 if (ret < 0) {
563 return ret;
564 }
565
566 status = parsed.json_id_tag_info.status;
567 if (status == 0) {
568 return -EINVAL;
569 }
570
571 switch (*status) {
572 case 'A':
573 idtag_info->auth_status = OCPP_AUTH_ACCEPTED;
574 break;
575 case 'B':
576 idtag_info->auth_status = OCPP_AUTH_BLOCKED;
577 break;
578 case 'E':
579 idtag_info->auth_status = OCPP_AUTH_EXPIRED;
580 break;
581 case 'I':
582 idtag_info->auth_status = OCPP_AUTH_INVALID;
583 break;
584 case 'C':
585 idtag_info->auth_status = OCPP_AUTH_CONCURRENT_TX;
586 break;
587 default:
588 return -EINVAL;
589 }
590
591 if (parsed.json_id_tag_info.parent_id_tag != NULL) {
592 strncpy(idtag_info->p_idtag, parsed.json_id_tag_info.parent_id_tag,
593 sizeof(idtag_info->p_idtag));
594 }
595
596 if (parsed.json_id_tag_info.expiry_date != NULL) {
597 strncpy(idtag_info->exptime, parsed.json_id_tag_info.expiry_date,
598 sizeof(idtag_info->exptime));
599 }
600
601 return 0;
602 }
603
parse_heartbeat_msg(char * json,struct timeval * date)604 static int parse_heartbeat_msg(char *json, struct timeval *date)
605 {
606 int ret;
607
608 struct json_obj_descr descr[] = {
609 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "currentTime",
610 val1, JSON_TOK_STRING),
611 };
612
613 struct json_common_payload_field_str heartbeat = {0};
614
615 ret = json_obj_parse(json, strlen(json), descr,
616 ARRAY_SIZE(descr), &heartbeat);
617
618 /* todo: convert civil time to epoch and update local time */
619
620 if (ret < 0) {
621 return ret;
622 }
623
624 return 0;
625 }
626
parse_authorize_msg(char * json,struct ocpp_idtag_info * idtag_info)627 static int parse_authorize_msg(char *json, struct ocpp_idtag_info *idtag_info)
628 {
629 int ret;
630
631 ret = parse_idtag_info(json, idtag_info);
632 if (ret < 0) {
633 return ret;
634 }
635
636 return 0;
637 }
638
parse_bootnotification_msg(char * json,struct boot_notif * binfo)639 static int parse_bootnotification_msg(char *json, struct boot_notif *binfo)
640 {
641 int ret;
642
643 struct json_obj_descr descr[] = {
644 JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "status",
645 status, JSON_TOK_STRING),
646 JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "interval",
647 interval, JSON_TOK_NUMBER),
648 JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "currentTime",
649 current_time, JSON_TOK_STRING),
650 };
651
652 struct json_bootnotif_payload msg = { 0 };
653
654 ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &msg);
655 if (ret < 0) {
656 return ret;
657 }
658
659 if (msg.status == NULL) {
660 return -EINVAL;
661 }
662
663 switch (*msg.status) {
664 case 'A': /* accepted */
665 binfo->status = BOOT_ACCEPTED;
666 break;
667 case 'P': /* pending */
668 binfo->status = BOOT_PENDING;
669 break;
670 case 'R': /* rejected */
671 binfo->status = BOOT_REJECTED;
672 break;
673 default:
674 return -EINVAL;
675 }
676
677 if (msg.interval == 0) {
678 return -EINVAL;
679 }
680
681 binfo->interval = msg.interval;
682
683 if (msg.current_time == NULL) {
684 return -EINVAL;
685 }
686
687 /* todo: convert civil time to epoch and update local time */
688 (void)binfo->date;
689
690 return 0;
691 }
692
parse_start_txn_msg(char * json,int * idtxn,struct ocpp_idtag_info * idtag_info)693 static int parse_start_txn_msg(char *json,
694 int *idtxn,
695 struct ocpp_idtag_info *idtag_info)
696 {
697 int ret;
698
699 struct json_obj_descr descr[] = {
700 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "transactionId",
701 val1, JSON_TOK_NUMBER),
702 };
703
704 struct json_common_payload_field payload = { 0 };
705
706 ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
707 if (ret < 0) {
708 return ret;
709 }
710
711 *idtxn = payload.val1;
712
713 ret = parse_idtag_info(json, idtag_info);
714 if (ret < 0) {
715 return ret;
716 }
717
718 return 0;
719 }
720
parse_getconfig_msg(char * json,char * key)721 static int parse_getconfig_msg(char *json, char *key)
722 {
723 int ret;
724
725 struct json_obj_descr descr[] = {
726 JSON_OBJ_DESCR_ARRAY_NAMED(struct json_getconfig_payload, "key",
727 key, 1, key_len, JSON_TOK_STRING),
728 };
729
730 struct json_getconfig_payload payload = { 0 };
731
732 ret = json_obj_parse(json, strlen(json), descr,
733 ARRAY_SIZE(descr), &payload);
734 if (ret < 0) {
735 return ret;
736 }
737
738 /* key is optional so return success*/
739 if (payload.key[0] != NULL) {
740 strcpy(key, payload.key[0]);
741 }
742
743 return 0;
744 }
745
parse_changeconfig_msg(char * json,char * key,char * val)746 static int parse_changeconfig_msg(char *json, char *key, char *val)
747 {
748 int ret;
749
750 struct json_obj_descr descr[] = {
751 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "key",
752 val1, JSON_TOK_STRING),
753 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "value",
754 val2, JSON_TOK_STRING),
755 };
756
757 struct json_common_payload_field_str payload = { 0 };
758
759 ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
760 if (ret < 0) {
761 return ret;
762 }
763
764 if (payload.val1 == NULL || payload.val2 == NULL) {
765 return -EINVAL;
766 }
767
768 strncpy(key, payload.val1, CISTR50);
769 strncpy(val, payload.val2, CISTR500);
770
771 return 0;
772 }
773
parse_remote_start_txn_msg(char * json,int * idcon,char * idtag)774 static int parse_remote_start_txn_msg(char *json,
775 int *idcon,
776 char *idtag)
777 {
778 int ret;
779
780 struct json_obj_descr descr[] = {
781 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "connectorId",
782 val1, JSON_TOK_NUMBER),
783 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "idTag",
784 val2, JSON_TOK_STRING),
785 };
786
787 struct json_common_payload_field payload = { 0 };
788
789 ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
790 if (ret < 0) {
791 return ret;
792 }
793
794 if (payload.val2 == NULL) {
795 return -EINVAL;
796 }
797
798 strncpy(idtag, payload.val2, CISTR50);
799 *idcon = payload.val1;
800
801 return 0;
802 }
803
parse_remote_stop_txn_msg(char * json,int * idtxn)804 static int parse_remote_stop_txn_msg(char *json, int *idtxn)
805 {
806 int ret;
807
808 struct json_obj_descr descr[] = {
809 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "transactionId",
810 val1, JSON_TOK_NUMBER),
811 };
812
813 struct json_common_payload_field payload = { 0 };
814
815 ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
816 if (ret < 0) {
817 return ret;
818 }
819
820 *idtxn = payload.val1;
821
822 return 0;
823 }
824
parse_unlock_connectormsg(char * json,int * idcon)825 static int parse_unlock_connectormsg(char *json, int *idcon)
826 {
827 int ret;
828
829 struct json_obj_descr descr[] = {
830 JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "connectorId",
831 val1, JSON_TOK_NUMBER),
832 };
833
834 struct json_common_payload_field payload = { 0 };
835
836 ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
837 if (ret < 0) {
838 return ret;
839 }
840
841 if (payload.val1 == 0) {
842 return -EINVAL;
843 }
844
845 *idcon = payload.val1;
846
847 return 0;
848 }
849
850 static ocpp_msg_fp_t ocpp_json_parser[PDU_MSG_END] = {
851 [PDU_BOOTNOTIFICATION] = (ocpp_msg_fp_t)parse_bootnotification_msg,
852 [PDU_AUTHORIZE] = (ocpp_msg_fp_t)parse_authorize_msg,
853 [PDU_START_TRANSACTION] = (ocpp_msg_fp_t)parse_start_txn_msg,
854 [PDU_STOP_TRANSACTION] = (ocpp_msg_fp_t)parse_authorize_msg,
855 [PDU_METER_VALUES] = NULL,
856 [PDU_HEARTBEAT] = (ocpp_msg_fp_t)parse_heartbeat_msg,
857 [PDU_GET_CONFIGURATION] = (ocpp_msg_fp_t)parse_getconfig_msg,
858 [PDU_CHANGE_CONFIGURATION] = (ocpp_msg_fp_t)parse_changeconfig_msg,
859 [PDU_REMOTE_START_TRANSACTION] = (ocpp_msg_fp_t)parse_remote_start_txn_msg,
860 [PDU_REMOTE_STOP_TRANSACTION] = (ocpp_msg_fp_t)parse_remote_stop_txn_msg,
861 [PDU_UNLOCK_CONNECTOR] = (ocpp_msg_fp_t)parse_unlock_connectormsg,
862 };
863
864 static ocpp_msg_fp_t ocpp_json_frame[PDU_MSG_END] = {
865 [PDU_BOOTNOTIFICATION] = (ocpp_msg_fp_t)frame_bootnotif_msg,
866 [PDU_AUTHORIZE] = (ocpp_msg_fp_t)frame_authorize_msg,
867 [PDU_START_TRANSACTION] = (ocpp_msg_fp_t)frame_start_txn_msg,
868 [PDU_STOP_TRANSACTION] = (ocpp_msg_fp_t)frame_stop_txn_msg,
869 [PDU_METER_VALUES] = (ocpp_msg_fp_t)frame_meter_val_msg,
870 [PDU_HEARTBEAT] = (ocpp_msg_fp_t)frame_heartbeat_msg,
871 [PDU_GET_CONFIGURATION] = (ocpp_msg_fp_t)frame_getconfig_msg,
872 [PDU_CHANGE_CONFIGURATION] (ocpp_msg_fp_t)frame_status_resp_msg,
873 [PDU_REMOTE_START_TRANSACTION] = (ocpp_msg_fp_t)frame_status_resp_msg,
874 [PDU_REMOTE_STOP_TRANSACTION] = (ocpp_msg_fp_t)frame_status_resp_msg,
875 [PDU_UNLOCK_CONNECTOR] = (ocpp_msg_fp_t)frame_status_resp_msg,
876 };
877
ocpp_parser_init(ocpp_msg_fp_t ** cfn,ocpp_msg_fp_t ** pfn)878 void ocpp_parser_init(ocpp_msg_fp_t **cfn, ocpp_msg_fp_t **pfn)
879 {
880 *pfn = ocpp_json_parser;
881 *cfn = ocpp_json_frame;
882 }
883