
#include "v2g_context.h"

static const char* dinResponse[] = {
    "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",
    "EVSE Present Voltage To Low",
    "Metering Signature Not Valid",
    "Wrong Energy Transfer Type"
};

enum din_state_id {
    WAIT_FOR_SESSIONSETUP = 0,
    WAIT_FOR_SERVICEDISCOVERY,
    WAIT_FOR_PAYMENTSERVICESELECTION,
    WAIT_FOR_AUTHORIZATION,
    WAIT_FOR_CHARGEPARAMETERDISCOVERY,
    WAIT_FOR_CABLECHECK,
    WAIT_FOR_PRECHARGE,
    WAIT_FOR_PRECHARGE_POWERDELIVERY,
    WAIT_FOR_CURRENTDEMAND,
    WAIT_FOR_CURRENTDEMAND_POWERDELIVERY,
    WAIT_FOR_WELDINGDETECTION_SESSIONSTOP,
    WAIT_FOR_SESSIONSTOP,
    WAIT_FOR_TERMINATED_SESSION
};

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

static const struct din_state din_states[] = {
    /* [V2G-DC-437]  Expected req msg after supportedAppProtocolRes */
    [WAIT_FOR_SESSIONSETUP] = {"Waiting for SessionSetupReq", 1 << V2G_SESSION_SETUP_MSG},
    /* [V2G-DC-439] Expected req msg after SessionSetupRes */
    [WAIT_FOR_SERVICEDISCOVERY] = {"Waiting for ServiceDiscoveryReq, SessionStopReq", 1 << V2G_SERVICE_DISCOVERY_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-441] Expected req msg after ServiceDiscoveryRes */
    [WAIT_FOR_PAYMENTSERVICESELECTION] = {"Waiting for ServicePaymentSelectionReq, SessionStopReq", 1 << V2G_PAYMENT_SERVICE_SELECTION_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-444] [V2G-DC-497] Expected req msg after ServicePaymentSelectionRes */
    [WAIT_FOR_AUTHORIZATION] = {"Waiting for ContractAuthenticationReq, SessionStopReq", 1 << V2G_AUTHORIZATION_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-498], [V2G-DC-495] Expected req msg after ContractAuthenticationRes*/
    [WAIT_FOR_CHARGEPARAMETERDISCOVERY] = {"Waiting for ChargeParameterDiscoveryReq, SessionStopReq", 1 << V2G_CHARGE_PARAMETER_DISCOVERY_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-453], [V2G-DC-499] Expected req msg after ChargeParameterDiscoveryRes, CableCheckRes */
    [WAIT_FOR_CABLECHECK] = {"Waiting for CableCheckReq, SessionStopReq",  1 << V2G_CABLE_CHECK_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-455] Expected req msgs after CableCheckRes */
    [WAIT_FOR_PRECHARGE] = {"Waiting for PreChargeReq, SessionStopReq",  1 << V2G_PRE_CHARGE_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-458] Expected req msg after PreChargeRes */
    [WAIT_FOR_PRECHARGE_POWERDELIVERY] = {"Waiting for PowerDeliveryReq, PreChargeReq, SessionStopRes", 1 << V2G_POWER_DELIVERY_MSG | 1 << V2G_PRE_CHARGE_MSG | 1 << V2G_SESSION_STOP_MSG},
    /* [V2G-DC-462] Expected req msg after PowerDeliveryRes (Ready to Charge = true) */
    [WAIT_FOR_CURRENTDEMAND] = {"Waiting for CurrentDemandReq", 1 << V2G_CURRENT_DEMAND_MSG},
    /* [V2G-DC-462], [V2G-DC-465] Expected req msg after PowerDeliveryRes (Ready to Charge = true), CurrentDemandRes */
    [WAIT_FOR_CURRENTDEMAND_POWERDELIVERY] = {"Waiting for CurrentDemandReq, PowerDeliveryReq", 1 << V2G_CURRENT_DEMAND_MSG | 1 << V2G_POWER_DELIVERY_MSG},
    /* [V2G-DC-459], [V2G-DC-469] Expected req msg after PowerDeliveryRes, WeldingDetectionRes */
    [WAIT_FOR_WELDINGDETECTION_SESSIONSTOP] = {"Waiting for WeldingDetectionReq, SessionStopReq ", 1 << V2G_WELDING_DETECTION_MSG | 1 << V2G_SESSION_STOP_MSG},
    [WAIT_FOR_SESSIONSTOP] = {"Waiting for SessionStopReq", 1 << V2G_SESSION_STOP_MSG},
    [WAIT_FOR_TERMINATED_SESSION] = {"Terminate session", 0}
};

