blob: 8521cfeeb40b8088e3aa50a92c86d7823a2002e0 [file] [log] [blame]
/*
* Copyright (c) 2025 Linumiz GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ocpp_i.h"
#include "ocpp_j.h"
#include <zephyr/data/json.h>
#include <zephyr/random/random.h>
static int extract_string_field(char *out_buf, int outlen, char *token)
{
char *end;
if (out_buf == NULL || token == NULL) {
return -EINVAL;
}
strncpy(out_buf, token + 1, outlen - 1);
end = strchr(out_buf, '"');
if (end != NULL) {
*end = '\0';
}
return 0;
}
static int extract_payload(char *msg, int msglen)
{
size_t len;
char *start = strchr(msg, '{');
char *end = strrchr(msg, '}');
if (start == NULL || end == NULL || end < start) {
return -EINVAL;
}
len = end - start + 1;
if (len >= msglen) {
return -ENOMEM;
}
memmove(msg, start, len);
msg[len] = '\0';
return 0;
}
static int frame_rpc_call_req(char *rpcbuf, int len, int pdu,
uint32_t ses, char *pdumsg)
{
int ret;
char uid[JSON_MSG_BUF_128];
const char *action;
uint32_t rnd = sys_rand32_get();
snprintk(uid, sizeof(uid), "%u-%d-%u", ses, pdu, rnd);
action = ocpp_get_pdu_literal(pdu);
if (action == NULL) {
return -EINVAL;
}
/* Encode OCPP Call Request msg: [2,"<UID>","<Action>",<Payload>] */
ret = snprintk(rpcbuf, len,
"[2,\"%s\",\"%s\",%s]",
uid, action, pdumsg);
if (ret < 0 || ret >= len) {
return -ENOMEM;
}
return 0;
}
static int frame_rpc_call_res(char *rpcbuf, int len,
char *uid, char *pdumsg)
{
int ret;
/* Encode OCPP Call Result msg: [3,"<UID>",<Payload>] */
ret = snprintk(rpcbuf, len, "[3,\"%s\",%s]", uid, pdumsg);
if (ret < 0 || ret >= len) {
return -ENOMEM;
}
return 0;
}
static int frame_authorize_msg(char *buf, int len,
struct ocpp_session *ses)
{
int ret;
char auth_obj[JSON_MSG_BUF_128];
struct json_obj_descr authorize_descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "idTag",
val1, JSON_TOK_STRING),
};
struct json_common_payload_field_str payload = {
.val1 = ses->idtag,
};
ret = json_obj_encode_buf(authorize_descr,
ARRAY_SIZE(authorize_descr),
&payload,
auth_obj,
sizeof(auth_obj));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_req(buf, len, PDU_AUTHORIZE,
(uintptr_t)ses, auth_obj);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_heartbeat_msg(char *buf, int len, struct ocpp_session *ses)
{
int ret;
char tmp_buf[8] = "{}";
ret = frame_rpc_call_req(buf, len, PDU_HEARTBEAT,
(uintptr_t)ses, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_bootnotif_msg(char *buf, int len,
struct ocpp_session *ses,
struct ocpp_cp_info *cpi)
{
int ret;
uint8_t descr_count = BOOTNOTIF_MIN_FIELDS;
char tmp_buf[JSON_MSG_BUF_512];
struct json_ocpp_bootnotif_msg msg = {
.charge_point_model = cpi->model,
.charge_point_vendor = cpi->vendor,
.charge_box_serial_number = cpi->box_sl_no ? cpi->box_sl_no : NULL,
.charge_point_serial_number = cpi->sl_no ? cpi->sl_no : NULL,
.firmware_version = cpi->fw_ver ? cpi->fw_ver : NULL,
.iccid = cpi->iccid ? cpi->iccid : NULL,
.imsi = cpi->imsi ? cpi->imsi : NULL,
.meter_serial_number = cpi->meter_sl_no ? cpi->meter_sl_no : NULL,
.meter_type = cpi->meter_type ? cpi->meter_type : NULL,
};
struct json_obj_descr bootnotif_descr[BOOTNOTIF_MAX_FIELDS] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointModel",
charge_point_model, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointVendor",
charge_point_vendor, JSON_TOK_STRING),
};
if (msg.charge_box_serial_number != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargeBoxSerialNumber",
charge_box_serial_number, JSON_TOK_STRING);
}
if (msg.charge_point_serial_number != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointSerialNumber",
charge_point_serial_number, JSON_TOK_STRING);
}
if (msg.firmware_version != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "firmwareVersion",
firmware_version, JSON_TOK_STRING);
}
if (msg.iccid != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "iccid",
iccid, JSON_TOK_STRING);
}
if (msg.imsi != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "imsi",
imsi, JSON_TOK_STRING);
}
if (msg.meter_serial_number != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "meterSerialNumber",
meter_serial_number, JSON_TOK_STRING);
}
if (msg.meter_type != NULL) {
bootnotif_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "meterType",
meter_type, JSON_TOK_STRING);
}
ret = json_obj_encode_buf(bootnotif_descr, descr_count,
&msg, tmp_buf, sizeof(tmp_buf));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_req(buf, len, PDU_BOOTNOTIFICATION,
(uintptr_t)ses, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_meter_val_msg(char *buf, int len, struct ocpp_session *ses, char *timestamp,
char *val, char *measurand, char *unit)
{
int ret;
char tmp_buf[JSON_MSG_BUF_512];
uint8_t descr_count = SAMPLED_VALUE_MIN_FIELDS;
struct json_ocpp_meter_val_msg msg = {
.connector_id = ses ? ses->idcon : 0,
.transaction_id = ses ? ses->idtxn : 0,
.meter_value = {{
.timestamp = timestamp,
.sampled_value = {{
.measurand = measurand,
.value = val,
.unit = unit ? unit : NULL,
}},
.sampled_value_len = 1,
}},
.meter_value_len = 1,
};
struct json_obj_descr sampled_value_descr[SAMPLED_VALUE_MAX_FIELDS] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "measurand",
measurand, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "value",
value, JSON_TOK_STRING),
};
if (msg.meter_value[0].sampled_value[0].unit != NULL) {
sampled_value_descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "unit",
unit, JSON_TOK_STRING);
}
struct json_obj_descr meter_value_descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val, "timestamp",
timestamp, JSON_TOK_STRING),
JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_meter_val, "sampledValue",
sampled_value, 1, sampled_value_len,
sampled_value_descr,
descr_count),
};
struct json_obj_descr meter_val_msg_descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val_msg, "connectorId",
connector_id, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val_msg, "transactionId",
transaction_id, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_meter_val_msg, "meterValue",
meter_value, 1, meter_value_len,
meter_value_descr,
ARRAY_SIZE(meter_value_descr)),
};
ret = json_obj_encode_buf(meter_val_msg_descr,
ARRAY_SIZE(meter_val_msg_descr),
&msg, tmp_buf, sizeof(tmp_buf));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_req(buf, len, PDU_METER_VALUES,
(uintptr_t)ses, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_stop_txn_msg(char *buf, int len, struct ocpp_session *ses,
int Wh, char *reason, char *timestamp)
{
int ret;
char tmp_buf[JSON_MSG_BUF_256];
uint8_t descr_count = STOP_TXN_MIN_FIELDS;
struct json_ocpp_stop_txn_msg msg = {
.transaction_id = ses->idtxn,
.meter_stop = Wh,
.timestamp = timestamp,
.reason = reason ? reason : NULL,
.id_tag = ses->idtag[0] ? ses->idtag : NULL,
};
struct json_obj_descr descr[STOP_TXN_MAX_FIELDS] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "transactionId",
transaction_id, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "meterStop",
meter_stop, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "timestamp",
timestamp, JSON_TOK_STRING),
};
if (msg.reason != NULL) {
descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "reason",
reason, JSON_TOK_STRING);
}
if (msg.id_tag != NULL) {
descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "idTag",
id_tag, JSON_TOK_STRING);
}
ret = json_obj_encode_buf(descr, descr_count, &msg,
tmp_buf, sizeof(tmp_buf));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_req(buf, len, PDU_STOP_TRANSACTION,
(uintptr_t)ses, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_start_txn_msg(char *buf, int len, struct ocpp_session *ses,
int Wh, int reserv_id, char *timestamp)
{
int ret;
char tmp_buf[JSON_MSG_BUF_256];
uint8_t descr_count = START_TXN_MIN_FIELDS;
struct json_ocpp_start_txn_msg msg = {
.connector_id = ses->idcon,
.id_tag = ses->idtag,
.meter_start = Wh,
.timestamp = timestamp,
.reservation_id = (reserv_id >= 0) ? reserv_id : -1,
};
struct json_obj_descr descr[START_TXN_MAX_FIELDS] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "connectorId",
connector_id, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "idTag",
id_tag, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "meterStart",
meter_start, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "timestamp",
timestamp, JSON_TOK_STRING),
};
if (msg.reservation_id != -1) {
descr[descr_count++] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "reservationId",
reservation_id, JSON_TOK_NUMBER);
}
ret = json_obj_encode_buf(descr, descr_count, &msg,
tmp_buf, sizeof(tmp_buf));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_req(buf, len, PDU_START_TRANSACTION,
(uintptr_t)ses, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_getconfig_msg(char *buf, int len, char *key, char *val,
bool is_rw, char *uid)
{
int ret;
char tmp_buf[JSON_MSG_BUF_128];
struct json_ocpp_getconfig_msg msg = { 0 };
if (val != NULL) {
msg.configuration_key[0].key = key;
msg.configuration_key[0].readonly = !is_rw;
msg.configuration_key[0].value = val;
msg.configuration_key_len = 1;
} else {
msg.unknown_key = key;
}
struct json_obj_descr keyval_descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "key",
key, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "readonly",
readonly, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "value",
value, JSON_TOK_STRING),
};
struct json_obj_descr config_descr[GET_CFG_MAX_FIELDS] = {
JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_getconfig_msg, "configurationKey",
configuration_key, 1, configuration_key_len,
keyval_descr, ARRAY_SIZE(keyval_descr))
};
if (val == NULL) {
config_descr[0] = (struct json_obj_descr)
JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_getconfig_msg, "unknownKey",
unknown_key, JSON_TOK_STRING);
}
ret = json_obj_encode_buf(config_descr, GET_CFG_MAX_FIELDS, &msg,
tmp_buf, sizeof(tmp_buf));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_res(buf, len, uid, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
static int frame_status_resp_msg(char *buf, int len, char *res, char *uid)
{
int ret;
char tmp_buf[JSON_MSG_BUF_128];
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "status",
val1, JSON_TOK_STRING),
};
struct json_common_payload_field_str msg = {
.val1 = res,
};
ret = json_obj_encode_buf(descr, ARRAY_SIZE(descr), &msg,
tmp_buf, sizeof(tmp_buf));
if (ret < 0) {
return ret;
}
ret = frame_rpc_call_res(buf, len, uid, tmp_buf);
if (ret < 0) {
return ret;
}
return 0;
}
/* parse msg from server */
int parse_rpc_msg(char *msg, int msglen, char *uid, int uidlen,
int *pdu, bool *is_rsp)
{
int ret;
char local_buf[JSON_MSG_BUF_512];
char action[JSON_MSG_BUF_128];
char *token;
char *saveptr = NULL;
int rpc_id = -1;
if (msg == NULL || uid == NULL || pdu == NULL || is_rsp == NULL) {
return -EINVAL;
}
memcpy(local_buf, msg + 1, sizeof(local_buf) - 1);
local_buf[sizeof(local_buf) - 1] = '\0';
token = strtok_r(local_buf, ",", &saveptr);
if (token == NULL) {
return -EINVAL;
}
rpc_id = *token - '0';
token = strtok_r(NULL, ",", &saveptr);
if (token == NULL) {
return -EINVAL;
}
ret = extract_string_field(uid, uidlen, token);
if (ret < 0) {
return ret;
}
switch (rpc_id + '0') {
case OCPP_WAMP_RPC_REQ:
token = strtok_r(NULL, ",", &saveptr);
if (token == NULL) {
return -EINVAL;
}
ret = extract_string_field(action, sizeof(action), token);
if (ret < 0) {
return ret;
}
*pdu = ocpp_find_pdu_from_literal(action);
__fallthrough;
case OCPP_WAMP_RPC_RESP:
*is_rsp = rpc_id - 2;
ret = extract_payload(msg, msglen);
if (ret < 0) {
return ret;
}
break;
case OCPP_WAMP_RPC_ERR:
__fallthrough;
default:
return -EINVAL;
}
return 0;
}
static int parse_idtag_info(char *json, struct ocpp_idtag_info *idtag_info)
{
int ret;
char *status;
struct json_obj_descr inner_descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "status",
json_id_tag_info.status, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "parentIdTag",
json_id_tag_info.parent_id_tag, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "expiryDate",
json_id_tag_info.expiry_date, JSON_TOK_STRING),
};
struct json_obj_descr root_descr[] = {
JSON_OBJ_DESCR_OBJECT_NAMED(struct json_idtag_info_root, "idTagInfo",
json_id_tag_info, inner_descr),
};
struct json_idtag_info_root parsed = { 0 };
ret = json_obj_parse(json, strlen(json), root_descr,
ARRAY_SIZE(root_descr), &parsed);
if (ret < 0) {
return ret;
}
status = parsed.json_id_tag_info.status;
if (status == 0) {
return -EINVAL;
}
switch (*status) {
case 'A':
idtag_info->auth_status = OCPP_AUTH_ACCEPTED;
break;
case 'B':
idtag_info->auth_status = OCPP_AUTH_BLOCKED;
break;
case 'E':
idtag_info->auth_status = OCPP_AUTH_EXPIRED;
break;
case 'I':
idtag_info->auth_status = OCPP_AUTH_INVALID;
break;
case 'C':
idtag_info->auth_status = OCPP_AUTH_CONCURRENT_TX;
break;
default:
return -EINVAL;
}
if (parsed.json_id_tag_info.parent_id_tag != NULL) {
strncpy(idtag_info->p_idtag, parsed.json_id_tag_info.parent_id_tag,
sizeof(idtag_info->p_idtag));
}
if (parsed.json_id_tag_info.expiry_date != NULL) {
strncpy(idtag_info->exptime, parsed.json_id_tag_info.expiry_date,
sizeof(idtag_info->exptime));
}
return 0;
}
static int parse_heartbeat_msg(char *json, struct timeval *date)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "currentTime",
val1, JSON_TOK_STRING),
};
struct json_common_payload_field_str heartbeat = {0};
ret = json_obj_parse(json, strlen(json), descr,
ARRAY_SIZE(descr), &heartbeat);
/* todo: convert civil time to epoch and update local time */
if (ret < 0) {
return ret;
}
return 0;
}
static int parse_authorize_msg(char *json, struct ocpp_idtag_info *idtag_info)
{
int ret;
ret = parse_idtag_info(json, idtag_info);
if (ret < 0) {
return ret;
}
return 0;
}
static int parse_bootnotification_msg(char *json, struct boot_notif *binfo)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "status",
status, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "interval",
interval, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "currentTime",
current_time, JSON_TOK_STRING),
};
struct json_bootnotif_payload msg = { 0 };
ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &msg);
if (ret < 0) {
return ret;
}
if (msg.status == NULL) {
return -EINVAL;
}
switch (*msg.status) {
case 'A': /* accepted */
binfo->status = BOOT_ACCEPTED;
break;
case 'P': /* pending */
binfo->status = BOOT_PENDING;
break;
case 'R': /* rejected */
binfo->status = BOOT_REJECTED;
break;
default:
return -EINVAL;
}
if (msg.interval == 0) {
return -EINVAL;
}
binfo->interval = msg.interval;
if (msg.current_time == NULL) {
return -EINVAL;
}
/* todo: convert civil time to epoch and update local time */
(void)binfo->date;
return 0;
}
static int parse_start_txn_msg(char *json,
int *idtxn,
struct ocpp_idtag_info *idtag_info)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "transactionId",
val1, JSON_TOK_NUMBER),
};
struct json_common_payload_field payload = { 0 };
ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
if (ret < 0) {
return ret;
}
*idtxn = payload.val1;
ret = parse_idtag_info(json, idtag_info);
if (ret < 0) {
return ret;
}
return 0;
}
static int parse_getconfig_msg(char *json, char *key)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_ARRAY_NAMED(struct json_getconfig_payload, "key",
key, 1, key_len, JSON_TOK_STRING),
};
struct json_getconfig_payload payload = { 0 };
ret = json_obj_parse(json, strlen(json), descr,
ARRAY_SIZE(descr), &payload);
if (ret < 0) {
return ret;
}
/* key is optional so return success*/
if (payload.key[0] != NULL) {
strcpy(key, payload.key[0]);
}
return 0;
}
static int parse_changeconfig_msg(char *json, char *key, char *val)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "key",
val1, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "value",
val2, JSON_TOK_STRING),
};
struct json_common_payload_field_str payload = { 0 };
ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
if (ret < 0) {
return ret;
}
if (payload.val1 == NULL || payload.val2 == NULL) {
return -EINVAL;
}
strncpy(key, payload.val1, CISTR50);
strncpy(val, payload.val2, CISTR500);
return 0;
}
static int parse_remote_start_txn_msg(char *json,
int *idcon,
char *idtag)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "connectorId",
val1, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "idTag",
val2, JSON_TOK_STRING),
};
struct json_common_payload_field payload = { 0 };
ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
if (ret < 0) {
return ret;
}
if (payload.val2 == NULL) {
return -EINVAL;
}
strncpy(idtag, payload.val2, CISTR50);
*idcon = payload.val1;
return 0;
}
static int parse_remote_stop_txn_msg(char *json, int *idtxn)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "transactionId",
val1, JSON_TOK_NUMBER),
};
struct json_common_payload_field payload = { 0 };
ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
if (ret < 0) {
return ret;
}
*idtxn = payload.val1;
return 0;
}
static int parse_unlock_connectormsg(char *json, int *idcon)
{
int ret;
struct json_obj_descr descr[] = {
JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "connectorId",
val1, JSON_TOK_NUMBER),
};
struct json_common_payload_field payload = { 0 };
ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
if (ret < 0) {
return ret;
}
if (payload.val1 == 0) {
return -EINVAL;
}
*idcon = payload.val1;
return 0;
}
static ocpp_msg_fp_t ocpp_json_parser[PDU_MSG_END] = {
[PDU_BOOTNOTIFICATION] = (ocpp_msg_fp_t)parse_bootnotification_msg,
[PDU_AUTHORIZE] = (ocpp_msg_fp_t)parse_authorize_msg,
[PDU_START_TRANSACTION] = (ocpp_msg_fp_t)parse_start_txn_msg,
[PDU_STOP_TRANSACTION] = (ocpp_msg_fp_t)parse_authorize_msg,
[PDU_METER_VALUES] = NULL,
[PDU_HEARTBEAT] = (ocpp_msg_fp_t)parse_heartbeat_msg,
[PDU_GET_CONFIGURATION] = (ocpp_msg_fp_t)parse_getconfig_msg,
[PDU_CHANGE_CONFIGURATION] = (ocpp_msg_fp_t)parse_changeconfig_msg,
[PDU_REMOTE_START_TRANSACTION] = (ocpp_msg_fp_t)parse_remote_start_txn_msg,
[PDU_REMOTE_STOP_TRANSACTION] = (ocpp_msg_fp_t)parse_remote_stop_txn_msg,
[PDU_UNLOCK_CONNECTOR] = (ocpp_msg_fp_t)parse_unlock_connectormsg,
};
static ocpp_msg_fp_t ocpp_json_frame[PDU_MSG_END] = {
[PDU_BOOTNOTIFICATION] = (ocpp_msg_fp_t)frame_bootnotif_msg,
[PDU_AUTHORIZE] = (ocpp_msg_fp_t)frame_authorize_msg,
[PDU_START_TRANSACTION] = (ocpp_msg_fp_t)frame_start_txn_msg,
[PDU_STOP_TRANSACTION] = (ocpp_msg_fp_t)frame_stop_txn_msg,
[PDU_METER_VALUES] = (ocpp_msg_fp_t)frame_meter_val_msg,
[PDU_HEARTBEAT] = (ocpp_msg_fp_t)frame_heartbeat_msg,
[PDU_GET_CONFIGURATION] = (ocpp_msg_fp_t)frame_getconfig_msg,
[PDU_CHANGE_CONFIGURATION] (ocpp_msg_fp_t)frame_status_resp_msg,
[PDU_REMOTE_START_TRANSACTION] = (ocpp_msg_fp_t)frame_status_resp_msg,
[PDU_REMOTE_STOP_TRANSACTION] = (ocpp_msg_fp_t)frame_status_resp_msg,
[PDU_UNLOCK_CONNECTOR] = (ocpp_msg_fp_t)frame_status_resp_msg,
};
void ocpp_parser_init(ocpp_msg_fp_t **cfn, ocpp_msg_fp_t **pfn)
{
*pfn = ocpp_json_parser;
*cfn = ocpp_json_frame;
}