Skip to content

Commit 5b409cc

Browse files
basmeermanclaude
andcommitted
Fix charging not starting: guard modem flow with ModemEnabled flag
The #if MODEM compile-time guards from the original main.cpp were lost during state machine extraction, causing the A→B transition to always enter STATE_MODEM_REQUEST (65-second ISO15118 handshake) instead of going directly to STATE_B. Since MODEM=0 (disabled), the original code never entered this path. Added ModemEnabled bool to evse_ctx_t, synced from the MODEM compile flag via the bridge. Modem-related code in tick_10ms (A→B transition) and tick_1s (modem timer handling) is now guarded by ctx->ModemEnabled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 58ffbd1 commit 5b409cc

File tree

5 files changed

+67
-40
lines changed

5 files changed

+67
-40
lines changed

SmartEVSE-3/src/evse_bridge.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ void evse_sync_globals_to_ctx(void) {
317317
ctx->Switching_Phases_C2 = (uint8_t)Switching_Phases_C2;
318318
ctx->phasesLastUpdateFlag = phasesLastUpdateFlag;
319319

320+
ctx->ModemEnabled = MODEM;
320321
ctx->ModemStage = ModemStage;
321322
ctx->DisconnectTimeCounter = DisconnectTimeCounter;
322323
ctx->ToModemWaitStateTimer = ToModemWaitStateTimer;

SmartEVSE-3/src/evse_ctx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ typedef struct {
265265
bool LimitedByMaxSumMains;
266266

267267
// --- Modem ---
268+
bool ModemEnabled;
268269
uint8_t ModemStage;
269270
uint8_t ToModemWaitStateTimer;
270271
uint8_t ToModemDoneStateTimer;

SmartEVSE-3/src/evse_state_machine.c

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ void evse_init(evse_ctx_t *ctx, evse_hal_t *hal) {
131131
ctx->LimitedByMaxSumMains = false;
132132

133133
// Modem
134+
ctx->ModemEnabled = false;
134135
ctx->ModemStage = 0;
135136
ctx->DisconnectTimeCounter = -1; // Disabled
136137
ctx->RequiredEVCCID[0] = '\0';
@@ -779,8 +780,8 @@ void evse_tick_10ms(evse_ctx_t *ctx, uint8_t pilot) {
779780
ctx->BalancedMax[0] = ctx->MaxCapacity * 10;
780781
ctx->Balanced[0] = ctx->ChargeCurrent;
781782

782-
// Modem stage check (lines 3119-3123)
783-
if (ctx->ModemStage == 0) {
783+
// Modem stage check (lines 3119-3123, guarded by #if MODEM in original)
784+
if (ctx->ModemEnabled && ctx->ModemStage == 0) {
784785
evse_set_state(ctx, STATE_MODEM_REQUEST);
785786
} else {
786787
evse_set_state(ctx, STATE_B);
@@ -929,48 +930,50 @@ void evse_tick_1s(evse_ctx_t *ctx) {
929930
// ActivationTimer countdown (line 1546)
930931
if (ctx->ActivationTimer) ctx->ActivationTimer--;
931932

932-
// Modem timers (lines 1548-1611)
933-
if (ctx->State == STATE_MODEM_REQUEST) {
934-
if (ctx->ToModemWaitStateTimer > 0) {
935-
ctx->ToModemWaitStateTimer--;
936-
} else {
937-
evse_set_state(ctx, STATE_MODEM_WAIT);
938-
}
939-
}
940-
if (ctx->State == STATE_MODEM_WAIT) {
941-
if (ctx->ToModemDoneStateTimer > 0) {
942-
ctx->ToModemDoneStateTimer--;
943-
}
944-
if (ctx->ToModemDoneStateTimer == 0) {
945-
evse_set_state(ctx, STATE_MODEM_DONE);
946-
}
947-
}
948-
if (ctx->State == STATE_MODEM_DONE) {
949-
if (ctx->LeaveModemDoneStateTimer > 0) {
950-
ctx->LeaveModemDoneStateTimer--;
951-
}
952-
if (ctx->LeaveModemDoneStateTimer == 0) {
953-
// EVCCID validation (lines 1585-1598)
954-
record_cp_duty(ctx, 1024); // Reset CP (line 1581)
955-
record_pilot(ctx, false); // PILOT_DISCONNECTED (line 1582)
956-
if (ctx->RequiredEVCCID[0] == '\0' ||
957-
strcmp(ctx->RequiredEVCCID, ctx->EVCCID) == 0) {
958-
ctx->ModemStage = 1; // Skip modem next time
959-
evse_set_state(ctx, STATE_B);
933+
// Modem timers (lines 1548-1611, guarded by #if MODEM in original)
934+
if (ctx->ModemEnabled) {
935+
if (ctx->State == STATE_MODEM_REQUEST) {
936+
if (ctx->ToModemWaitStateTimer > 0) {
937+
ctx->ToModemWaitStateTimer--;
960938
} else {
961-
ctx->ModemStage = 0;
962-
ctx->LeaveModemDeniedStateTimer = 60;
963-
evse_set_state(ctx, STATE_MODEM_DENIED);
939+
evse_set_state(ctx, STATE_MODEM_WAIT);
964940
}
965941
}
966-
}
967-
if (ctx->State == STATE_MODEM_DENIED) {
968-
if (ctx->LeaveModemDeniedStateTimer > 0) {
969-
ctx->LeaveModemDeniedStateTimer--;
942+
if (ctx->State == STATE_MODEM_WAIT) {
943+
if (ctx->ToModemDoneStateTimer > 0) {
944+
ctx->ToModemDoneStateTimer--;
945+
}
946+
if (ctx->ToModemDoneStateTimer == 0) {
947+
evse_set_state(ctx, STATE_MODEM_DONE);
948+
}
970949
}
971-
if (ctx->LeaveModemDeniedStateTimer == 0) {
972-
evse_set_state(ctx, STATE_A);
973-
record_pilot(ctx, true); // PILOT_CONNECTED (line 1608)
950+
if (ctx->State == STATE_MODEM_DONE) {
951+
if (ctx->LeaveModemDoneStateTimer > 0) {
952+
ctx->LeaveModemDoneStateTimer--;
953+
}
954+
if (ctx->LeaveModemDoneStateTimer == 0) {
955+
// EVCCID validation (lines 1585-1598)
956+
record_cp_duty(ctx, 1024); // Reset CP (line 1581)
957+
record_pilot(ctx, false); // PILOT_DISCONNECTED (line 1582)
958+
if (ctx->RequiredEVCCID[0] == '\0' ||
959+
strcmp(ctx->RequiredEVCCID, ctx->EVCCID) == 0) {
960+
ctx->ModemStage = 1; // Skip modem next time
961+
evse_set_state(ctx, STATE_B);
962+
} else {
963+
ctx->ModemStage = 0;
964+
ctx->LeaveModemDeniedStateTimer = 60;
965+
evse_set_state(ctx, STATE_MODEM_DENIED);
966+
}
967+
}
968+
}
969+
if (ctx->State == STATE_MODEM_DENIED) {
970+
if (ctx->LeaveModemDeniedStateTimer > 0) {
971+
ctx->LeaveModemDeniedStateTimer--;
972+
}
973+
if (ctx->LeaveModemDeniedStateTimer == 0) {
974+
evse_set_state(ctx, STATE_A);
975+
record_pilot(ctx, true); // PILOT_CONNECTED (line 1608)
976+
}
974977
}
975978
}
976979

SmartEVSE-3/test/native/tests/test_modem_states.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ static void setup_basic(void) {
1616
evse_init(&ctx, NULL);
1717
ctx.AccessStatus = ON;
1818
ctx.Mode = MODE_NORMAL;
19+
ctx.ModemEnabled = true; // Modem tests require modem to be enabled
1920
}
2021

2122
// ---- MODEM_REQUEST ----

SmartEVSE-3/test/native/tests/test_state_transitions.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,31 @@ void test_A_to_modem_when_modem_stage_0(void) {
123123
ctx.Mode = MODE_NORMAL;
124124
ctx.LoadBl = 0;
125125
ctx.ChargeCurrent = 100;
126+
ctx.ModemEnabled = true; // Modem must be enabled for modem flow
126127
ctx.ModemStage = 0; // Modem not yet authenticated
127128
evse_tick_10ms(&ctx, PILOT_9V);
128129
TEST_ASSERT_EQUAL_INT(STATE_MODEM_REQUEST, ctx.State);
129130
}
130131

132+
/*
133+
* @feature IEC 61851-1 State Transitions
134+
* @req REQ-IEC61851-007B
135+
* @scenario A→B goes directly to STATE_B when modem is disabled
136+
* @given The EVSE is in STATE_A with ModemStage=0 but ModemEnabled=false
137+
* @when A 9V pilot signal is received (vehicle connected)
138+
* @then The state transitions directly to STATE_B (modem flow skipped)
139+
*/
140+
void test_A_to_B_skips_modem_when_disabled(void) {
141+
setup_idle();
142+
ctx.Mode = MODE_NORMAL;
143+
ctx.LoadBl = 0;
144+
ctx.ChargeCurrent = 100;
145+
ctx.ModemEnabled = false; // Modem disabled (default)
146+
ctx.ModemStage = 0;
147+
evse_tick_10ms(&ctx, PILOT_9V);
148+
TEST_ASSERT_EQUAL_INT(STATE_B, ctx.State);
149+
}
150+
131151
/*
132152
* @feature IEC 61851-1 State Transitions
133153
* @req REQ-IEC61851-008
@@ -672,6 +692,7 @@ int main(void) {
672692
RUN_TEST(test_A_stays_A_on_12V);
673693
RUN_TEST(test_A_to_B_on_9V_when_ready);
674694
RUN_TEST(test_A_to_modem_when_modem_stage_0);
695+
RUN_TEST(test_A_to_B_skips_modem_when_disabled);
675696
RUN_TEST(test_A_stays_A_when_access_off);
676697
RUN_TEST(test_A_to_B1_when_errors);
677698
RUN_TEST(test_A_to_B1_when_charge_delay);

0 commit comments

Comments
 (0)