static int publish_DIN_DcEvStatus(v2g_connect_t* conn, struct din_DC_EVStatusType* status)
{
    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;
    switch(status->EVErrorCode)
    {
        case din_DC_EVErrorCodeType_FAILED_RESSTemperatureInhibit: mlog_i(LOG_TAG_V2G, "EV battery overtemp!\n"); break;
        case din_DC_EVErrorCodeType_FAILED_EVShiftPosition: mlog_i(LOG_TAG_V2G, "EV is not in park!\n"); break;
        case din_DC_EVErrorCodeType_FAILED_ChargerConnectorLockFault: mlog_i(LOG_TAG_V2G, "EV ELock failed!\n"); secc->GUN_Error = GUN_ELECLOCK_STALL; break;
        case din_DC_EVErrorCodeType_FAILED_EVRESSMalfunction: mlog_i(LOG_TAG_V2G, "EV RESS Fault!\n");  secc->GUN_Error = BMS_CONTACTOR_FAULT;break;
        case din_DC_EVErrorCodeType_FAILED_ChargingCurrentdifferential: mlog_i(LOG_TAG_V2G, "EV ChargingCurrentdifferential!\n");  secc->GUN_Error = BMS_CURRENT_MISTACH;break;
        case din_DC_EVErrorCodeType_FAILED_ChargingVoltageOutOfRange: mlog_i(LOG_TAG_V2G, "EV ChargingVoltageOutOfRange!\n");  secc->GUN_Error = BMS_VOLTAGE_MISTACH;break;
        case din_DC_EVErrorCodeType_FAILED_ChargingSystemIncompatibility: mlog_i(LOG_TAG_V2G, "EV ChargingSystemIncompatibility!\n");  secc->GUN_Error = BMS_VOLTAGE_MISTACH;break;
    }
    
    return 0;
}

static void fill_din_DC_EVSEStatus(v2g_connect_t* conn, struct din_DC_EVSEStatusType* status, enum charging_phase PHASE)
{
    v2g_context_t *v2g = (v2g_context_t*)conn->v2g;
    secc_port_t *secc = v2g->secc;
    status->EVSEIsolationStatus = (din_isolationLevelType)v2g->evse_isolation_status;
    status->EVSEIsolationStatus_isUsed = 1;
    status->NotificationMaxDelay = 0;
    status->EVSENotification = din_EVSENotificationType_None;
    status->EVSEStatusCode = (secc->GUN_Error == 0?  (din_DC_EVSEStatusCodeType)v2g->evse_status_code[PHASE] : din_DC_EVSEStatusCodeType_EVSE_EmergencyShutdown);
    if (secc->manul_stop == true) status->EVSEStatusCode = din_DC_EVSEStatusCodeType_EVSE_Shutdown;
    if (secc_should_stop(secc)==1 && PHASE == PHASE_CHARGE) { status->EVSEStatusCode = din_DC_EVSEStatusCodeType_EVSE_Shutdown; }
}

