#include "v2g_context.h"
#include "openssl_utils.h"
#include "hmac_sha256.h"
#include "sha256_help.h"

static const uint16_t SAE_V2H = 28472;
static const uint16_t SAE_V2G = 28473;

struct iso_state {
    const char* description;
    int allowed_requests;
};

enum iso_ac_state_id {
    WAIT_FOR_AC_SESSIONSETUP = 0,
    WAIT_FOR_AC_SERVICEDISCOVERY,
    WAIT_FOR_AC_SVCDETAIL_PAYMENTSVCSEL,
    WAIT_FOR_AC_PAYMENTDETAILS_CERTINST_CERTUPD,
    WAIT_FOR_AC_PAYMENTDETAILS,
    WAIT_FOR_AC_AUTHORIZATION,
    WAIT_FOR_AC_CHARGEPARAMETERDISCOVERY,
    WAIT_FOR_AC_POWERDELIVERY,
    WAIT_FOR_AC_CHARGINGSTATUS,
    WAIT_FOR_AC_CHARGINGSTATUS_POWERDELIVERY,
    WAIT_FOR_AC_METERINGRECEIPT,
    WAIT_FOR_AC_SESSIONSTOP,
    WAIT_FOR_AC_TERMINATED_SESSION
};

enum iso_dc_state_id {
    WAIT_FOR_SESSIONSETUP = 0,
    WAIT_FOR_SERVICEDISCOVERY,
    WAIT_FOR_SVCDETAIL_PAYMENTSVCSEL,
    WAIT_FOR_PAYMENTDETAILS_CERTINST_CERTUPD,
    WAIT_FOR_PAYMENTDETAILS,
    WAIT_FOR_AUTHORIZATION,
    WAIT_FOR_CHARGEPARAMETERDISCOVERY,
    WAIT_FOR_CABLECHECK,
    WAIT_FOR_PRECHARGE,
    WAIT_FOR_PRECHARGE_POWERDELIVERY,
    WAIT_FOR_CURRENTDEMAND_POWERDELIVERY,
    WAIT_FOR_CURRENTDEMAND,
    WAIT_FOR_METERINGRECEIPT,
    WAIT_FOR_WELDINGDETECTION_SESSIONSTOP,
    WAIT_FOR_TERMINATED_SESSION
};

static const char* isoResponse[] = {
    "Response OK",
    "New Session Established",
    "Old Session Joined",
    "Certificate Expires Soon",
    "Response FAILED",
    "Sequence Error",
    "Service ID Invalid",
    "Unknown Session",
    "Service Selection Invalid",
    "Payment Selection Invalid",
    "Certificate Expired",
    "Signature Error",
    "No Certificate Available",
    "Cert Chain Error",
    "Challenge Invalid",
    "Contract Canceled",
    "Wrong Charge Parameter",
    "Power Delivery Not Applied",
    "Tariff Selection Invalid",
    "Charging Profile Invalid",
    "Metering Signature Not Valid",
    "No Charge Service Selected",
    "Wrong Energy Transfer Mode",
    "Contactor Error",
    "Certificate Not Allowed At This EVSE",
    "Certificate Revoked",
};

static const struct iso_state iso_dc_states[] = {
    /* [V2G-541] Expected req msg after SupportedAppProtocolRes */
    {"Waiting for SessionSetupReq", 1 << V2G_SESSION_SETUP_MSG},
    /* [V2G-543] Expected req msg after SessionSetupRes */
    {"Waiting for ServiceDiscoveryReq, SessionStopReq", 1 << V2G_SERVICE_DISCOVERY_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-545] Expected req msg after ServiceDiscoveryRes */
    {"Waiting for ServiceDetailReq, ServicePaymentSelectionReq, SessionStopReq", 1 << V2G_SERVICE_DETAIL_MSG | 1 << V2G_PAYMENT_SERVICE_SELECTION_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-551] Expected req msg after ServicePaymentSelectionRes */
    {"Waiting for PaymentDetailsReq, AuthorizationReq, CertificateInstallationReq, CertificateUpdateReq, SessionStopReq", 1 << V2G_PAYMENT_DETAILS_MSG | 1 << V2G_AUTHORIZATION_MSG | 1 << V2G_CERTIFICATE_INSTALLATION_MSG | 1 << V2G_CERTIFICATE_UPDATE_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-557], [V2G-554], [V2G-558] Expected req msg after CertificateInstallationRes or CertificateUpdateRes */
    {"Waiting for PaymentDetailsReq, SessionStopReq", 1 << V2G_PAYMENT_DETAILS_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-560], [V2G-687] Expected req msg after PaymentDetailsRes, ContractAuthenticationRes */
    {"Waiting for AuthorizationReq, SessionStopReq", 1 << V2G_AUTHORIZATION_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-573], [V2G-813],[V2G-688] Expected req msg after AuthorizationRes or PowerDeliveryRes or ChargeParameterDiscoveryRes */
    {"Waiting for ChargeParameterDiscoveryReq, SessionStopReq", 1 << V2G_CHARGE_PARAMETER_DISCOVERY_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-582], [V2G-621] Expected req msg after CableCheckRes or ChargeParameterDiscoveryRes */
    {"Waiting for CableCheckReq, SessionStopReq", 1 << V2G_CABLE_CHECK_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-584] Expected req msg after CableCheckRes */
    {"Waiting for PreChargeReq, SessionStopReq", 1 << V2G_PRE_CHARGE_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-587] Expected req msg after PreChargeRes */
    {"Waiting for PreChargeReq, PowerDeliveryReq, SessionStopReq", 1 << V2G_PRE_CHARGE_MSG | 1 << V2G_POWER_DELIVERY_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-797] Expected req msg after CurrentDemandRes or MeteringReceiptRes*/
    {"Waiting for CurrentDemandReq, PowerDeliveryReq", 1 << V2G_CURRENT_DEMAND_MSG | 1 << V2G_POWER_DELIVERY_MSG},
    /* [V2G-590] Expected req msg after PowerDeliveryRes or CurrentDemandRes or MeteringReceiptRes*/
    {"Waiting for CurrentDemandReq", 1 << V2G_CURRENT_DEMAND_MSG},
    /* [V2G-795] Expected req msg after CurrentDemandRes */
    {"Waiting for MeteringReceiptReq", 1 << V2G_METERING_RECEIPT_MSG},
    /* [V2G-597], [V2G-601] Expected req msg after PowerDeliveryRes or WeldingDetectionRes*/
    {"Waiting for WeldingDetectionReq, SessionStopReq", 1 << V2G_WELDING_DETECTION_MSG | 1 << V2G_SESSION_STOP_MSG},
    {"Closing session", 0}
};

static void fill_iso_DC_EVSEStatus(v2g_connect_t* conn, struct iso2_DC_EVSEStatusType* status, enum charging_phase PHASE)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    secc_port_t *secc = v2g->secc;
    status->EVSEIsolationStatus = (iso2_isolationLevelType)v2g->evse_isolation_status;
    status->EVSEIsolationStatus_isUsed = 1;
    status->NotificationMaxDelay = 0;
    status->EVSENotification = iso2_EVSENotificationType_None;
    status->EVSEStatusCode = (secc->GUN_Error == 0?  (iso2_DC_EVSEStatusCodeType)v2g->evse_status_code[PHASE] : iso2_DC_EVSEStatusCodeType_EVSE_EmergencyShutdown);
    if (secc->manul_stop == true) status->EVSEStatusCode = iso2_DC_EVSEStatusCodeType_EVSE_Shutdown;
    if (secc_should_stop(secc)==1 && PHASE == PHASE_CHARGE) { status->EVSEStatusCode = iso2_DC_EVSEStatusCodeType_EVSE_Shutdown; }
}

