@@ -226,17 +226,6 @@ void Charger::run_state_machine() {
226226 break ;
227227
228228 case EvseState::WaitingForAuthentication:
229- if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
230- // Wed did not start to charge yet, so go directly to finished.
231- set_state (EvseState::Finished);
232- break ;
233- }
234-
235- // Errors prevent charging? -> go to EVSE paused
236- if (stop_charging_on_fatal_error_internal ()) {
237- set_state (EvseState::ChargingPausedEVSE);
238- break ;
239- }
240229
241230 // Explicitly do not allow to be powered on. This is important
242231 // to make sure control_pilot does not switch on relais even if
@@ -249,12 +238,12 @@ void Charger::run_state_machine() {
249238
250239 bsp->allow_power_on (false , types::evse_board_support::Reason::PowerOff);
251240
252- // First user interaction was plug in of car? Start session here.
253- if (not shared_context.session_active ) {
254- start_session (false );
255- }
256- // External signal on MQTT
257- signal_simple_event (types::evse_manager::SessionEventEnum::AuthRequired);
241+ // First user interaction was plug in of car? Start session here.
242+ if (not shared_context.session_active ) {
243+ start_session (false );
244+ }
245+ // External signal on MQTT
246+ signal_simple_event (types::evse_manager::SessionEventEnum::AuthRequired);
258247
259248 hlc_use_5percent_current_session = false ;
260249
@@ -288,6 +277,17 @@ void Charger::run_state_machine() {
288277 }
289278 }
290279
280+ // Errors prevent charging? -> wait here, we cannot go to paused etc because we are not authorized yet
281+ if (stop_charging_on_fatal_error_internal ()) {
282+ break ;
283+ }
284+
285+ if (not shared_context.flag_ev_plugged_in ) {
286+ // Wed did not start to charge yet, so go directly to finished.
287+ set_state (EvseState::Finished);
288+ break ;
289+ }
290+
291291 // Read PP value in case of AC socket
292292 if (connector_type == types::evse_board_support::Connector_type::IEC62196Type2Socket and
293293 shared_context.max_current_cable == 0 ) {
@@ -324,25 +324,7 @@ void Charger::run_state_machine() {
324324 }
325325 }
326326
327- // SLAC is running in the background trying to setup a PLC connection.
328-
329- // we get Auth (maybe before SLAC matching or during matching)
330- // FIXME: getAuthorization needs to distinguish between EIM and PnC in Auth mananger
331-
332- // FIXME: Note Fig 7. is not fully supported here yet (AC Auth before plugin - this overides PnC and always
333- // starts with nominal PWM). We need to support this as this is the only way a user can
334- // skip PnC if he does NOT want to use it for this charging session.
335-
336- // FIXME: In case V2G is not successfull after all, it needs
337- // to send a dlink_error request, which then needs to:
338- // AC mode: fall back to nominal PWM charging etc (not
339- // implemented yet!), it can do so because it is already authorized.
340- // DC mode: go to error_hlc and give up
341-
342- // FIXME: if slac reports a dlink_ready=false while we are still waiting for auth we should:
343- // in AC mode: go back to non HLC nominal PWM mode
344- // in DC mode: go to error_slac for this session
345-
327+ // EIM
346328 if (shared_context.flag_authorized and not shared_context.authorized_pnc ) {
347329 if (not internal_context.auth_received_printed ) {
348330 internal_context.auth_received_printed = true ;
@@ -476,6 +458,7 @@ void Charger::run_state_machine() {
476458 // unsupported charging mode, give up here.
477459 error_handling->raise_internal_error (" Unsupported charging mode." );
478460 }
461+ // Contract / Plug and Charge
479462 } else if (shared_context.flag_authorized and shared_context.authorized_pnc ) {
480463
481464 if (not shared_context.flag_transaction_active ) {
@@ -620,20 +603,10 @@ void Charger::run_state_machine() {
620603 }
621604 }
622605
623- if (not shared_context.flag_authorized ) {
606+ if (stop_charging_on_fatal_error_internal () or not shared_context.flag_authorized or
607+ not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
624608 // We started to initialize charging already, so we need to stop via StoppingCharging
625609 set_state (EvseState::StoppingCharging);
626- }
627-
628- if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
629- // We started to initialize charging already, so we need to stop via StoppingCharging
630- set_state (EvseState::StoppingCharging);
631- }
632-
633- // Errors prevent charging? -> go to StoppingCharging
634- if (stop_charging_on_fatal_error_internal ()) {
635- internal_context.current_state_started = now;
636- set_state (EvseState::StoppingCharging);
637610 break ;
638611 }
639612
@@ -654,10 +627,13 @@ void Charger::run_state_machine() {
654627 // In AC mode BASIC, iec_allow is sufficient. The same is true for HLC mode when nominal PWM is
655628 // used as the car can do BASIC and HLC charging any time. In AC HLC with 5 percent mode, we need to
656629 // wait for both iec_allow and hlc_allow.
657-
658630 if (not power_available ()) {
659- // TODO: start timer to stop charging
631+ // FIXME: For AC BC, it is ok to wait here. The behaviour we would like to have for AC ISO
632+ // when starting up with no power needs to be defined still. For DC it just continues here without
633+ // power.
634+ break ;
660635 }
636+
661637 // Power is available, PWM is already enabled. Check if we can go to charging
662638 if ((shared_context.iec_allow_close_contactor and not hlc_use_5percent_current_session) or
663639 (shared_context.iec_allow_close_contactor and shared_context.hlc_allow_close_contactor and
@@ -711,34 +687,14 @@ void Charger::run_state_machine() {
711687 }
712688 }
713689
714- // Errors prevent charging? -> go to StoppingCharging
715- if (stop_charging_on_fatal_error_internal ()) {
690+ // Stop charging on errors, user stops or pause requests
691+ if (stop_charging_on_fatal_error_internal () or not shared_context.flag_authorized or
692+ not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in or
693+ shared_context.flag_paused_by_evse ) {
716694 set_state (EvseState::StoppingCharging);
717695 break ;
718696 }
719697
720- if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
721- set_state (EvseState::StoppingCharging);
722- }
723-
724- if (shared_context.flag_paused_by_evse ) {
725- set_state (EvseState::StoppingCharging);
726- }
727-
728- if (config_context.state_F_after_fault_ms > 0 and not shared_context.hlc_charging_active ) {
729- // First time we see that a fatal error became active, signal F for a short time.
730- // Only use in basic charging mode.
731- if (entered_fatal_error_state ()) {
732- pwm_F ();
733- }
734-
735- if (internal_context.pwm_F_active and
736- time_in_fatal_error_state_ms () > config_context.state_F_after_fault_ms and
737- shared_context.shutdown_type == ShutdownType::EmergencyShutdown) {
738- pwm_off ();
739- }
740- }
741-
742698 if (config_context.charge_mode == ChargeMode::DC) {
743699 if (initialize_state) {
744700 bsp->allow_power_on (true , types::evse_board_support::Reason::FullPowerCharging);
@@ -787,9 +743,10 @@ void Charger::run_state_machine() {
787743 signal_simple_event (types::evse_manager::SessionEventEnum::ChargingPausedEV);
788744 }
789745
790- if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
791- // Wed did not start to charge yet, so go directly to finished.
746+ if (not shared_context.flag_transaction_active or not shared_context.flag_authorized or
747+ not shared_context. flag_ev_plugged_in ) {
792748 set_state (EvseState::StoppingCharging);
749+ break ;
793750 }
794751
795752 if (config_context.charge_mode == ChargeMode::AC) {
@@ -847,43 +804,61 @@ void Charger::run_state_machine() {
847804 internal_context.last_charging_paused_evse_reasons = {};
848805 }
849806
850- if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
807+ if (not shared_context.flag_transaction_active or not shared_context.flag_authorized or
808+ not shared_context.flag_ev_plugged_in ) {
851809 set_state (EvseState::StoppingCharging);
852- }
853- {
854- types::evse_manager::ChargingPausedEVSEReasons r;
855- if (stop_charging_on_fatal_error_internal ()) {
856- r.reasons .push_back (types::evse_manager::PauseChargingEVSEReasonEnum::Error);
810+ break ;
857811 }
858812
859- if (not power_available ()) {
860- r.reasons .push_back (types::evse_manager::PauseChargingEVSEReasonEnum::NoEnergy);
861- }
813+ if (config_context.state_F_after_fault_ms > 0 and not shared_context.hlc_charging_active ) {
814+ // First time we see that a fatal error became active, signal F for a short time.
815+ // Only use in basic charging mode.
816+ if (entered_fatal_error_state ()) {
817+ pwm_F ();
818+ }
862819
863- if (shared_context.flag_paused_by_evse ) {
864- r.reasons .push_back (types::evse_manager::PauseChargingEVSEReasonEnum::UserPause);
820+ if (internal_context.pwm_F_active and
821+ time_in_fatal_error_state_ms () > config_context.state_F_after_fault_ms and
822+ shared_context.shutdown_type == ShutdownType::EmergencyShutdown) {
823+ pwm_off ();
824+ }
865825 }
866826
867- if (r. reasons . size () == 0 ) {
868- // resume charging
869- if (shared_context. hlc_charging_terminate_pause == HlcTerminatePause::Terminate ) {
870- signal_slac_start (); // wake up SLAC as well
827+ {
828+ types::evse_manager::ChargingPausedEVSEReasons r;
829+ if (stop_charging_on_fatal_error_internal () ) {
830+ r. reasons . push_back (types::evse_manager::PauseChargingEVSEReasonEnum::Error);
871831 }
872- shared_context.current_state = EvseState::PrepareCharging;
873- } else {
874- if (internal_context.last_charging_paused_evse_reasons not_eq r) {
875- signal_charging_paused_evse_event (r);
876- internal_context.last_charging_paused_evse_reasons = r;
832+
833+ if (not power_available ()) {
834+ r.reasons .push_back (types::evse_manager::PauseChargingEVSEReasonEnum::NoEnergy);
835+ }
836+
837+ if (shared_context.flag_paused_by_evse ) {
838+ r.reasons .push_back (types::evse_manager::PauseChargingEVSEReasonEnum::UserPause);
839+ }
840+
841+ if (r.reasons .size () == 0 ) {
842+ // resume charging
843+ if (shared_context.hlc_charging_terminate_pause == HlcTerminatePause::Terminate) {
844+ signal_slac_start (); // wake up SLAC as well
845+ }
846+ shared_context.current_state = EvseState::PrepareCharging;
847+ } else {
848+ if (internal_context.last_charging_paused_evse_reasons not_eq r) {
849+ signal_charging_paused_evse_event (r);
850+ internal_context.last_charging_paused_evse_reasons = r;
851+ }
877852 }
878853 }
879- }
880854 break ;
881855
882856 /*
883857 Stopping Charging:
884- - stops an ongoing charging session actively from EVSE side if it is still ongoing
858+ - stops an ongoing charging session actively from EVSE side if it is still ongoing (hard stop)
885859 - switch to this state to stop charging
886- - When EV stops charging, remain in Charging state unt
860+ - DC: When EV stops charging, remain in Charging state until WeldingCheck etc is really done, otherwise PWM
861+ will switch off too early
887862 - after charging is stopped, it switches to PausedEVSE or Finished depending on whether it may restart or
888863 not (only a short transitional state)
889864 */
@@ -912,20 +887,17 @@ void Charger::run_state_machine() {
912887 bsp->allow_power_on (false , types::evse_board_support::Reason::PowerOff);
913888 }
914889
915- // Errors prevent charging? -> go to StoppingCharging
916- if (stop_charging_on_fatal_error_internal ()) {
917- set_state (EvseState::ChargingPausedEVSE);
918- break ;
919- }
920-
921- if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in ) {
922- // Wed did not start to charge yet, so go directly to finished.
890+ // Those are fatal, so we can not recover without replugging.
891+ if (not shared_context.flag_transaction_active or not shared_context.flag_ev_plugged_in or
892+ not shared_context.flag_authorized ) {
923893 set_state (EvseState::Finished);
894+ break ;
924895 }
925896
926- if (shared_context.flag_paused_by_evse ) {
897+ if (shared_context.flag_paused_by_evse or stop_charging_on_fatal_error_internal () ) {
927898 // Paused was initiated by EVSE, continue to PausedEVSE
928899 set_state (EvseState::ChargingPausedEVSE);
900+ break ;
929901 }
930902
931903 break ;
@@ -953,6 +925,8 @@ void Charger::run_state_machine() {
953925 bsp->allow_power_on (false , types::evse_board_support::Reason::PowerOff);
954926 }
955927
928+ // FIXME: wait here for SLAC to become available again
929+
956930 // If unplugged, proceed to Idle, otherwise wait here and do nothing
957931 if (not shared_context.flag_ev_plugged_in ) {
958932 shared_context.current_state = EvseState::Idle;
@@ -1013,7 +987,6 @@ void Charger::process_cp_events_state(CPEvent cp_event) {
1013987
1014988 case EvseState::WaitingForAuthentication:
1015989 if (cp_event == CPEvent::CarRequestedPower) {
1016- session_log.car (false , " B->C transition before PWM is enabled at this stage violates IEC61851-1" );
1017990 shared_context.iec_allow_close_contactor = true ;
1018991 } else if (cp_event == CPEvent::CarRequestedStopPower) {
1019992 shared_context.iec_allow_close_contactor = false ;
@@ -1038,15 +1011,13 @@ void Charger::process_cp_events_state(CPEvent cp_event) {
10381011 // if this is not the case, we have to do it here.
10391012 if (shared_context.hlc_charging_active ) {
10401013 signal_hlc_stop_charging ();
1041- session_log.evse (false , " CP state transition C->B at this stage violates ISO15118-2" );
10421014 }
10431015 } else if (cp_event == CPEvent::BCDtoE) {
10441016 shared_context.iec_allow_close_contactor = false ;
10451017 shared_context.current_state = EvseState::StoppingCharging;
10461018 // Tell HLC stack to stop the session in case of an E event while charging.
10471019 if (shared_context.hlc_charging_active ) {
10481020 signal_hlc_stop_charging ();
1049- session_log.evse (false , " CP state transition C->E/F at this stage violates ISO15118-2" );
10501021 }
10511022 }
10521023 break ;
0 commit comments