static void load_din_physical_value(struct din_PhysicalValueType* out, din_unitSymbolType type,  float value)
{
    out->Unit_isUsed = 1;
    switch(type)
    {
        case din_unitSymbolType_h:  {out->Unit= din_unitSymbolType_h;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
        case din_unitSymbolType_m:  {out->Unit= din_unitSymbolType_m;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
        case din_unitSymbolType_s:  {out->Unit= din_unitSymbolType_s;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
        case din_unitSymbolType_A:  {out->Unit= din_unitSymbolType_A;  out->Value = (uint16_t)(value*10); out->Multiplier = -1;}break;
        case din_unitSymbolType_V:  {out->Unit= din_unitSymbolType_V;  out->Value = (uint16_t)(value*10); out->Multiplier = -1;}break;
        case din_unitSymbolType_W:  {out->Unit= din_unitSymbolType_W;  out->Value = (uint16_t)(value/100); out->Multiplier = 2;}break;
        case din_unitSymbolType_Wh: {out->Unit= din_unitSymbolType_Wh; out->Value = (uint16_t)(value/1000); out->Multiplier = 3;}break;
        default :                   {out->Unit= din_unitSymbolType_h;  out->Value = (uint16_t)(value); out->Multiplier = 0;}break;
    }
}

static din_responseCodeType din_validate_state(int state, enum V2gMsgTypeId current_v2g_msg) 
{
    return (din_states[state].allowed_requests & (1 << current_v2g_msg)) ? din_responseCodeType_OK : din_responseCodeType_FAILED_SequenceError;
}

static int din_validate_response_code(din_responseCodeType* const din_response_code, 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;
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    din_responseCodeType response_code_tmp;

    if (secc->GUN_State < GUN_SLACOK) 
    {
        mlog_e(LOG_TAG_V2G, "Connection is terminated. Abort charging\n");
        return V2G_EVENT_TERMINATE_CONNECTION;
    }

    /* If alarm abort or emergency shutdown has occurred */
    if ( secc->GUN_Error != 0 ) {
        mlog_e(LOG_TAG_V2G, "secc->GUN_Error=%d\n", secc->GUN_Error);
        *din_response_code = din_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 = din_validate_state(v2g->state, v2g->current_v2g_msg);
    if (response_code_tmp == din_responseCodeType_FAILED_SequenceError )
    {
        printd("state:%d, current_msg:%d, allowed_requests:%08x\n", v2g->state, v2g->current_v2g_msg, din_states[v2g->state].allowed_requests);
    }
    *din_response_code = (response_code_tmp >= din_responseCodeType_FAILED) ? response_code_tmp : *din_response_code;

    /* [V2G-DC-391]: check whether the session id matches the expected one of the active session */
    *din_response_code = ((v2g->current_v2g_msg != V2G_SESSION_SETUP_MSG) && (v2g->evse_session_id != v2g->evcc_session_id))? din_responseCodeType_FAILED_UnknownSession : *din_response_code;

    if ((v2g->terminate_connection_on_failed_response == true) && (*din_response_code >= din_responseCodeType_FAILED)) 
    {
        nextEvent = V2G_EVENT_SEND_AND_TERMINATE; // [V2G-DC-665]
    }

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

    return nextEvent;
}

static int handle_din_session_setup(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_SessionSetupReqType* req = (struct din_SessionSetupReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.SessionSetupReq;
    struct din_SessionSetupResType* res = (struct din_SessionSetupResType*)&conn->dinEXIDocument_out.V2G_Message.Body.SessionSetupRes;
    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;
    char buffer[din_evccIDType_BYTES_SIZE * 2 + din_evccIDType_BYTES_SIZE - 1 + 4]; /* 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);

    /* 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->ResponseCode = din_responseCodeType_OK_NewSessionEstablished;
    res->EVSEID.bytesLen = snprintf(res->EVSEID.bytes, din_evseIDType_BYTES_SIZE, "%s", config->CCU_SN);
    res->DateTimeNow = time(NULL);
    res->DateTimeNow_isUsed = 1;
    nextEvent = din_validate_response_code(&res->ResponseCode, conn);
    /* Set next expected req msg */
    v2g->state = WAIT_FOR_SERVICEDISCOVERY; // [V2G-DC-438]
    return nextEvent;
}

static int handle_din_service_discovery(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_ServiceDiscoveryReqType* req = (struct din_ServiceDiscoveryReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.ServiceDiscoveryReq;
    struct din_ServiceDiscoveryResType* res = (struct din_ServiceDiscoveryResType*)&conn->dinEXIDocument_out.V2G_Message.Body.ServiceDiscoveryRes;
    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;

    res->ResponseCode = din_responseCodeType_OK;                                        // [V2G-DC-388]
    res->ChargeService.ServiceTag.ServiceID = V2G_SERVICE_ID_CHARGING;                  // ID of the charge service
    res->ChargeService.ServiceTag.ServiceCategory = din_serviceCategoryType_EVCharging; // Is fixed
    res->ChargeService.ServiceTag.ServiceName_isUsed = 0;   // [V2G-DC-628] Shall not be used in DIN 70121
    res->ChargeService.ServiceTag.ServiceScope_isUsed = 0;  // [V2G-DC-629] Shall not be used in DIN 70121
    res->ChargeService.FreeService = 0;
    res->ChargeService.EnergyTransferType = (din_EVSESupportedEnergyTransferType)iso2_EnergyTransferModeType_DC_extended;

    res->ServiceList_isUsed = 0; // Shall not be used in DIN 70121
    // In the scope of DIN 70121 only ExternalPayment shall be used.
    res->PaymentOptions.PaymentOption.array[0] = din_paymentOptionType_ExternalPayment;
    res->PaymentOptions.PaymentOption.arrayLen = 1;
    /* Check the current response code and check if no external error has occurred */
    nextEvent = din_validate_response_code(&res->ResponseCode, conn);
    /* Set next expected req msg */
    v2g->state = WAIT_FOR_PAYMENTSERVICESELECTION; // [V2G-DC-441]
    return nextEvent;
}

static int handle_din_service_payment_selection(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_ServicePaymentSelectionReqType* req = (struct din_ServicePaymentSelectionReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.ServicePaymentSelectionReq;
    struct din_ServicePaymentSelectionResType* res = (struct din_ServicePaymentSelectionResType*)&conn->dinEXIDocument_out.V2G_Message.Body.ServicePaymentSelectionRes;
    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;

    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]
    res->ResponseCode = (req->SelectedPaymentOption == din_paymentOptionType_ExternalPayment)? res->ResponseCode : din_responseCodeType_FAILED_PaymentSelectionInvalid; // [V2G-DC-395]
    res->ResponseCode = (req->SelectedServiceList.SelectedService.arrayLen == (uint16_t)1 && (req->SelectedServiceList.SelectedService.array[0].ServiceID == 1)) ? res->ResponseCode : din_responseCodeType_FAILED_ServiceSelectionInvalid; // [V2G-DC-396] [V2G-DC-635] (List shall be limited to 1)

    /* Check the current response code and check if no external error has occurred */
    nextEvent = din_validate_response_code(&res->ResponseCode, conn);
    /* Set next expected req msg */
    v2g->state = WAIT_FOR_AUTHORIZATION; // [V2G-DC-444]
    return nextEvent;
}

static int handle_din_contract_authentication(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_ContractAuthenticationReqType* req = (struct din_ContractAuthenticationReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.ContractAuthenticationReq;
    struct din_ContractAuthenticationResType* res = (struct din_ContractAuthenticationResType*)&conn->dinEXIDocument_out.V2G_Message.Body.ContractAuthenticationRes;
    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;
    /* Fill the EVSE response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]

    res->EVSEProcessing = (secc->GUN_State < GUN_AUTHORIZED ? din_EVSEProcessingType_Ongoing : din_EVSEProcessingType_Finished);

    /* Check the current response code and check if no external error has occurred */
    nextEvent = din_validate_response_code(&res->ResponseCode, conn);
    /* Set next expected req msg */
    v2g->state = (res->EVSEProcessing == din_EVSEProcessingType_Ongoing)? WAIT_FOR_AUTHORIZATION : WAIT_FOR_CHARGEPARAMETERDISCOVERY; // [V2G-DC-444], [V2G-DC-497]

    return nextEvent;
}

static int handle_din_charge_parameter(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_ChargeParameterDiscoveryReqType* req = (struct din_ChargeParameterDiscoveryReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.ChargeParameterDiscoveryReq;
    struct din_ChargeParameterDiscoveryResType* res = (struct din_ChargeParameterDiscoveryResType*)&conn->dinEXIDocument_out.V2G_Message.Body.ChargeParameterDiscoveryRes;
    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;

    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]
    res->AC_EVSEChargeParameter_isUsed = 0u;

    if (req->EVRequestedEnergyTransferType != din_EVRequestedEnergyTransferType_DC_extended) 
    {
        res->ResponseCode = din_responseCodeType_FAILED_WrongEnergyTransferType; // [V2G-DC-397] Failed reponse code is logged at the end of the function
        mlog_e(LOG_TAG_V2G, "Selected energy transfer mode %d is invalid");
        secc_set_error(secc, GUN_PARAMETERS_FAULT);
    }else{
        mlog_d(LOG_TAG_V2G, "Selected energy transfer mode: din_EVRequestedEnergyTransferType_DC_extended");
    }

    res->ResponseCode = (req->AC_EVChargeParameter_isUsed == 1)? din_responseCodeType_FAILED_WrongChargeParameter : res->ResponseCode; // [V2G-DC-398]

    if (req->DC_EVChargeParameter_isUsed)
    {
        secc->EVCC_maxI = calc_physical_value(req->DC_EVChargeParameter.EVMaximumCurrentLimit.Value, req->DC_EVChargeParameter.EVMaximumCurrentLimit.Multiplier);
        secc->EVCC_maxV = calc_physical_value(req->DC_EVChargeParameter.EVMaximumVoltageLimit.Value, req->DC_EVChargeParameter.EVMaximumVoltageLimit.Multiplier);
        if (req->DC_EVChargeParameter.EVMaximumPowerLimit_isUsed) 
        { secc->EVCC_maxP = calc_physical_value(req->DC_EVChargeParameter.EVMaximumPowerLimit.Value, req->DC_EVChargeParameter.EVMaximumPowerLimit.Multiplier) / 1000; }
        if (req->DC_EVChargeParameter.EVEnergyCapacity_isUsed) 
        { secc->request_KWh = calc_physical_value(req->DC_EVChargeParameter.EVEnergyCapacity.Value, req->DC_EVChargeParameter.EVEnergyCapacity.Multiplier) / 1000; }
        if (req->DC_EVChargeParameter.EVEnergyRequest_isUsed) 
        { secc->request_KWh = calc_physical_value(req->DC_EVChargeParameter.EVEnergyRequest.Value, req->DC_EVChargeParameter.EVEnergyRequest.Multiplier) / 1000; }
        if (req->DC_EVChargeParameter.BulkSOC_isUsed) { secc->SOC = req->DC_EVChargeParameter.BulkSOC; }
        if (req->DC_EVChargeParameter.FullSOC_isUsed) { secc->SOC = req->DC_EVChargeParameter.FullSOC; }
    }
    
    /* DC_EVSEChargeParameter */
    res->EVSEProcessing = (v2g->evse_processing[PHASE_PARAMETER] == iso2_EVSEProcessingType_Finished)? din_EVSEProcessingType_Finished : din_EVSEProcessingType_Ongoing;

    fill_din_DC_EVSEStatus(conn, &res->DC_EVSEChargeParameter.DC_EVSEStatus, PHASE_PARAMETER);

    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance, din_unitSymbolType_A, 1); 
    res->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance_isUsed = 0;

    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered, din_unitSymbolType_Wh,  0);
    res->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered_isUsed = 0;

    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEMaximumPowerLimit, din_unitSymbolType_W, secc->SECC_maxP);
    res->DC_EVSEChargeParameter.EVSEMaximumPowerLimit_isUsed = 1;
    
    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEMaximumCurrentLimit, din_unitSymbolType_A, secc->SECC_maxI);
    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEMinimumCurrentLimit, din_unitSymbolType_A, secc->SECC_minI);
    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEMaximumVoltageLimit, din_unitSymbolType_V, secc->SECC_maxV);
    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEMinimumVoltageLimit, din_unitSymbolType_V, secc->SECC_minV);
    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEPeakCurrentRipple, din_unitSymbolType_A, 1);
    load_din_physical_value(&res->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered, din_unitSymbolType_Wh, secc->request_KWh*1000);
    res->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered_isUsed = 1;
    res->DC_EVSEChargeParameter_isUsed = 1u;
    res->AC_EVSEChargeParameter_isUsed = 0u;

    // res->EVSEChargeParameter.noContent
    res->EVSEChargeParameter_isUsed = 0;
    
    res->SAScheduleList.SAScheduleTuple.arrayLen = 1;
    res->SAScheduleList.SAScheduleTuple.array[0].SalesTariff_isUsed = 0; // In the scope of DIN 70121, this optional element shall not be used. [V2G-DC-554]
    res->SAScheduleList.SAScheduleTuple.array[0].SAScheduleTupleID = 1;
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleID = 1; 
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.arrayLen = 1;
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].PMax = SHRT_MAX;
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval.duration = 86400; // Must cover 24 hours
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval.duration_isUsed = 1; // Must be used in DIN
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval.start = 0;
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].RelativeTimeInterval_isUsed = 1;
    res->SAScheduleList.SAScheduleTuple.array[0].PMaxSchedule.PMaxScheduleEntry.array[0].TimeInterval_isUsed = 0; // no content
    res->SAScheduleList_isUsed = 1;

    // res->SASchedules.noContent
    res->SASchedules_isUsed = 0;
    /* Check the current response code and check if no external error has occurred */
    nextEvent = din_validate_response_code(&res->ResponseCode, conn);

    if (res->EVSEProcessing == din_EVSEProcessingType_Finished)
    {
        if (res->DC_EVSEChargeParameter.DC_EVSEStatus.EVSEStatusCode != din_DC_EVSEStatusCodeType_EVSE_Ready) {
            mlog_d(LOG_TAG_V2G, "EVSE wants to finish charge parameter phase, but status code is not set to 'ready' (1)");
        }
        v2g->state = WAIT_FOR_CABLECHECK; // [V2G-DC-453]
    }else{
        v2g->state = WAIT_FOR_CHARGEPARAMETERDISCOVERY; // [V2G-DC-498]
    }
    
    secc_set_state(secc, GUN_PARAMETERS);
    return nextEvent;
}