static void load_iso_physical_value(struct iso2_PhysicalValueType* out, iso2_unitSymbolType type,  float value)
{
    switch(type)
    {
        case iso2_unitSymbolType_h:  {out->Unit= iso2_unitSymbolType_h;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
        case iso2_unitSymbolType_m:  {out->Unit= iso2_unitSymbolType_m;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
        case iso2_unitSymbolType_s:  {out->Unit= iso2_unitSymbolType_s;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
        case iso2_unitSymbolType_A:  {out->Unit= iso2_unitSymbolType_A;  out->Value = (uint16_t)(value*10); out->Multiplier = -1;}break;
        case iso2_unitSymbolType_V:  {out->Unit= iso2_unitSymbolType_V;  out->Value = (uint16_t)(value*10); out->Multiplier = -1;}break;
        case iso2_unitSymbolType_W:  {out->Unit= iso2_unitSymbolType_W;  out->Value = (uint16_t)(value/100); out->Multiplier = 2;}break;
        case iso2_unitSymbolType_Wh: {out->Unit= iso2_unitSymbolType_Wh; out->Value = (uint16_t)(value/1000); out->Multiplier = 3;}break;
        default :                    {out->Unit= iso2_unitSymbolType_h;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
    }
}

static iso2_responseCodeType iso_validate_state(int state, enum V2gMsgTypeId current_v2g_msg) 
{
    return (iso_dc_states[state].allowed_requests & (1 << current_v2g_msg)) ? iso2_responseCodeType_OK : iso2_responseCodeType_FAILED_SequenceError;
}

static int iso_validate_response_code(iso2_responseCodeType* const v2g_response_code, v2g_connect_t* const conn) 
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;
    iso2_responseCodeType response_code_tmp;

    if (secc->GUN_State < GUN_ELOCKED) {
        mlog_e(LOG_TAG_V2G, "Connection is terminated. Abort charging");
        return V2G_EVENT_TERMINATE_CONNECTION;
    }
    
    /* If alarm abort or emergency shutdown has occurred */
    if ( secc->GUN_Error != 0) {
        *v2g_response_code = iso2_responseCodeType_FAILED;
    }

    /* [V2G-DC-390]: at this point we must check whether the given request is valid at this step;
    * the idea is that we catch this error in each function below to respond with a valid
    * encoded message; note, that the handler functions below must not access v2g_session in
    * error path, since it might not be set, yet!
    */
    response_code_tmp = iso_validate_state(v2g->state, v2g->current_v2g_msg); // [V2G2-538]

    *v2g_response_code = (response_code_tmp >= iso2_responseCodeType_FAILED) ? response_code_tmp : *v2g_response_code;

    /* [V2G2-460]: check whether the session id matches the expected one of the active session */
    *v2g_response_code = ((v2g->current_v2g_msg != V2G_SESSION_SETUP_MSG) && (v2g->evse_session_id != v2g->evcc_session_id))? iso2_responseCodeType_FAILED_UnknownSession : *v2g_response_code;

    if ((v2g->terminate_connection_on_failed_response == true) && (*v2g_response_code >= iso2_responseCodeType_FAILED)) {
        next_event = V2G_EVENT_SEND_AND_TERMINATE; // [V2G2-539], [V2G2-034] Send response and terminate tcp-connection
    }

    /* log failed response code message */
    if ((*v2g_response_code >= iso2_responseCodeType_FAILED) && (*v2g_response_code <= iso2_responseCodeType_FAILED_CertificateRevoked)) {
        mlog_e(LOG_TAG_V2G, "Failed response code detected for message \"%s\", error: %s", v2g_msg_type[v2g->current_v2g_msg], isoResponse[*v2g_response_code]);
    }

    return next_event;
}

static int handle_iso_session_setup(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_SessionSetupReqType* req = (struct iso2_SessionSetupReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.SessionSetupReq;
    struct iso2_SessionSetupResType* res = (struct iso2_SessionSetupResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.SessionSetupRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    char buffer[iso2_evccIDType_BYTES_SIZE * 2 + iso2_evccIDType_BYTES_SIZE - 1 + 1]; /* format: (%02x:) * n - 1x ':' + 1x NUL */
    int idx;
    /* format EVCC ID */
    for (idx = 0; idx < req->EVCCID.bytesLen; idx++) {
        sprintf(&buffer[idx * 3], "%02X:", req->EVCCID.bytes[idx]);
    }
    if (idx)
        buffer[idx * 3 - 1] = '\0';
    else
        sprintf(buffer, "NULL");
    sprintf(v2g->secc->evccid, "%s", buffer);
    mlog_d(LOG_TAG_V2G, "SessionSetupReq.EVCCID: %s", buffer);


    /* Now fill the evse response message */
    res->ResponseCode = iso2_responseCodeType_OK_NewSessionEstablished;
    /* If the customer doesen't select a session id, generate one */
    srand((unsigned int)time(NULL));
    if (v2g->evse_session_id == (uint64_t)0) 
    {
        v2g->evse_session_id = ((uint64_t)rand() << 48) | ((uint64_t)rand() << 32) | ((uint64_t)rand() << 16) | (uint64_t)rand();
        mlog_d(LOG_TAG_V2G, "No evse_session_id found. Generating random session id.");
    }
    mlog_d(LOG_TAG_V2G, "Created new session with id 0x%08llu", v2g->evse_session_id);

    res->EVSEID.charactersLen = snprintf(res->EVSEID.characters, iso2_EVSEID_CHARACTER_SIZE, "%s", config->CCU_SN);
    res->EVSETimeStamp_isUsed = 1;
    res->EVSETimeStamp = time(NULL);

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_SERVICEDISCOVERY; // [V2G-543]

    return next_event;
}

static int handle_iso_service_discovery(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_ServiceDiscoveryReqType* req = (struct iso2_ServiceDiscoveryReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.ServiceDiscoveryReq;
    struct iso2_ServiceDiscoveryResType* res = (struct iso2_ServiceDiscoveryResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.ServiceDiscoveryRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    /* build up response */
    res->ResponseCode = iso2_responseCodeType_OK;

    res->ChargeService.ServiceID = V2G_SERVICE_ID_CHARGING;
    res->ChargeService.ServiceCategory = iso2_serviceCategoryType_EVCharging;
    res->ChargeService.ServiceName_isUsed = 0;
    res->ChargeService.SupportedEnergyTransferMode.EnergyTransferMode.array[0] = iso2_EnergyTransferModeType_DC_extended;
    res->ChargeService.SupportedEnergyTransferMode.EnergyTransferMode.arrayLen = 1;
    res->ChargeService.ServiceScope_isUsed = (unsigned int)0;
    res->ChargeService.FreeService = 0;

    res->PaymentOptionList.PaymentOption.array[0] = iso2_paymentOptionType_ExternalPayment;
    res->PaymentOptionList.PaymentOption.arrayLen = 1;

    if (conn->is_tls_connection == 1 && v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract)
    {
        res->PaymentOptionList.PaymentOption.array[1] = iso2_paymentOptionType_Contract;
        res->PaymentOptionList.PaymentOption.arrayLen = 2;
    }
    
    res->ServiceList.Service.array[0].ServiceID = V2G_SERVICE_ID_CHARGING;
    res->ServiceList.Service.array[0].ServiceCategory = iso2_serviceCategoryType_EVCharging;
    res->ServiceList.Service.array[0].ServiceName_isUsed = 0;
    res->ServiceList.Service.array[0].ServiceScope_isUsed = 0;
    res->ServiceList.Service.array[0].FreeService = 0;
    res->ServiceList.Service.arrayLen = 1;
    res->ServiceList_isUsed = 1;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_SVCDETAIL_PAYMENTSVCSEL; // [V2G-545]

    return next_event;
}

static int handle_iso_service_detail(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_ServiceDetailReqType* req = (struct iso2_ServiceDetailReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.ServiceDetailReq;
    struct iso2_ServiceDetailResType* res = (struct iso2_ServiceDetailResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.ServiceDetailRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    /* ServiceID reported back always matches the requested one */
    res->ServiceID = req->ServiceID;

    res->ResponseCode = (req->ServiceID == V2G_SERVICE_ID_CHARGING)? iso2_responseCodeType_OK : iso2_responseCodeType_FAILED_ServiceIDInvalid;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_SVCDETAIL_PAYMENTSVCSEL; // [V2G-DC-548]

    return next_event;

}

static int handle_iso_payment_service_selection(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_PaymentServiceSelectionReqType* req = (struct iso2_PaymentServiceSelectionReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.PaymentServiceSelectionReq;
    struct iso2_PaymentServiceSelectionResType* res = (struct iso2_PaymentServiceSelectionResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.PaymentServiceSelectionRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    res->ResponseCode = iso2_responseCodeType_OK;

    if (v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract)
    {
        res->ResponseCode = ((req->SelectedPaymentOption == iso2_paymentOptionType_Contract) && (conn->is_tls_connection == 1))? res->ResponseCode : iso2_responseCodeType_FAILED_PaymentSelectionInvalid; // [V2G2-465]
    }else{
        res->ResponseCode = (req->SelectedPaymentOption == iso2_paymentOptionType_ExternalPayment)? res->ResponseCode : iso2_responseCodeType_FAILED_PaymentSelectionInvalid; // [V2G2-465]
    }

    /* Check the selected services */
    bool charge_service_found = false;
    bool selected_services_found = true;

    for (uint8_t req_idx = 0; (req_idx < req->SelectedServiceList.SelectedService.arrayLen) && (selected_services_found == true); req_idx++) 
    {
        /* Check if it's a charging service */
        if (req->SelectedServiceList.SelectedService.array[req_idx].ServiceID == V2G_SERVICE_ID_CHARGING) {
            charge_service_found = true;
        }
        else /* Otherwise check if the selected service is in the stored in the service list */
        {
            /* If the requested SelectedService entry was not found, break up service list check */
            selected_services_found = false;
            break;
        }
    }

    res->ResponseCode = (selected_services_found == false)? iso2_responseCodeType_FAILED_ServiceSelectionInvalid : res->ResponseCode; // [V2G2-467]
    res->ResponseCode = (charge_service_found == false)? iso2_responseCodeType_FAILED_NoChargeServiceSelected : res->ResponseCode; // [V2G2-804]

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    if (req->SelectedPaymentOption == iso2_paymentOptionType_Contract) {
        mlog_i(LOG_TAG_V2G, "SelectedPaymentOption: Contract");
        v2g->iso_selected_payment_option = iso2_paymentOptionType_Contract;
        /* Set next expected req msg */
        v2g->state = (int)WAIT_FOR_PAYMENTDETAILS_CERTINST_CERTUPD; // [V2G-551] (iso specification describes only the ac case... )
    } else {
        mlog_i(LOG_TAG_V2G, "SelectedPaymentOption: ExternalPayment");
        v2g->evse_processing[PHASE_AUTH] = (uint8_t)iso2_EVSEProcessingType_Ongoing_WaitingForCustomerInteraction; // [V2G2-854]
        /* Set next expected req msg */
        v2g->state = (int) WAIT_FOR_AUTHORIZATION; // [V2G-551] (iso specification describes only the ac case... )
        v2g->auth_start_timeout = systime_ms();
    }

    return next_event;
}
static void generate_random_string(uint8_t* stream, int N)
{
    int i;
    uint8_t temp;
    srand((int32_t)time(0));
    for (i = 0; i < N; i++)
    {
        temp = (uint8_t)(rand() % 256);
        if (temp == 0) //随机数不要0
            temp = 128;
        stream[i] = temp;
    }
}
static int handle_iso_payment_details(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_PaymentDetailsReqType* req = (struct iso2_PaymentDetailsReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.PaymentDetailsReq;
    struct iso2_PaymentDetailsResType* res = (struct iso2_PaymentDetailsResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.PaymentDetailsRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;
    
    if (conn->pubkey) { EVP_PKEY_free(conn->pubkey); conn->pubkey = NULL;}

    memset(res, 0, sizeof(struct iso2_PaymentDetailsResType));
    res->EVSETimeStamp = time(NULL);
    res->GenChallenge.bytesLen = GEN_CHALLENGE_SIZE;
    res->ResponseCode = iso2_responseCodeType_FAILED_CertChainError;

    if (req->ContractSignatureCertChain.Certificate.bytesLen > 0)
    {
        struct x509_st* cert = load_X509Cert_fromString(req->ContractSignatureCertChain.Certificate.bytes, req->ContractSignatureCertChain.Certificate.bytesLen);
        if (cert)
        {
            conn->pubkey = get_PublicKey_fromX509Cert(cert);
            const uint8_t* emaid = get_EMAID_fromX509Cert(cert);
            printd("X509.emaid:%s, req.emaid:%s\n", emaid, req->eMAID.characters);
            char emaid_dump[64];
            char emaid_cert[64];
            string_strip_chr(emaid_dump, req->eMAID.characters, '-', req->eMAID.charactersLen);
            string_strip_chr(emaid_cert, emaid, '-', strlen(emaid));
            if (strcmp(emaid_dump, emaid_cert) == 0)
            {
                x509_list_t subCerts = {.items = {NULL}, .count = 0};
                if (req->ContractSignatureCertChain.SubCertificates_isUsed)
                {
                    for (int i = 0; i < req->ContractSignatureCertChain.SubCertificates.Certificate.arrayLen; i++) 
                    {
                        append_X509SubCert_fromString(&subCerts, req->ContractSignatureCertChain.SubCertificates.Certificate.array[i].bytes, req->ContractSignatureCertChain.SubCertificates.Certificate.array[i].bytesLen);
                    }
                }
                int ret = verify_X509Certs_withV2GMO(cert, &subCerts, secc->config->root_cert_path_v2g, secc->config->root_cert_path_mo);
                free_X509Certs_list(&subCerts);
                switch (ret)
                {
                    case X509_V_OK: 
                        secc_eim_startup(secc, req->eMAID.characters, 1000, 0, 0);
                        generate_random_string(v2g->gen_challenge, GEN_CHALLENGE_SIZE);
                        memcpy(res->GenChallenge.bytes, v2g->gen_challenge, GEN_CHALLENGE_SIZE);
                        res->GenChallenge.bytesLen = GEN_CHALLENGE_SIZE;
                        break;
                    case X509_V_ERR_CERT_HAS_EXPIRED:
                    case X509_V_ERR_CERT_NOT_YET_VALID: 
                        res->ResponseCode = iso2_responseCodeType_FAILED_CertificateExpired;
                        break;
                    case X509_V_ERR_CERT_REVOKED: 
                        res->ResponseCode = iso2_responseCodeType_FAILED_CertificateRevoked;
                        break;
                    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
                    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: 
                        memset(res, 0, sizeof(struct iso2_PaymentDetailsResType));
                        res->ResponseCode = iso2_responseCodeType_FAILED_NoCertificateAvailable; 
                        break;
                }
            }
            X509_free(cert);
        }
    }

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_AUTHORIZATION; // [V2G-560]
    v2g->auth_start_timeout = systime_ms();
    v2g->evse_processing[PHASE_AUTH] = iso2_EVSEProcessingType_Ongoing;

    return next_event;
}

static int handle_iso_authorization(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;

    struct iso2_AuthorizationReqType* req = (struct iso2_AuthorizationReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.AuthorizationReq;
    struct iso2_AuthorizationResType* res = (struct iso2_AuthorizationResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.AuthorizationRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    res->ResponseCode = iso2_responseCodeType_OK;

    if (v2g->last_v2g_msg != V2G_AUTHORIZATION_MSG && (v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract)) 
    { /* [V2G2-684] */
        res->ResponseCode = iso2_responseCodeType_FAILED_SignatureError;
        if (conn->iso2EXIDocument_xin.V2G_Message.Header.Signature_isUsed == 1) 
        {
            res->ResponseCode = iso2_responseCodeType_FAILED_ChallengeInvalid;
            const struct iso2_SignatureType* iso2_signature = &conn->iso2EXIDocument_xin.V2G_Message.Header.Signature;
            const struct iso2_ReferenceType* reference = &iso2_signature->SignedInfo.Reference.array[0];
            const int signature_len = iso2_signature->SignatureValue.CONTENT.bytesLen;
            const uint8_t* signature = &iso2_signature->SignatureValue.CONTENT.bytes[0];

            if (req->GenChallenge_isUsed && req->GenChallenge.bytesLen == GEN_CHALLENGE_SIZE && reference->DigestValue.bytesLen == SHA256_SIGNATURE_SIZE && signature_len == 64)
            {
                if (strncmp(req->GenChallenge.bytes, v2g->gen_challenge, GEN_CHALLENGE_SIZE)==0)
                {
                    uint8_t digest[64];
                    sha256_signature_from_DigestValue(digest, req);
                    if (memcmp(reference->DigestValue.bytes, digest, reference->DigestValue.bytesLen)==0)
                    {
                        sha256_signature_from_SignedInfo(digest, iso2_signature);
                        if (conn->pubkey)
                        {
                            const uint8_t* r = &signature[0];
                            const uint8_t* s = &signature[SHA256_SIGNATURE_SIZE];
                            if (verify_Signature_UsePKEY(conn->pubkey, r, s, digest)==1)
                            {
                                res->ResponseCode = iso2_responseCodeType_OK;
                            }
                        }
                    }
                }
            }
        }
    }

    res->EVSEProcessing = (iso2_EVSEProcessingType)v2g->evse_processing[PHASE_AUTH];

    if (v2g->evse_processing[PHASE_AUTH] != iso2_EVSEProcessingType_Finished) {
        if (v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract && v2g->auth_timeout_pnc > 0)
        {
            if ((systime_ms() - v2g->auth_start_timeout) > v2g->auth_timeout_pnc)
            {
                v2g->auth_start_timeout = systime_ms();
                res->ResponseCode = iso2_responseCodeType_FAILED;
                secc_set_error(secc, CCS_AUTHORIZATE_TIMEOUT);
            }
        } 
        else 
        if (v2g->iso_selected_payment_option == iso2_paymentOptionType_ExternalPayment && v2g->auth_timeout_eim > 0)
        {
            if ((systime_ms() - v2g->auth_start_timeout) > v2g->auth_timeout_eim)
            {
                v2g->auth_start_timeout = systime_ms();
                res->ResponseCode = iso2_responseCodeType_FAILED;
                secc_set_error(secc, CCS_AUTHORIZATE_TIMEOUT);
            }
        }else{
            mlog_d(LOG_TAG_V2G, "Waiting for authorization forever!");
            secc_set_error(secc, CCSX_STATE_ERROR);
        }
    }

    if (conn->pubkey) { EVP_PKEY_free(conn->pubkey); conn->pubkey = NULL;}

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (res->EVSEProcessing == iso2_EVSEProcessingType_Finished)? (int)WAIT_FOR_CHARGEPARAMETERDISCOVERY : (int)WAIT_FOR_AUTHORIZATION; // [V2G-573] (AC) , [V2G-687] (DC)

    return next_event;
}

static int handle_iso_charge_parameter_discovery(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_ChargeParameterDiscoveryReqType* req = (struct iso2_ChargeParameterDiscoveryReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.ChargeParameterDiscoveryReq;
    struct iso2_ChargeParameterDiscoveryResType* res = (struct iso2_ChargeParameterDiscoveryResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.ChargeParameterDiscoveryRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    res->ResponseCode = (req->RequestedEnergyTransferMode == iso2_EnergyTransferModeType_DC_extended)? iso2_responseCodeType_OK : iso2_responseCodeType_FAILED_WrongEnergyTransferMode;
    res->ResponseCode = (req->AC_EVChargeParameter_isUsed == 1)? iso2_responseCodeType_FAILED_WrongChargeParameter : res->ResponseCode; // [V2G2-477]

    if (req->DC_EVChargeParameter_isUsed)
    {
        struct iso2_DC_EVChargeParameterType *DC_EVChargeParameter = (struct iso2_DC_EVChargeParameterType *)&req->DC_EVChargeParameter;

        secc->EVCC_maxI = calc_physical_value(DC_EVChargeParameter->EVMaximumCurrentLimit.Value, DC_EVChargeParameter->EVMaximumCurrentLimit.Multiplier);
        secc->EVCC_maxV = calc_physical_value(DC_EVChargeParameter->EVMaximumVoltageLimit.Value, DC_EVChargeParameter->EVMaximumVoltageLimit.Multiplier);
        if (DC_EVChargeParameter->DepartureTime_isUsed) { secc->request_Minutes = (DC_EVChargeParameter->DepartureTime + 30)/60; }
        if (DC_EVChargeParameter->EVMaximumPowerLimit_isUsed) 
        { secc->EVCC_maxP = calc_physical_value(DC_EVChargeParameter->EVMaximumPowerLimit.Value, DC_EVChargeParameter->EVMaximumPowerLimit.Multiplier) / 1000; }
        if (DC_EVChargeParameter->EVEnergyCapacity_isUsed) 
        { secc->request_KWh = calc_physical_value(DC_EVChargeParameter->EVEnergyCapacity.Value, DC_EVChargeParameter->EVEnergyCapacity.Multiplier) / 1000; }
        if (DC_EVChargeParameter->EVEnergyRequest_isUsed) 
        { secc->request_KWh = calc_physical_value(DC_EVChargeParameter->EVEnergyRequest.Value, DC_EVChargeParameter->EVEnergyRequest.Multiplier) / 1000; }
        if (DC_EVChargeParameter->BulkSOC_isUsed) { secc->SOC = DC_EVChargeParameter->BulkSOC; }
        if (DC_EVChargeParameter->FullSOC_isUsed) { secc->SOC = DC_EVChargeParameter->FullSOC; }
    }
    if (req->EVChargeParameter_isUsed)
    {
        struct iso2_DC_EVChargeParameterType *DC_EVChargeParameter = (struct iso2_DC_EVChargeParameterType *)&req->EVChargeParameter.DC_EVChargeParameter;
        secc->EVCC_maxI = calc_physical_value(DC_EVChargeParameter->EVMaximumCurrentLimit.Value, DC_EVChargeParameter->EVMaximumCurrentLimit.Multiplier);
        secc->EVCC_maxV = calc_physical_value(DC_EVChargeParameter->EVMaximumVoltageLimit.Value, DC_EVChargeParameter->EVMaximumVoltageLimit.Multiplier);
        if (DC_EVChargeParameter->DepartureTime_isUsed) { secc->request_Minutes = (DC_EVChargeParameter->DepartureTime + 30)/60; }
        if (DC_EVChargeParameter->EVMaximumPowerLimit_isUsed) 
        { secc->EVCC_maxP = calc_physical_value(DC_EVChargeParameter->EVMaximumPowerLimit.Value, DC_EVChargeParameter->EVMaximumPowerLimit.Multiplier) / 1000; }
        if (DC_EVChargeParameter->EVEnergyCapacity_isUsed) 
        { secc->request_KWh = calc_physical_value(DC_EVChargeParameter->EVEnergyCapacity.Value, DC_EVChargeParameter->EVEnergyCapacity.Multiplier) / 1000; }
        if (DC_EVChargeParameter->EVEnergyRequest_isUsed) 
        { secc->request_KWh = calc_physical_value(DC_EVChargeParameter->EVEnergyRequest.Value, DC_EVChargeParameter->EVEnergyRequest.Multiplier) / 1000; }
        if (DC_EVChargeParameter->BulkSOC_isUsed) { secc->SOC = DC_EVChargeParameter->BulkSOC; }
        if (DC_EVChargeParameter->FullSOC_isUsed) { secc->SOC = DC_EVChargeParameter->FullSOC; }
    }

    /* Configure DC stucture elements */
    res->EVSEProcessing = (iso2_EVSEProcessingType)v2g->evse_processing[PHASE_PARAMETER];
    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEChargeParameter.DC_EVSEStatus, PHASE_PARAMETER);



    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance, iso2_unitSymbolType_A, 2);
    res->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance_isUsed = 0;

    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered, iso2_unitSymbolType_Wh, 2000000);
    res->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered_isUsed = 0;

    printi("secc->SECC_maxV:%f, SECC_minV:%f\n", secc->SECC_maxV, secc->SECC_minV);

    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEMaximumPowerLimit, iso2_unitSymbolType_Wh, secc->SECC_maxP);
    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEMaximumCurrentLimit, iso2_unitSymbolType_A, secc->SECC_maxI);
    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEMinimumCurrentLimit, iso2_unitSymbolType_A, secc->SECC_minI);
    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEMaximumVoltageLimit, iso2_unitSymbolType_V, secc->SECC_maxV);
    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEMinimumVoltageLimit, iso2_unitSymbolType_V, secc->SECC_minV);
    load_iso_physical_value(&res->DC_EVSEChargeParameter.EVSEPeakCurrentRipple, iso2_unitSymbolType_A, 2);
    res->DC_EVSEChargeParameter_isUsed = 1;
    res->AC_EVSEChargeParameter_isUsed = 0;
    
    res->EVSEChargeParameter_isUsed = 0;

    /* Configure SA-schedules*/
    if (res->EVSEProcessing == iso2_EVSEProcessingType_Finished) 
    {
        res->SAScheduleList.SAScheduleTuple.array[0].SAScheduleTupleID = 1;
        res->SAScheduleList.SAScheduleTuple.array[0].SalesTariff_isUsed = 0;
        res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval.start = 0;
        res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval.duration = 86400;
        res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval.duration_isUsed = 1;
        res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.arrayLen = 1;
        res->SAScheduleList.SAScheduleTuple.arrayLen = 1;
        res->SAScheduleList_isUsed = (unsigned int)1; //  The SECC shall only omit the parameter 'SAScheduleList' in case EVSEProcessing is set to 'Ongoing'.
        if ((req->MaxEntriesSAScheduleTuple_isUsed == (unsigned int)1) &&
            (req->MaxEntriesSAScheduleTuple < res->SAScheduleList.SAScheduleTuple.arrayLen)) {
            mlog_w(LOG_TAG_V2G, "EV's max. SA-schedule-tuple entries exceeded");
        }
    }else{
        res->EVSEProcessing = iso2_EVSEProcessingType_Ongoing;
        res->SAScheduleList_isUsed = (unsigned int)0;
    }
    res->SASchedules_isUsed = 0;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (iso2_EVSEProcessingType_Finished == res->EVSEProcessing)? (int)WAIT_FOR_CABLECHECK : (int)WAIT_FOR_CHARGEPARAMETERDISCOVERY; // [V2G-582], [V2G-688]

    return next_event;
}

static int handle_iso_power_delivery(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_PowerDeliveryReqType* req = (struct iso2_PowerDeliveryReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.PowerDeliveryReq;
    struct iso2_PowerDeliveryResType* res = (struct iso2_PowerDeliveryResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.PowerDeliveryRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    secc_set_state(secc, GUN_CHARGING);

    res->ResponseCode = iso2_responseCodeType_OK;
    switch (req->ChargeProgress) {
    case iso2_chargeProgressType_Start:
        secc_request_power(secc, POWER_REQUEST_CONST_VOLTAGE, secc->request_voltage, secc->request_current);
        v2g->evse_status_code[PHASE_CHARGE] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;
        v2g->evse_processing[PHASE_CHARGE] = iso2_EVSEProcessingType_Finished;
        break;

    case iso2_chargeProgressType_Stop:
        secc_request_power(secc, POWER_REQUEST_SHUTDOWN, secc->request_voltage, secc->request_current);
        v2g->evse_status_code[PHASE_CHARGE] = iso2_DC_EVSEStatusCodeType_EVSE_Shutdown;
        v2g->evse_processing[PHASE_CHARGE] = iso2_EVSEProcessingType_Finished;
        break;

    case iso2_chargeProgressType_Renegotiate:
        v2g->evse_status_code[PHASE_CHARGE] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady;
        // v2g->evse_processing[PHASE_CHARGE] = iso2_EVSEProcessingType_Ongoing;
        break;
    default:
        mlog_e(LOG_TAG_V2G, "Unknown ChargeProgress %d received, signaling error", req->ChargeProgress);
        res->ResponseCode = iso2_responseCodeType_FAILED;
    }

    res->DC_EVSEStatus_isUsed = 1;
    res->AC_EVSEStatus_isUsed = 0;
    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_CHARGE);

    res->ResponseCode = (req->ChargeProgress == iso2_chargeProgressType_Start) && (res->DC_EVSEStatus.EVSEStatusCode != iso2_DC_EVSEStatusCodeType_EVSE_Ready)? iso2_responseCodeType_FAILED_PowerDeliveryNotApplied : res->ResponseCode; // [V2G2-480]
    res->EVSEStatus_isUsed = 0;

    /* Check the selected SAScheduleTupleID */
    v2g->sa_schedule_tuple_id = req->SAScheduleTupleID;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    if ((req->ChargeProgress == iso2_chargeProgressType_Renegotiate) && ((v2g->last_v2g_msg == V2G_CURRENT_DEMAND_MSG) || (v2g->last_v2g_msg == V2G_CHARGING_STATUS_MSG))) 
    {
        v2g->state = (int)WAIT_FOR_CHARGEPARAMETERDISCOVERY; // [V2G-813]
        // Reset DC relevant parameter to start the renegotation process
        v2g->evse_processing[PHASE_ISOLATION] = iso2_EVSEProcessingType_Ongoing;
        v2g->evse_notification = (v2g->evse_notification == iso2_EVSENotificationType_ReNegotiation)? iso2_EVSENotificationType_None : v2g->evse_notification;
        v2g->evse_isolation_status = iso2_isolationLevelType_Invalid;
    } 
    else  if ((req->ChargeProgress == iso2_chargeProgressType_Start) && (v2g->last_v2g_msg != V2G_CURRENT_DEMAND_MSG) && (v2g->last_v2g_msg != V2G_CHARGING_STATUS_MSG)) 
    {
        v2g->state = (int)WAIT_FOR_CURRENTDEMAND; // [V2G-590], [V2G2-576]
    } 
    else 
    {
        /* abort charging session if EV is ready to charge after current demand phase */
        res->ResponseCode = (req->ChargeProgress == iso2_chargeProgressType_Stop)? res->ResponseCode :  iso2_responseCodeType_FAILED; // (/*[V2G2-812]*/
        v2g->state = (int)WAIT_FOR_WELDINGDETECTION_SESSIONSTOP; // [V2G-601], [V2G2-568]
    }

    return next_event;
}

static int handle_iso_charging_status(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_ChargingStatusReqType* req = (struct iso2_ChargingStatusReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.ChargingStatusReq;
    struct iso2_ChargingStatusResType* res = (struct iso2_ChargingStatusResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.ChargingStatusRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    res->ResponseCode = iso2_responseCodeType_OK;

    res->ReceiptRequired = v2g->receipt_required;
    res->ReceiptRequired_isUsed = (v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract)? v2g->receipt_required : 0U;

    res->MeterInfo_isUsed = 0;

    res->EVSEMaxCurrent_isUsed = (v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract)? 0U : 1U; // This element is not included in the message if any AC PnC Message Set has been selected.

    if (res->EVSEMaxCurrent_isUsed == 1U) {
        load_iso_physical_value(&res->EVSEMaxCurrent, iso2_unitSymbolType_A, 80);//AC current limit
    }

    conn->iso2EXIDocument_out.V2G_Message.Body.ChargingStatusRes_isUsed = 1;

    /* the following field can also be set in error path */
    res->EVSEID.charactersLen = snprintf(res->EVSEID.characters, iso2_EVSEID_CHARACTER_SIZE, "%s", config->CCU_SN);

    /* in error path the session might not be available */
    res->SAScheduleTupleID = 1;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (((int)1 == res->ReceiptRequired))? (int)WAIT_FOR_METERINGRECEIPT : (int)WAIT_FOR_AC_CHARGINGSTATUS_POWERDELIVERY; // [V2G2-577], [V2G2-575]

    return next_event;
}

static int handle_iso_metering_receipt(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_MeteringReceiptReqType* req = (struct iso2_MeteringReceiptReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.MeteringReceiptReq;
    struct iso2_MeteringReceiptResType* res = (struct iso2_MeteringReceiptResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.MeteringReceiptRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    /* At first, publish the received ev request message to the MQTTinterface */
    // publish_iso_metering_receipt_req(req);

    mlog_d(LOG_TAG_V2G, "EVSE side: meteringReceipt called");
    mlog_d(LOG_TAG_V2G, "\tReceived data:");
    mlog_d(LOG_TAG_V2G, "\t\t ID=%c%c%c", req->Id.characters[0], req->Id.characters[1], req->Id.characters[2]);
    mlog_d(LOG_TAG_V2G, "\t\t SAScheduleTupleID=%d", req->SAScheduleTupleID);
    mlog_d(LOG_TAG_V2G, "\t\t SessionID=%d", req->SessionID.bytes[1]);
    mlog_d(LOG_TAG_V2G, "\t\t MeterInfo.MeterStatus=%d", req->MeterInfo.MeterStatus);
    mlog_d(LOG_TAG_V2G, "\t\t MeterInfo.MeterID=%d", req->MeterInfo.MeterID.characters[0]);
    mlog_d(LOG_TAG_V2G, "\t\t MeterInfo.isused.MeterReading=%d", req->MeterInfo.MeterReading_isUsed);
    mlog_d(LOG_TAG_V2G, "\t\t MeterReading.Value=%lu", (long unsigned int)req->MeterInfo.MeterReading);
    mlog_d(LOG_TAG_V2G, "\t\t MeterInfo.TMeter=%li", (long int)req->MeterInfo.TMeter);

    res->ResponseCode = iso2_responseCodeType_OK;
    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_CHARGE);
    res->DC_EVSEStatus_isUsed = 1;
    res->AC_EVSEStatus_isUsed = 0;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_CURRENTDEMAND_POWERDELIVERY; // [V2G2-580]/[V2G-797]

    return next_event;
}

static int handle_iso_certificate_update(v2g_connect_t* conn)
{
    // TODO: implement CertificateUpdate handling
    return V2G_EVENT_NO_EVENT;
}

static int handle_iso_certificate_installation(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    // TODO: implement CertificateUpdate handling
    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_PAYMENTDETAILS; // [V2G-554]
    return V2G_EVENT_NO_EVENT;
}

static int handle_iso_cable_check(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    struct iso2_CableCheckReqType* req = (struct iso2_CableCheckReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.CableCheckReq;
    struct iso2_CableCheckResType* res = (struct iso2_CableCheckResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.CableCheckRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    // TODO: For DC charging wait for CP state C or D , before transmitting of the response ([V2G2-917], [V2G2-918]). CP
    // state is checked by other module

    /* Fill the CableCheckRes */
    res->ResponseCode = iso2_responseCodeType_OK;
    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_ISOLATION);
    res->EVSEProcessing = v2g->evse_processing[PHASE_ISOLATION];
    res->DC_EVSEStatus.EVSEStatusCode = (res->EVSEProcessing == din_EVSEProcessingType_Finished)? din_DC_EVSEStatusCodeType_EVSE_Ready:(din_DC_EVSEStatusCodeType)v2g->evse_status_code[PHASE_ISOLATION];

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (res->EVSEProcessing == iso2_EVSEProcessingType_Finished)? (int)WAIT_FOR_PRECHARGE : (int)WAIT_FOR_CABLECHECK; // [V2G-584], [V2G-621]

    return next_event;

}

static int handle_iso_pre_charge(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_PreChargeReqType* req = (struct iso2_PreChargeReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.PreChargeReq;
    struct iso2_PreChargeResType* res = (struct iso2_PreChargeResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.PreChargeRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    secc->request_voltage = calc_physical_value(req->EVTargetVoltage.Value, req->EVTargetVoltage.Multiplier);
    secc->request_current = calc_physical_value(req->EVTargetCurrent.Value, req->EVTargetCurrent.Multiplier);
    secc->request_powerKW = secc->request_voltage * secc->request_current / 1000;
    /* At first, publish the received EV request message to the MQTT interface */
    // secc->VMeters = secc->get_DCMeters_voltage(secc);
    printi("request_voltage:%f, request_current:%f, presentVoltage:%f\n", secc->request_voltage, secc->request_current, secc->VMeters);
    // publish_iso_pre_charge_req(conn->ctx, req);

    /* Fill the PreChargeRes*/
    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_PRECHARGE);
    load_iso_physical_value(&res->EVSEPresentVoltage, iso2_unitSymbolType_V, secc->VMeters);
    res->ResponseCode = iso2_responseCodeType_OK;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_PRECHARGE_POWERDELIVERY; // [V2G-587]

    return next_event;    
}

static int handle_iso_current_demand(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_CurrentDemandReqType* req = (struct iso2_CurrentDemandReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.CurrentDemandReq;
    struct iso2_CurrentDemandResType* res = (struct iso2_CurrentDemandResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.CurrentDemandRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    /* At first, publish the received EV request message to the MQTT interface */

    // publish_iso_current_demand_req(conn->ctx, req);
    secc->request_voltage = calc_physical_value(req->EVTargetVoltage.Value, req->EVTargetVoltage.Multiplier);
    secc->request_current = calc_physical_value(req->EVTargetCurrent.Value, req->EVTargetCurrent.Multiplier);
    secc->request_powerKW = secc->request_voltage * secc->request_current / 1000;
    secc_request_power(secc, POWER_REQUEST_CONST_VOLTAGE, secc->request_voltage, secc->request_current);
    secc_report_MeterValues(secc);
    printi("request_voltage:%f, request_current:%f, request_powerKW:%f.  PresentVoltage:%f, PresentCurrent:%f\n", secc->request_voltage, secc->request_current, secc->request_powerKW, secc->VMeters, secc->IMeters);

    res->ResponseCode = iso2_responseCodeType_OK; // [V2G-DC-388]
    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_CHARGE);
    res->EVSEID.charactersLen = snprintf(res->EVSEID.characters, iso2_EVSEID_CHARACTER_SIZE, "%s", config->CCU_SN);
    res->EVSEVoltageLimitAchieved = (secc->request_voltage >= secc->SECC_maxV)? 1:0;
    res->EVSECurrentLimitAchieved = (secc->request_current >= secc->SECC_maxI)? 1:0;
    res->EVSEPowerLimitAchieved = (secc->request_powerKW >= secc->SECC_maxP)? 1:0;
    load_iso_physical_value(&res->EVSEMaximumVoltageLimit, din_unitSymbolType_V, secc->SECC_maxV);
    res->EVSEMaximumVoltageLimit_isUsed = 1;
    load_iso_physical_value(&res->EVSEMaximumCurrentLimit, din_unitSymbolType_A, secc->SECC_maxI);
    res->EVSEMaximumCurrentLimit_isUsed = 1;
    load_iso_physical_value(&res->EVSEMaximumPowerLimit, din_unitSymbolType_W, secc->SECC_maxP);
    res->EVSEMaximumPowerLimit_isUsed = 1;
    
    load_iso_physical_value(&res->EVSEPresentVoltage, din_unitSymbolType_V, secc->VMeters);
    load_iso_physical_value(&res->EVSEPresentCurrent, din_unitSymbolType_A, secc->IMeters);

    res->MeterInfo_isUsed = 0;

    res->ReceiptRequired = v2g->receipt_required; // TODO: PNC only
    res->ReceiptRequired_isUsed = (v2g->iso_selected_payment_option == iso2_paymentOptionType_Contract)? (unsigned int)v2g->receipt_required : (unsigned int)0;
    res->ResponseCode = iso2_responseCodeType_OK;
    res->SAScheduleTupleID = v2g->sa_schedule_tuple_id;


    if (req->EVTargetCurrent.Value > 0 && secc->IMeters < 0) {
        mlog_d(LOG_TAG_V2G, "SAE V2G Bidi handshake was not recognized by the ev side. Instead of shutting down, it is better to wait for a correct response");
    }
    if (req->EVTargetCurrent.Value < 0 && secc->IMeters > 0) {
        mlog_d(LOG_TAG_V2G, "SAE V2G Bidi handshake was not recognized by the ev side. Instead of shutting down, it is better to wait for a correct response");
    }

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = ((res->ReceiptRequired_isUsed == (unsigned int)1) && (res->ReceiptRequired == (int)1))? (int)WAIT_FOR_METERINGRECEIPT : WAIT_FOR_CURRENTDEMAND_POWERDELIVERY; // [V2G-795], [V2G-593]

    return next_event;
}

static int handle_iso_welding_detection(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_WeldingDetectionReqType* req = (struct iso2_WeldingDetectionReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.WeldingDetectionReq;
    struct iso2_WeldingDetectionResType* res = (struct iso2_WeldingDetectionResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.WeldingDetectionRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;

    /* At first, publish the received EV request message to the MQTT interface */

    secc_request_power(secc, POWER_REQUEST_SHUTDOWN, .0f, .0f);

    
    // publish_iso_welding_detection_req(conn->ctx, req);

    // TODO: Wait for CP state B, before transmitting of the response, or signal intl_emergency_shutdown in conn->ctx
    // ([V2G2-920], [V2G2-921]).

    fill_iso_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_WELDING);
    load_iso_physical_value(&res->EVSEPresentVoltage, iso2_unitSymbolType_V, secc->VMeters);
    res->ResponseCode = iso2_responseCodeType_OK;

    /* Check the current response code and check if no external error has occurred */
    next_event = iso_validate_response_code(&res->ResponseCode, conn);

    /* Set next expected req msg */
    v2g->state = (int)WAIT_FOR_WELDINGDETECTION_SESSIONSTOP; // [V2G-597]

    return next_event;
}

static int handle_iso_session_stop(v2g_connect_t* conn)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_SessionStopReqType* req = (struct iso2_SessionStopReqType*)&conn->iso2EXIDocument_xin.V2G_Message.Body.SessionStopReq;
    struct iso2_SessionStopResType* res = (struct iso2_SessionStopResType*)&conn->iso2EXIDocument_out.V2G_Message.Body.SessionStopRes;
    enum v2g_event next_event = V2G_EVENT_NO_EVENT;
    res->ResponseCode = iso2_responseCodeType_OK;

    secc_set_state(secc, GUN_STOPPING);
    secc_request_power(secc, POWER_REQUEST_PLACE_FREE, .0f, .0f);

    /* Check the current response code and check if no external error has occurred */
    iso_validate_response_code(&res->ResponseCode, conn);

    /* Set the next charging state */
    switch (req->ChargingSession) {
    case iso2_chargingSessionType_Terminate:
        /* Set next expected req msg */
        v2g->state = (int)WAIT_FOR_TERMINATED_SESSION;
        break;

    case iso2_chargingSessionType_Pause:
        /* Set next expected req msg */
        /* Check if the EV is allowed to request the sleep mode. TODO: Remove "true" if sleep mode is supported */
        if (((v2g->last_v2g_msg != V2G_POWER_DELIVERY_MSG) && (v2g->last_v2g_msg != V2G_WELDING_DETECTION_MSG))) 
        {
            // conn->dlink_action = MQTT_DLINK_ACTION_TERMINATE;
            // v2g->hlc_pause_active = false;
            res->ResponseCode = iso2_responseCodeType_FAILED;
            v2g->state = (int)WAIT_FOR_TERMINATED_SESSION;
        } else {
            /* Init sleep mode for the EV */
            // conn->dlink_action = MQTT_DLINK_ACTION_PAUSE;
            // v2g->hlc_pause_active = true;
            v2g->state = (int)WAIT_FOR_SESSIONSETUP;
        }
        break;

    default:
        /* Set next expected req msg */
        // conn->dlink_action = MQTT_DLINK_ACTION_TERMINATE;
        v2g->state = (int)WAIT_FOR_TERMINATED_SESSION;
    }

    return V2G_EVENT_SEND_AND_TERMINATE; // Charging must be terminated after sending the response message [V2G2-571]
}

int v2g_handle_iso_request(v2g_connect_t* conn)
{
    int next_v2g_event = 0;
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    ccu_config_t* config = &ccu_config;
    pcu_port_t* pcu = v2g->pcu;
    ccu_port_t* ccu = v2g->ccu;
    secc_port_t *secc = v2g->secc;
    struct iso2_exiDocument *exi_xin = &conn->iso2EXIDocument_xin;
    struct iso2_exiDocument *exi_out = &conn->iso2EXIDocument_out;
    memset(exi_xin, 0, sizeof(struct iso2_exiDocument));
    int rv = decode_iso2_exiDocument(&conn->stream, exi_xin);
    struct iso2_MessageHeaderType* hdr = &exi_xin->V2G_Message.Header;
    memcpy(&v2g->evcc_session_id, &hdr->SessionID.bytes, hdr->SessionID.bytesLen);

    init_iso2_exiDocument(exi_out);
    init_iso2_MessageHeaderType(&exi_out->V2G_Message.Header);
    exi_out->V2G_Message.Header.SessionID.bytesLen = 8;
    init_iso2_BodyType(&exi_out->V2G_Message.Body);

    /* handle each message type individually;
     * we use a none-usual source code formatting here to optically group the individual
     * request a little bit
     */
    if (exi_xin->V2G_Message.Body.CurrentDemandReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling CurrentDemandReq");
        if (v2g->last_v2g_msg == V2G_POWER_DELIVERY_MSG) {
            // v2g->p_charger->publish_current_demand_started(nullptr);
            // v2g->session.is_charging = true;
        }
        v2g->current_v2g_msg = V2G_CURRENT_DEMAND_MSG;
        exi_out->V2G_Message.Body.CurrentDemandRes_isUsed = 1u;
        init_iso2_CurrentDemandResType(&exi_out->V2G_Message.Body.CurrentDemandRes);
        next_v2g_event = handle_iso_current_demand(conn); //  [V2G2-592]
    } else if (exi_xin->V2G_Message.Body.SessionSetupReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling SessionSetupReq");
        v2g->current_v2g_msg = V2G_SESSION_SETUP_MSG;
        exi_out->V2G_Message.Body.SessionSetupRes_isUsed = 1u;
        init_iso2_SessionSetupResType(&exi_out->V2G_Message.Body.SessionSetupRes);
        next_v2g_event = handle_iso_session_setup(conn); // [V2G2-542]
    } else if (exi_xin->V2G_Message.Body.ServiceDiscoveryReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling ServiceDiscoveryReq");
        v2g->current_v2g_msg = V2G_SERVICE_DISCOVERY_MSG;
        exi_out->V2G_Message.Body.ServiceDiscoveryRes_isUsed = 1u;
        init_iso2_ServiceDiscoveryResType(&exi_out->V2G_Message.Body.ServiceDiscoveryRes);
        next_v2g_event = handle_iso_service_discovery(conn); // [V2G2-542]
    } else if (exi_xin->V2G_Message.Body.ServiceDetailReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling ServiceDetailReq");
        v2g->current_v2g_msg = V2G_SERVICE_DETAIL_MSG;
        exi_out->V2G_Message.Body.ServiceDetailRes_isUsed = 1u;
        init_iso2_ServiceDetailResType(&exi_out->V2G_Message.Body.ServiceDetailRes);
        next_v2g_event = handle_iso_service_detail(conn); // [V2G2-547]
    } else if (exi_xin->V2G_Message.Body.PaymentServiceSelectionReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling PaymentServiceSelectionReq");
        v2g->current_v2g_msg = V2G_PAYMENT_SERVICE_SELECTION_MSG;
        exi_out->V2G_Message.Body.PaymentServiceSelectionRes_isUsed = 1u;
        init_iso2_PaymentServiceSelectionResType(&exi_out->V2G_Message.Body.PaymentServiceSelectionRes);
        next_v2g_event = handle_iso_payment_service_selection(conn); // [V2G2-550]
    } else if (exi_xin->V2G_Message.Body.PaymentDetailsReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling PaymentDetailsReq");
        v2g->current_v2g_msg = V2G_PAYMENT_DETAILS_MSG;
        exi_out->V2G_Message.Body.PaymentDetailsRes_isUsed = 1u;
        init_iso2_PaymentDetailsResType(&exi_out->V2G_Message.Body.PaymentDetailsRes);
        next_v2g_event = handle_iso_payment_details(conn); // [V2G2-559]
    } else if (exi_xin->V2G_Message.Body.AuthorizationReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling AuthorizationReq");
        v2g->current_v2g_msg = V2G_AUTHORIZATION_MSG;
        exi_out->V2G_Message.Body.AuthorizationRes_isUsed = 1u;
        init_iso2_AuthorizationResType(&exi_out->V2G_Message.Body.AuthorizationRes);
        next_v2g_event = handle_iso_authorization(conn); // [V2G2-562]
    } else if (exi_xin->V2G_Message.Body.ChargeParameterDiscoveryReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling ChargeParameterDiscoveryReq");
        v2g->current_v2g_msg = V2G_CHARGE_PARAMETER_DISCOVERY_MSG;
        if (v2g->last_v2g_msg == V2G_AUTHORIZATION_MSG) {
            mlog_i(LOG_TAG_V2G, "Parameter-phase started");
        }
        exi_out->V2G_Message.Body.ChargeParameterDiscoveryRes_isUsed = 1u;
        init_iso2_ChargeParameterDiscoveryResType(&exi_out->V2G_Message.Body.ChargeParameterDiscoveryRes);
        next_v2g_event = handle_iso_charge_parameter_discovery(conn); // [V2G2-565]
    } else if (exi_xin->V2G_Message.Body.PowerDeliveryReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling PowerDeliveryReq");
        v2g->current_v2g_msg = V2G_POWER_DELIVERY_MSG;
        exi_out->V2G_Message.Body.PowerDeliveryRes_isUsed = 1u;
        init_iso2_PowerDeliveryResType(&exi_out->V2G_Message.Body.PowerDeliveryRes);
        next_v2g_event = handle_iso_power_delivery(conn); // [V2G2-589]
    } else if (exi_xin->V2G_Message.Body.ChargingStatusReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling ChargingStatusReq");
        v2g->current_v2g_msg = V2G_CHARGING_STATUS_MSG;

        exi_out->V2G_Message.Body.ChargingStatusRes_isUsed = 1u;
        init_iso2_ChargingStatusResType(&exi_out->V2G_Message.Body.ChargingStatusRes);
        next_v2g_event = handle_iso_charging_status(conn);
    } else if (exi_xin->V2G_Message.Body.MeteringReceiptReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling MeteringReceiptReq");
        v2g->current_v2g_msg = V2G_METERING_RECEIPT_MSG;
        exi_out->V2G_Message.Body.MeteringReceiptRes_isUsed = 1u;
        init_iso2_MeteringReceiptResType(&exi_out->V2G_Message.Body.MeteringReceiptRes);
        next_v2g_event = handle_iso_metering_receipt(conn); // [V2G2-796]
    } else if (exi_xin->V2G_Message.Body.CertificateUpdateReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling CertificateUpdateReq");
        v2g->current_v2g_msg = V2G_CERTIFICATE_UPDATE_MSG;

        exi_out->V2G_Message.Body.CertificateUpdateRes_isUsed = 1u;
        init_iso2_CertificateUpdateResType(&exi_out->V2G_Message.Body.CertificateUpdateRes);
        next_v2g_event = handle_iso_certificate_update(conn); // [V2G2-556]
    } else if (exi_xin->V2G_Message.Body.CertificateInstallationReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling CertificateInstallationReq");
        v2g->current_v2g_msg = V2G_CERTIFICATE_INSTALLATION_MSG;
        mlog_i(LOG_TAG_V2G, "CertificateInstallation-phase started");

        exi_out->V2G_Message.Body.CertificateInstallationRes_isUsed = 1u;
        init_iso2_CertificateInstallationResType(&exi_out->V2G_Message.Body.CertificateInstallationRes);
        next_v2g_event = handle_iso_certificate_installation(conn); // [V2G2-553]
    } else if (exi_xin->V2G_Message.Body.CableCheckReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling CableCheckReq");
        v2g->current_v2g_msg = V2G_CABLE_CHECK_MSG;
        /* At first send mqtt charging phase signal to the customer interface */
        if (V2G_CHARGE_PARAMETER_DISCOVERY_MSG == v2g->last_v2g_msg) {
            mlog_i(LOG_TAG_V2G, "Isolation-phase started");
            secc_set_state(secc, GUN_INSULATION);
        }

        exi_out->V2G_Message.Body.CableCheckRes_isUsed = 1u;
        init_iso2_CableCheckResType(&exi_out->V2G_Message.Body.CableCheckRes);
        next_v2g_event = handle_iso_cable_check(conn); // [V2G2-583
    } else if (exi_xin->V2G_Message.Body.PreChargeReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling PreChargeReq");
        v2g->current_v2g_msg = V2G_PRE_CHARGE_MSG;
        /* At first send  mqtt charging phase signal to the customer interface */
        if (v2g->last_v2g_msg == V2G_CABLE_CHECK_MSG) {
            mlog_i(LOG_TAG_V2G, "Precharge-phase started");
            secc_set_state(secc, GUN_PRECHARGE);
        }

        exi_out->V2G_Message.Body.PreChargeRes_isUsed = 1u;
        init_iso2_PreChargeResType(&exi_out->V2G_Message.Body.PreChargeRes);
        next_v2g_event = handle_iso_pre_charge(conn); // [V2G2-586]
    } else if (exi_xin->V2G_Message.Body.WeldingDetectionReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling WeldingDetectionReq");
        v2g->current_v2g_msg = V2G_WELDING_DETECTION_MSG;
        if (v2g->last_v2g_msg != V2G_WELDING_DETECTION_MSG) {
            mlog_i(LOG_TAG_V2G, "Welding-phase started");
            secc->set_PWM_ratio(secc, 100);
        }
        exi_out->V2G_Message.Body.WeldingDetectionRes_isUsed = 1u;
        init_iso2_WeldingDetectionResType(&exi_out->V2G_Message.Body.WeldingDetectionRes);
        next_v2g_event = handle_iso_welding_detection(conn); // [V2G2-596]
    } else if (exi_xin->V2G_Message.Body.SessionStopReq_isUsed) {
        mlog_i(LOG_TAG_V2G, "Handling SessionStopReq");
        v2g->current_v2g_msg = V2G_SESSION_STOP_MSG;
        exi_out->V2G_Message.Body.SessionStopRes_isUsed = 1u;
        init_iso2_SessionStopResType(&exi_out->V2G_Message.Body.SessionStopRes);
        
        next_v2g_event = handle_iso_session_stop(conn); // [V2G2-570]
        if (v2g->next_client)
        {
            v2g_connect_t* conn = (v2g_connect_t*)v2g->next_client;
            v2g_tcp_client_exit(conn);
            v2g->next_client = NULL;
        }
    } else {
        mlog_i(LOG_TAG_V2G, "create_response_message: request type not found");
        next_v2g_event = V2G_EVENT_IGNORE_MSG;
    }

    mlog_i(LOG_TAG_V2G, "Current state: %s", iso_dc_states[v2g->state].description);

    // If next_v2g_event == V2G_EVENT_IGNORE_MSG, keep the current state and ignore msg
    if (next_v2g_event != V2G_EVENT_IGNORE_MSG) {
        v2g->last_v2g_msg = v2g->current_v2g_msg;

        /* Configure session id */
        memcpy(exi_out->V2G_Message.Header.SessionID.bytes, &v2g->evse_session_id, iso2_sessionIDType_BYTES_SIZE);
        /* We always set bytesLen to iso2_MessageHeaderType_SessionID_BYTES_SIZE */
        exi_out->V2G_Message.Header.SessionID.bytesLen = iso2_sessionIDType_BYTES_SIZE;
    }

    return next_v2g_event;
}