forked from achamaikin/CCSModuleSW30Web
Policy/executor hooks, event-driven OFF/ON state machine, and release binaries. Co-authored-by: Cursor <cursoragent@cursor.com>
197 lines
4.5 KiB
C
197 lines
4.5 KiB
C
#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
|
|
}
|