static int handle_din_cable_check(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_CableCheckReqType* req = (struct din_CableCheckReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.CableCheckReq;
    struct din_CableCheckResType* res = (struct din_CableCheckResType*)&conn->dinEXIDocument_out.V2G_Message.Body.CableCheckRes;
    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;

    /* Now fill the evse response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]
    fill_din_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_ISOLATION);
    res->EVSEProcessing = (v2g->evse_processing[PHASE_ISOLATION] == iso2_EVSEProcessingType_Finished)? din_EVSEProcessingType_Finished : din_EVSEProcessingType_Ongoing;
    res->DC_EVSEStatus.EVSEStatusCode = (res->EVSEProcessing == din_EVSEProcessingType_Finished)? din_DC_EVSEStatusCodeType_EVSE_Ready:(din_DC_EVSEStatusCodeType)v2g->evse_status_code[PHASE_ISOLATION];

    /* Set next expected req msg */
    if ((res->EVSEProcessing == din_EVSEProcessingType_Finished) &&
        (res->DC_EVSEStatus.EVSEIsolationStatus_isUsed == (unsigned int)1) &&
        ((res->DC_EVSEStatus.EVSEIsolationStatus == din_isolationLevelType_Valid) ||
         (res->DC_EVSEStatus.EVSEIsolationStatus == din_isolationLevelType_Warning)) &&
        (res->DC_EVSEStatus.EVSEStatusCode == din_DC_EVSEStatusCodeType_EVSE_Ready)) {
        v2g->state = WAIT_FOR_PRECHARGE; // [V2G-DC-499]
    } else {
        if ((res->EVSEProcessing == din_EVSEProcessingType_Finished) &&
            ((res->DC_EVSEStatus.EVSEIsolationStatus_isUsed == (unsigned int)0) ||
             ((res->DC_EVSEStatus.EVSEIsolationStatus != din_isolationLevelType_Valid) &&
              (res->DC_EVSEStatus.EVSEIsolationStatus != din_isolationLevelType_Warning)))) {
            mlog_e(LOG_TAG_V2G, "EVSE wants to finish cable check phase, but either status code is not set to 'ready' (1) or isolation status is not valid");
        }
        v2g->state = WAIT_FOR_CABLECHECK; // [V2G-DC-455]
    }

    return nextEvent;
}

static int handle_din_pre_charge(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_PreChargeReqType* req = (struct din_PreChargeReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.PreChargeReq;
    struct din_PreChargeResType* res = (struct din_PreChargeResType*)&conn->dinEXIDocument_out.V2G_Message.Body.PreChargeRes;
    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;

    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);
    printi("request_voltage:%f, request_current:%f, presentVoltage:%f\n", secc->request_voltage, secc->request_current, secc->VMeters);    
    /* Now fill the EVSE response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]
    fill_din_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_PRECHARGE);
    load_din_physical_value(&res->EVSEPresentVoltage, din_unitSymbolType_V, secc->VMeters);

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

    /* Set next expected req msg */
    v2g->state = WAIT_FOR_PRECHARGE_POWERDELIVERY; // [V2G-DC-458]

    return nextEvent;
}

static int handle_din_power_delivery(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_PowerDeliveryReqType* req = (struct din_PowerDeliveryReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.PowerDeliveryReq;
    struct din_PowerDeliveryResType* res = (struct din_PowerDeliveryResType*)&conn->dinEXIDocument_out.V2G_Message.Body.PowerDeliveryRes;
    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;

    secc_set_state(secc, GUN_CHARGING);

    printd("ReadyToChargeState=%d, ChargingProfile_isUsed:%d, DC_EVPowerDeliveryParameter_isUsed:%d, EVPowerDeliveryParameter_isUsed:%d\n", 
        req->ReadyToChargeState, req->ChargingProfile_isUsed, req->DC_EVPowerDeliveryParameter_isUsed, req->EVPowerDeliveryParameter_isUsed);

    if (req->ReadyToChargeState == (int)0) {
        secc_request_power(secc, POWER_REQUEST_SHUTDOWN, secc->request_voltage, secc->request_current);
        v2g->evse_status_code[PHASE_CHARGE] = din_DC_EVSEStatusCodeType_EVSE_Shutdown;
        v2g->evse_processing[PHASE_CHARGE] = din_EVSEProcessingType_Finished;
    } else {
        secc_request_power(secc, POWER_REQUEST_CONST_VOLTAGE, secc->request_voltage, secc->request_current);
        v2g->evse_status_code[PHASE_CHARGE] = din_DC_EVSEStatusCodeType_EVSE_Ready;
        v2g->evse_processing[PHASE_CHARGE] = din_EVSEProcessingType_Finished;
    }
    /* Now fill the evse response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]

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

    /* Check response code */
    if (req->ChargingProfile_isUsed == (unsigned int)1) {
        /* Check the selected SAScheduleTupleID */
        res->ResponseCode = (req->ChargingProfile.SAScheduleTupleID != (int16_t)1)? din_responseCodeType_FAILED_TariffSelectionInvalid : res->ResponseCode; // [V2G-DC-400]
        int idx;
        for (idx = 0; idx < req->ChargingProfile.ProfileEntry.arrayLen; idx++) {
            bool entry_found = (req->ChargingProfile.ProfileEntry.array[idx].ChargingProfileEntryStart <= (uint32_t)1);
            if ((entry_found == false) || (req->ChargingProfile.ProfileEntry.array[idx].ChargingProfileEntryMaxPower > secc->SECC_maxP))
            {
                // res->ResponseCode = din_responseCodeType_FAILED_ChargingProfileInvalid; //[V2G-DC-399]. Currently commented to increase compatibility with EV'S
                mlog_e(LOG_TAG_V2G, "EV's charging profile is invalid (ChargingProfileEntryMaxPower %d too high)!", req->ChargingProfile.ProfileEntry.array[idx].ChargingProfileEntryMaxPower);
                break;
            }
        }
    }
    res->ResponseCode = ((req->ReadyToChargeState == (int)1) && (res->DC_EVSEStatus.EVSEStatusCode != din_DC_EVSEStatusCodeType_EVSE_Ready)) ? din_responseCodeType_FAILED_PowerDeliveryNotApplied : res->ResponseCode; // [V2G-DC-401]

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

    /* Set next expected req msg */
    if ((req->ReadyToChargeState == (int)1) && (v2g->last_v2g_msg != V2G_CURRENT_DEMAND_MSG)) {
        v2g->state = WAIT_FOR_CURRENTDEMAND; // [V2G-DC-462]
    } else {
        /* abort charging session if EV is ready to charge after current demand phase */
        if (req->ReadyToChargeState == (int)1) 
        {
            res->ResponseCode = din_responseCodeType_FAILED;
            nextEvent = V2G_EVENT_SEND_AND_TERMINATE;
        }
        v2g->state = WAIT_FOR_WELDINGDETECTION_SESSIONSTOP; // [V2G-DC-459]
    }

    return nextEvent;
}

static int handle_din_current_demand(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_CurrentDemandReqType* req = (struct din_CurrentDemandReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.CurrentDemandReq;
    struct din_CurrentDemandResType* res = (struct din_CurrentDemandResType*)&conn->dinEXIDocument_out.V2G_Message.Body.CurrentDemandRes;
    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;

    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);

    /* Now fill the evse response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]
    fill_din_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_CHARGE);

    res->EVSECurrentLimitAchieved = 1;
    res->EVSEVoltageLimitAchieved = 1;
    res->EVSEPowerLimitAchieved = 1;

    res->EVSEMaximumCurrentLimit_isUsed = 1;
    load_din_physical_value(&res->EVSEMaximumCurrentLimit, din_unitSymbolType_A, secc->SECC_maxI);
    res->EVSEMaximumVoltageLimit_isUsed = 1;
    load_din_physical_value(&res->EVSEMaximumVoltageLimit, din_unitSymbolType_V, secc->SECC_maxV);
    res->EVSEMaximumPowerLimit_isUsed = 1;
    load_din_physical_value(&res->EVSEMaximumPowerLimit, din_unitSymbolType_W, secc->SECC_maxP);
    
    load_din_physical_value(&res->EVSEPresentCurrent, din_unitSymbolType_A, secc->IMeters);
    load_din_physical_value(&res->EVSEPresentVoltage, din_unitSymbolType_V, secc->VMeters);


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

    /* Set next expected req msg */
    v2g->state = WAIT_FOR_CURRENTDEMAND_POWERDELIVERY; // [V2G-DC-465]

    return nextEvent;
}

static int handle_din_welding_detection(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_WeldingDetectionReqType* req = (struct din_WeldingDetectionReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.WeldingDetectionReq;
    struct din_WeldingDetectionResType* res = (struct din_WeldingDetectionResType*)&conn->dinEXIDocument_out.V2G_Message.Body.WeldingDetectionRes;
    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;

    /* TODO: Waiting for CP-State B [V2G-DC-556]. */
    secc_request_power(secc, POWER_REQUEST_SHUTDOWN, .0f, .0f);

    /* Now fill the evse response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]
    fill_din_DC_EVSEStatus(conn, &res->DC_EVSEStatus, PHASE_WELDING);

    load_din_physical_value(&res->EVSEPresentVoltage, din_unitSymbolType_V, secc->VMeters);

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

    /* Set next expected req msg */
    v2g->state = WAIT_FOR_WELDINGDETECTION_SESSIONSTOP; // [V2G-DC-469]

    return nextEvent;
}

static int handle_din_session_stop(v2g_connect_t* conn)
{
    enum v2g_event nextEvent = V2G_EVENT_NO_EVENT;
    struct din_SessionStopReqType* req = (struct din_SessionStopReqType*)&conn->dinEXIDocument_xin.V2G_Message.Body.SessionStopReq;
    struct din_SessionStopResType* res = (struct din_SessionStopResType*)&conn->dinEXIDocument_out.V2G_Message.Body.SessionStopRes;
    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;

    secc_set_state(secc, GUN_STOPPING);

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

    /* Now fill the EVSE response message */
    res->ResponseCode = din_responseCodeType_OK; // [V2G-DC-388]

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

    /* Setuo dlink action */
    // conn->dlink_action = MQTT_DLINK_ACTION_TERMINATE;

    /* Set next expected req msg */
    v2g->state = WAIT_FOR_TERMINATED_SESSION; // [V2G-DC-451]

    /* Check the current response code and check if no external error has occurred */
    return V2G_EVENT_SEND_AND_TERMINATE; // Charging must be terminated after sending the response message.

}


int v2g_handle_din_request(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;

    int next_v2g_event = V2G_EVENT_TERMINATE_CONNECTION;
    struct din_exiDocument *exi_xin = &conn->dinEXIDocument_xin;
    struct din_exiDocument *exi_out = &conn->dinEXIDocument_out;  
    memset(exi_xin, 0, sizeof(struct din_exiDocument));
    int rv = decode_din_exiDocument(&conn->stream, exi_xin);
    struct din_MessageHeaderType* hdr = &exi_xin->V2G_Message.Header;
    memcpy(&v2g->evcc_session_id, &hdr->SessionID.bytes, hdr->SessionID.bytesLen);
    // printline((uint8_t*)&v2g->evcc_session_id, 8, "evcc_session_id");
    // printd("decode_din_exiDocument=%d, xin.V2G_Message.Header.SessionID.bytesLen=%d\n", rv , hdr->SessionID.bytesLen);
    init_din_exiDocument(exi_out);
    init_din_MessageHeaderType(&exi_out->V2G_Message.Header);
    exi_out->V2G_Message.Header.SessionID.bytesLen = 8;
    init_din_BodyType(&exi_out->V2G_Message.Body);
    // === Start request handling ===
    if (exi_xin->V2G_Message.Body.SessionSetupReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling SessionSetupReq");
        v2g->current_v2g_msg = V2G_SESSION_SETUP_MSG;
        exi_out->V2G_Message.Body.SessionSetupRes_isUsed = 1u;
        init_din_SessionSetupResType(&exi_out->V2G_Message.Body.SessionSetupRes);
        /* Handle v2g msg */
        next_v2g_event = handle_din_session_setup(conn);
    } else if (exi_xin->V2G_Message.Body.ServiceDiscoveryReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling ServiceDiscoveryReq");
        v2g->current_v2g_msg = V2G_SERVICE_DISCOVERY_MSG;
        exi_out->V2G_Message.Body.ServiceDiscoveryRes_isUsed = 1u;
        init_din_ServiceDiscoveryResType(&exi_out->V2G_Message.Body.ServiceDiscoveryRes);
        next_v2g_event = handle_din_service_discovery(conn);
    } else if (exi_xin->V2G_Message.Body.ServicePaymentSelectionReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling PaymentServiceSelectionReq");
        v2g->current_v2g_msg = V2G_PAYMENT_SERVICE_SELECTION_MSG;
        exi_out->V2G_Message.Body.ServicePaymentSelectionRes_isUsed = 1u;
        init_din_ServicePaymentSelectionResType(&exi_out->V2G_Message.Body.ServicePaymentSelectionRes);
        next_v2g_event = handle_din_service_payment_selection(conn);
    } else if (exi_xin->V2G_Message.Body.ContractAuthenticationReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling ContractAuthenticationReq");
        v2g->current_v2g_msg = V2G_AUTHORIZATION_MSG;
        if (v2g->last_v2g_msg != V2G_AUTHORIZATION_MSG) {
            mlog_i(LOG_TAG_V2G, "Auth-phase started");
        }
        exi_out->V2G_Message.Body.ContractAuthenticationRes_isUsed = 1u;
        init_din_ContractAuthenticationResType(&exi_out->V2G_Message.Body.ContractAuthenticationRes);
        next_v2g_event = handle_din_contract_authentication(conn);
    } else if (exi_xin->V2G_Message.Body.PaymentDetailsReq_isUsed) {
        mlog_e(LOG_TAG_V2G, "PaymentDetails request is not supported in DIN 70121");
        v2g->current_v2g_msg = V2G_UNKNOWN_MSG;
        // next_v2g_event = V2G_EVENT_IGNORE_MSG;
    } else if (exi_xin->V2G_Message.Body.ServiceDetailReq_isUsed) {
        mlog_e(LOG_TAG_V2G, "ServiceDetail request is not supported in DIN 70121");
        v2g->current_v2g_msg = V2G_UNKNOWN_MSG;
        // next_v2g_event = V2G_EVENT_IGNORE_MSG;
    } else if (exi_xin->V2G_Message.Body.ChargeParameterDiscoveryReq_isUsed) {
        mlog_d(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_din_ChargeParameterDiscoveryResType(&exi_out->V2G_Message.Body.ChargeParameterDiscoveryRes);
        next_v2g_event = handle_din_charge_parameter(conn);
    } else if (exi_xin->V2G_Message.Body.CableCheckReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling CableCheckReq");
        v2g->current_v2g_msg = V2G_CABLE_CHECK_MSG;
        if (v2g->last_v2g_msg == V2G_CHARGE_PARAMETER_DISCOVERY_MSG) {
            mlog_i(LOG_TAG_V2G, "Isolation-phase started");
            secc_set_state(secc, GUN_INSULATION);
        }
        exi_out->V2G_Message.Body.CableCheckRes_isUsed = 1u;
        init_din_CableCheckResType(&exi_out->V2G_Message.Body.CableCheckRes);
        next_v2g_event = handle_din_cable_check(conn);
    } else if (exi_xin->V2G_Message.Body.PreChargeReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling PreChargeReq");
        v2g->current_v2g_msg = V2G_PRE_CHARGE_MSG;
        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_din_PreChargeResType(&exi_out->V2G_Message.Body.PreChargeRes);
        next_v2g_event = handle_din_pre_charge(conn);
    } else if (exi_xin->V2G_Message.Body.PowerDeliveryReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling PowerDeliveryReq");
        v2g->current_v2g_msg = V2G_POWER_DELIVERY_MSG;
        if (v2g->last_v2g_msg == V2G_PRE_CHARGE_MSG) {
            mlog_i(LOG_TAG_V2G, "Charge-phase started");
        }
        exi_out->V2G_Message.Body.PowerDeliveryRes_isUsed = 1u;
        init_din_PowerDeliveryResType(&exi_out->V2G_Message.Body.PowerDeliveryRes);
        next_v2g_event = handle_din_power_delivery(conn);
    } else if (exi_xin->V2G_Message.Body.CurrentDemandReq_isUsed) {
        mlog_d(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_din_CurrentDemandResType(&exi_out->V2G_Message.Body.CurrentDemandRes);
        next_v2g_event = handle_din_current_demand(conn);
    } else if (exi_xin->V2G_Message.Body.ChargingStatusReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "ChargingStatus request is not supported in DIN 70121");
        v2g->current_v2g_msg = V2G_UNKNOWN_MSG;
        exi_out->V2G_Message.Body.ChargingStatusRes_isUsed = 0u;
        init_din_ChargingStatusResType(&exi_out->V2G_Message.Body.ChargingStatusRes);
        next_v2g_event = V2G_EVENT_IGNORE_MSG;
    } else if (exi_xin->V2G_Message.Body.MeteringReceiptReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "MeteringReceipt request is not supported in DIN 70121");
        v2g->current_v2g_msg = V2G_UNKNOWN_MSG;
        exi_out->V2G_Message.Body.MeteringReceiptRes_isUsed = 0u;
        init_din_MeteringReceiptResType(&exi_out->V2G_Message.Body.MeteringReceiptRes);
        next_v2g_event = V2G_EVENT_IGNORE_MSG;
    } else if (exi_xin->V2G_Message.Body.CertificateUpdateReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "CertificateUpdate request is not supported in DIN 70121");
        v2g->current_v2g_msg = V2G_UNKNOWN_MSG;
        next_v2g_event = V2G_EVENT_IGNORE_MSG;
    } else if (exi_xin->V2G_Message.Body.CertificateInstallationReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "CertificateInstallation request is not supported in DIN 70121");
        v2g->current_v2g_msg = V2G_UNKNOWN_MSG;
        next_v2g_event = V2G_EVENT_IGNORE_MSG;
    } else if (exi_xin->V2G_Message.Body.WeldingDetectionReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling WeldingDetectionReq");
        v2g->current_v2g_msg = V2G_WELDING_DETECTION_MSG;
        if (v2g->last_v2g_msg == V2G_POWER_DELIVERY_MSG) {
            mlog_i(LOG_TAG_V2G, "Welding-phase started");
            secc->set_PWM_ratio(secc, 100);
        }
        exi_out->V2G_Message.Body.WeldingDetectionRes_isUsed = 1u;
        init_din_WeldingDetectionResType(&exi_out->V2G_Message.Body.WeldingDetectionRes);
        next_v2g_event = handle_din_welding_detection(conn);
    } else if (exi_xin->V2G_Message.Body.SessionStopReq_isUsed) {
        mlog_d(LOG_TAG_V2G, "Handling SessionStopReq");
        v2g->current_v2g_msg = V2G_SESSION_STOP_MSG;

        exi_out->V2G_Message.Body.SessionStopRes_isUsed = 1u;
        init_din_SessionStopResType(&exi_out->V2G_Message.Body.SessionStopRes);
        next_v2g_event = handle_din_session_stop(conn);

        v2g_tcp_client_exit((v2g_connect_t*)v2g->next_client);
        v2g->next_client = NULL;
        
    } else {
        mlog_e(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", din_states[v2g->state].description);

    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, sizeof(uint64_t));
        exi_out->V2G_Message.Header.SessionID.bytesLen = din_sessionIDType_BYTES_SIZE;
    }

    return next_v2g_event;
}