fix(ocpp): cross-check OCPP 1.6 lifecycle flags in trigger, re-entry, and simulation entry (#1987)
The OCPP 1.6 TriggerMessage handler cases for DiagnosticsStatusNotification and
FirmwareStatusNotification read stationInfo.diagnosticsStatus and
stationInfo.firmwareStatus directly. When an exception, abort, or lifecycle
drift left stationInfo.*Status at a stale non-terminal value, the trigger
faithfully reported that stale value to the CSMS instead of Idle.
The identical anti-pattern was present in handleRequestUpdateFirmware's re-entry
guard (which suppressed legitimate new UpdateFirmware.req when
stationInfo.firmwareStatus was stuck at Downloading / Downloaded / Installing)
and in the base-class event dispatcher's unconditional fan-out of
UPDATE_FIRMWARE emits (which spawned duplicate concurrent
updateFirmwareSimulation invocations emitting duplicate progress notifications
to the CSMS).
Track lifecycle progress with two per-station boolean flags on
OCPP16StationState (diagnosticsUploadInProgress, firmwareUpdateInProgress), set
on lifecycle entry and cleared in a finally block on every exit path (happy,
return, throw). The flags are consumed at four sites: the two TriggerMessage
cases, the handleRequestUpdateFirmware re-entry guard, and the
updateFirmwareSimulation entry guard.
OCPP 1.6 GetDiagnostics.req and UpdateFirmware.req core-profile payloads do not
carry a requestId (unlike OCPP 2.0.1 GetLog and UpdateFirmware), so lifecycle
progress is tracked with boolean flags rather than requestId-presence
sentinels.
Satisfies OCPP 1.6 SHALL clauses in section 4.4 (Diagnostics) and section 4.5
(Firmware), and the Idle enumeration definitions in section 7.24 and
section 7.25.