#include "power_setpoint_executor.h" #include "charger_config.h" #include "charger_control.h" #include "debug.h" #include "psu_control.h" #include "serial.h" static PowerSetpoint_t applied; static PowerSetpoint_t pending; static PowerSetpoint_t fd_target; static uint8_t setpoint_dirty; static uint8_t fd_active; static uint8_t power_delivery_latched; static uint8_t fast_discharge_count; static uint32_t last_fast_discharge_ms; static uint32_t measured_high_current_since_ms; static uint8_t session_ended_state(CONN_State_t state) { return (state == Unknown) || (state == Unplugged) || (state == Finished) || (state == FinishedEV) || (state == FinishedEVSE); } void PowerSetpoint_Init(void) { applied.voltage_V = PSU_MIN_VOLTAGE; applied.current_0p1A = 0u; pending = applied; fd_target = applied; setpoint_dirty = 0u; fd_active = 0u; power_delivery_latched = 0u; fast_discharge_count = 0u; last_fast_discharge_ms = 0u; measured_high_current_since_ms = 0u; } void PowerSetpoint_OnCommand(uint16_t voltage_V, uint16_t current_0p1A) { #if PSD_ENABLE pending.voltage_V = voltage_V; pending.current_0p1A = current_0p1A; setpoint_dirty = 1u; #else (void)voltage_V; (void)current_0p1A; #endif } void PowerSetpoint_UpdateDeliveryLatch(void) { #if PSD_ENABLE uint32_t now = HAL_GetTick(); if (!CONN.EnableOutput || !CONN.EvConnected || session_ended_state(CCS_EvseState)) { power_delivery_latched = 0u; fast_discharge_count = 0u; last_fast_discharge_ms = 0u; measured_high_current_since_ms = 0u; return; } if (CONN.WantedCurrent > PSD_MAX_CMD_CURRENT_0P1A) { power_delivery_latched = 1u; } if (CCS_EvseState == Charging) { power_delivery_latched = 1u; } if (CONN.MeasuredCurrent >= PSD_MAX_MEASURED_CURRENT_0P1A) { if (measured_high_current_since_ms == 0u) { measured_high_current_since_ms = now; } else if ((now - measured_high_current_since_ms) >= PSD_MEASURED_LATCH_MS) { power_delivery_latched = 1u; } } else { measured_high_current_since_ms = 0u; } #endif } uint8_t PowerSetpoint_HasPending(void) { #if PSD_ENABLE return setpoint_dirty; #else return 0u; #endif } uint8_t PowerSetpoint_IsBusy(void) { #if PSD_ENABLE if (!fd_active) { return 0u; } switch (PSU0.state) { case PSU_FAST_DISCHARGE_OFF: case PSU_FAST_DISCHARGE_WAIT: case PSU_FAST_DISCHARGE_SET: case PSU_FAST_DISCHARGE_ON: case PSU_FAST_DISCHARGE_ON_WAIT: return 1u; default: return 0u; } #else return 0u; #endif } static PowerPathContext_t build_context(void) { PowerPathContext_t ctx; ctx.dc_contactor_closed = PSU0.CONT_enabled; ctx.psu_hv_enabled = PSU0.PSU_enabled; ctx.measured_voltage_V = CONN.MeasuredVoltage; ctx.measured_current_0p1A = (uint16_t)CONN.MeasuredCurrent; ctx.power_delivery_active = power_delivery_latched; ctx.enable_output = CONN.EnableOutput; ctx.psu_state_connected = (PSU0.state == PSU_CONNECTED) ? 1u : 0u; ctx.psu_cont_fault = PSU0.cont_fault; ctx.psu_fault = PSU0.psu_fault; ctx.fast_discharge_count = fast_discharge_count; ctx.last_fast_discharge_ms = last_fast_discharge_ms; ctx.now_ms = HAL_GetTick(); return ctx; } PowerSetpointTryResult_t PowerSetpoint_TryApply(void) { #if PSD_ENABLE PowerPathContext_t ctx; PowerSetpointAction_t action; if (!setpoint_dirty || fd_active) { return PSD_TRY_IDLE; } ctx = build_context(); action = PowerSetpoint_Decide(&applied, &pending, &ctx); if (action == POWER_SETPOINT_FAST_DISCHARGE) { fd_target = pending; fd_active = 1u; setpoint_dirty = 0u; log_printf(LOG_INFO, "Fast discharge trigger %u->%u I=%u\n", (unsigned)applied.voltage_V, (unsigned)fd_target.voltage_V, (unsigned)fd_target.current_0p1A); return PSD_TRY_START_FAST_DISCHARGE; } if (!PSU0.ready) { return PSD_TRY_IDLE; } PSU_SetVoltageCurrent(0, pending.voltage_V, pending.current_0p1A); applied = pending; setpoint_dirty = 0u; return PSD_TRY_APPLIED_NORMAL; #else return PSD_TRY_IDLE; #endif } void PowerSetpoint_GetFastDischargeTarget(PowerSetpoint_t *target) { if (target != 0) { *target = fd_target; } } void PowerSetpoint_OnFastDischargeComplete(void) { #if PSD_ENABLE applied = fd_target; fd_active = 0u; fast_discharge_count++; last_fast_discharge_ms = HAL_GetTick(); log_printf(LOG_INFO, "Fast discharge complete, V=%u\n", (unsigned)CONN.MeasuredVoltage); #endif } void PowerSetpoint_OnFastDischargeAbort(void) { #if PSD_ENABLE fd_active = 0u; pending = fd_target; setpoint_dirty = 1u; log_printf(LOG_WARN, "Fast discharge aborted, V=%u\n", (unsigned)CONN.MeasuredVoltage); #endif }