IEC 61851-23/-24 System A Runbook
ChargeLink Native implements the DC charging control communication of IEC 61851-23 / IEC 61851-24 System A, the CAN-based DC scheme of those standards. Both roles exist: a station (charger, EVSE side) that runs against a simulated System A plant, and an EV (vehicle side). They run a session from start-up through the insulation check and energy transfer to shutdown, and ChargeLink judges each session against its own ledger of timing and state rules, whose values follow IEC 61851-24 (System A). The stack is built as chargelink dc-can chademo; chademo in command names is a legacy identifier for IEC 61851-23/-24 System A.
$CL = 'C:\ChargeLink\0.5.0-rc2\pc1\bin\chargelink.exe'
$Data = 'C:\ChargeLinkData'
1. What the stack implements
Messages on the bus
The station and the EV exchange the periodic EV and station messages of IEC 61851-23/-24 System A, over a virtual CAN hub or a Kvaser CANlib channel. The trace of each cycle records every frame with its bus timestamp, so ChargeLink's message-timing rule (ledger row L-004) is checked from the evidence, not assumed. A frame with a wrong length or an unknown identifier is counted as a bus error; case k6 checks that values the standard requires a station to tolerate do not end the session.
Station phases
The station reports its progress with the phase names shown in the figure; they are the names printed in roles\station-report.json: Handshake, WaitPermission, Latching, PreCheck, InsulationCheck, PostCheck, WaitEvContactor, EnergyTransfer, RampDown, WaitWelding, VoltageRemoval, EndCommunication and Finished. A fault or stop request in any phase goes to RampDown and runs the same shutdown chain; the report states the shutdown kind (normal or an error shutdown), its cause and the times at which current reached zero, the switches opened and the connector unlatched.
Rules the station enforces
The limit and timing values of these rules follow IEC 61851-24 (System A); ChargeLink checks them from the evidence of every cycle.
| ChargeLink rule | Station action |
|---|---|
| Communication-loss timeout | error shutdown (cases k5a, k5b, k5c, k12) |
| Normal-stop ramp start | checked in L-037 |
| Zero-current deadline | checked in L-038 |
| Welding-detection deadline | switches open after the EV's report or at the deadline (L-039, case k15) |
| Unlatch voltage limit | connector unlatched only below it (L-040) |
| Overvoltage tolerance | error shutdown when exceeded (case k10) |
| Overcurrent tolerance | error shutdown when exceeded (case k11) |
| Latch-fault detection | emergency shutdown (case k8c) |
The station also watches the plant: the plant link carries a watchdog (case k4 trips it), the in-process owner can revoke its grant at any time (case k7), and an insulation fault or earth leakage measured by the plant ends the session (cases k2a, k2b). The plant starts and must end in the safe state (contactors open, unlatched, zero voltage); each cycle records that as a pre- and post-cycle check.
2. The one-PC case matrix (lane-f)
The lane-f command runs the station, the EV, the simulated plant, the owner and the virtual CAN bus in one process on one PC. It is the regression run and the first thing to run on a new installation. It needs no network, no second PC and no CAN hardware.
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo lane-f --cases all --run-id matrix-<DATE> --out "$Data\artifacts\t5-chademo"
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo lane-f --cases n1,k1,k5b --run-id matrix-quick
Expected with --cases all: exit code 0, "status": "passed", cycles_requested 29, cycles_run 29, cycles_passed 29, cycles_failed 0, cycles_blocked 0; one console line per cycle (<run-id> cycle 2 of 29: n1 passed); the process raises its own priority class to High and reports it. The result records the workload it found at the start (build, .NET, PowerShell, VeriStand and ChargeLink processes) and whether the bench lock was held. About four minutes. A case counts only when it runs against the implemented roles: a cycle whose pre-checks fail (bus not empty, plant not safe, owner not active) is reported as blocked, not as a pass.
| Case | Title | What is judged |
|---|---|---|
bus_self_test | Virtual bus, plant and owner self-test | The lane's own fixtures work before any protocol case runs (one-PC matrix only). |
n1 | Nominal session, EV-initiated normal stop | Complete session; energy transfer reaches the EV target; normal shutdown timing; latch, insulation check, pilot lines and station state order. |
n2 | Station-initiated normal stop (user stop) | Same as n1 with the stop coming from the station side. |
k1 | Station emergency stop, judged as a station-triggered error shutdown | Emergency stop input on the plant; error shutdown chain and flags. |
k2a | Insulation fault during the insulation check | Check fails; no permission to close; safe end. |
k2b | Earth leakage during energy transfer | Error shutdown from the transfer phase. |
k3a | EV contactor welded before the insulation check | Station detects the closed EV contactor and refuses to proceed. |
k4 | Plant communication loss (plant watchdog) | Plant link watchdog trips; station goes safe. |
k5a | Peer abort: EV process killed during transfer | Communication-loss timeout; error shutdown. |
k5b | Silent peer during energy transfer | Communication-loss monitor during transfer. |
k5c | Silent peer during parameter exchange | Communication-loss monitor before permission. |
k5d | EV-flagged error shutdown | EV sets a fault flag; station performs the error shutdown. |
k6 | Frame integrity and tolerated values | Wrong-length and unknown frames are rejected; tolerated values do not end the session. |
k7 | Owner loss | Owner revokes its grant; station ends the session safely. |
k8a | EV opens switch k while charging is enabled | Permission withdrawn mid-session. |
k8b | Loss of CP3 continuity (emergency shutdown) | Pilot-line loss handled as an emergency shutdown. |
k8c | Connector latch malfunction | Latch feedback lost; emergency shutdown. |
k9 | Incompatible EV, and insulation check without permission | Parameter incompatibility ends the session; the check never starts without permission. |
k10 | Side B overvoltage | Overvoltage beyond its tolerance; error shutdown. |
k11 | Side B overcurrent | Overcurrent beyond its tolerance; error shutdown. |
k12 | CAN bus-off of the EV node during energy transfer | Communication loss after the EV node leaves the bus; error shutdown. |
k13 | CAN bus-off of the station node during energy transfer | The station's own node leaves the bus; safe end. |
k14 | Error frames and an error-passive EV node during energy transfer, without data loss | Bus errors that do not lose data must not end the session. |
k15 | The EV never reports welding detection finished (deadline L-039) | Station opens its switches at the deadline. |
k16 | The EV never gives permission (the station's stage timeout) | Session ends at the stage timeout without an insulation check. |
k17 | The EV never closes its contactor after CP2 (the station's stage timeout) | Session ends at the stage timeout; voltage removed. |
k18 | Loss of protective-conductor continuity during transfer (emergency shutdown) | PE continuity lost; emergency shutdown. |
k19 | Vehicle coupler disconnected during transfer: pilot lines, PE and DC contacts (emergency shutdown) | All coupler circuits open at once; emergency shutdown. |
k20 | CP broken during transfer: the SV1 interlock drops the EV contactor and the EV stops | The EV side opens; the station ends the session. |
3. Two-PC SIL lane: station on PC1, EV on PC2
The two-PC lane puts the EV on a second machine so that the CAN messages and the plant coupling cross a real network. PC1 runs the station, the plant, the owner, the CAN hub and the plant link; PC2 runs the EV. The station decides which case runs in each session and tells the EV what to do through the plant link, so PC2 needs no case list. Validate both sides first:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo evse --dry-run --cases all
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo ev --dry-run --hub 127.0.0.1:47100 --plant-link 127.0.0.1:47101
The EV dry-run answers "mode": "dry_run", "status": "validated", session_status dry_run_validated, profile_id iec61851_23_24_system_a_ev, protocol chademo-classic, role evcc, backend_id virtual-can-hub, run id ev-t5-<timestamp>, and under t5.settings the backend, hub, plant link, connect_wait_s and the run directory <artifact-root>\t5-chademo\…; it opens no socket and no CAN channel. The station dry-run prints the same shape with profile_id iec61851_23_24_system_a_station, the bind addresses, ev_wait_s and the case list, but it first binds the hub and plant-link ports to prove they are free. The default ports 47100 and 47101 can be refused on a PC that runs Docker Desktop or WSL: Windows reserves a block of ports for them (on the reference PC 43500 to 47350) that netstat does not show, so the check fails with CL-CONFIG-001 "cannot be bound" although nothing listens. Pass ports outside that block on both sides, for example --hub-bind 127.0.0.1:52100 --plant-link-bind 127.0.0.1:52101 on PC1 and --hub <PC1>:52100 --plant-link <PC1>:52101 on PC2; the station dry-run then answers "status": "validated" with session_status dry_run_validated, profile_id iec61851_23_24_system_a_station, role evse, the case list and the claim boundary of the two-PC lane. The error message names this cause.
PC1 (station; replace the address with PC1's bench IPv4 address):
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo evse --hub-bind 192.0.2.10:47100 --plant-link-bind 192.0.2.10:47101 --allow-network `
--cases n1,n2,k1,k5b --sessions 1 --ev-wait-s 600 --run-id chademo-pc1-<DATE>
PC2 (EV):
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo ev --hub 192.0.2.10:47100 --plant-link 192.0.2.10:47101 `
--sessions 4 --connect-wait-s 600 --run-id chademo-pc2-<DATE>
--allow-networkis required whenever the hub or the plant link listens on anything but loopback. Without it the station refuses to bind. Open TCP 47100 and 47101 on PC1's firewall for PC2's address only.--caseson PC1 accepts the same case identifiers as the one-PC matrix, orallfor every case except the one-PC bus self-test (19 cases).--sessions Nrepeats the case list N times;0repeats untilchargelink evse stop --run-id <id>. On PC2--sessionscounts sessions, one per case offered;0runs untilchargelink evcc stop --run-id <id>, and a stop lets the current session finish.--ev-wait-s(PC1) and--connect-wait-s(PC2) bound how long each side waits for the other per session;0waits until stopped. Start PC1 first; PC2 retries until PC1 serves the next session.- Progress:
chargelink --json runtime listshows both runs with their role and run id while they are active;chargelink --json evse statusandchargelink --json evcc statuswork as for the IPv6 roles. - The station judges each session with the same checks as the one-PC matrix and writes the same evidence layout (section 5). PC2 writes its own
session-NNN\ev-report.jsonper session; collect it together with PC1's run directory.
The activation catalogue of the build (chargelink --json evse external-evcc-session-policy) lists the same two commands under protocol chademo-classic with status t5_iec61851_system_a_two_pc_runtime_engineering_evidence and tls_recommended: false: CAN carries no TLS, and the hub and plant link are plaintext bench links. Keep them on an isolated bench network.
4. CAN on a Kvaser channel
Instead of the network hub, both roles can put their frames on a Kvaser CAN channel through Kvaser CANlib (canlib32.dll from the Kvaser driver package), at the System A bus parameters, which the roles set themselves. The plant link still runs over TCP, so PC1 and PC2 are connected by Ethernet and by CAN.
# PC1
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo evse --can-backend kvaser --kvaser-channel 0 --plant-link-bind 192.0.2.10:47101 --allow-network --cases n1 --run-id chademo-kvaser-pc1
# PC2
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo ev --can-backend kvaser --kvaser-channel 0 --plant-link 192.0.2.10:47101 --run-id chademo-kvaser-pc2
--kvaser-channel is the CANlib channel number (0 is the first channel; Kvaser virtual channels count). With two virtual channels on one PC the lane runs in the same way as on the hub and is a useful driver check before hardware is attached. The chosen hardware is one Kvaser Leaf v3 per PC (classic CAN, hardware timestamps of 50 µs, two 120 Ω terminators on a 1:1 D-sub 9 cable); no vehicle or charger has been connected. Check the driver and channels with Kvaser's own tools before starting a run; a missing DLL or channel is reported as a startup error, not as a protocol result.
Check the adapters and the cable
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo kvaser-check
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo kvaser-check --channel 0 --send 100 # PC1: send 100 test frames (identifier 0x7F0), 10 ms apart
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo kvaser-check --channel 0 --listen-s 10 --expect 100 # PC2: listen and require them
Without --channel the command only lists the CANlib channels: number, name (for example Kvaser Leaf v3 #0 (Channel 0) or Virtual #0 (Channel 0)), EAN, serial number, whether silent mode is supported and whether the channel is virtual; "status": "ok" with an empty problems list. With --channel it opens the channel at the System A bus parameters, reads them back, sends or listens for test frames and reports sent, received, received_by_id, send_errors and bus_health. Run it on both PCs before the first physical session: it is the cable test of the hardware runbook.
Repeatability in fresh processes
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo repeatability --clean 10 --faults k1,k2b,k4,k5a,k5b,k7,k8b,k12,k13 --run-id repeat-<DATE>
The repeatability lane runs N consecutive clean sessions (default 10), then each listed fault case followed by a clean recovery session, every cycle in fresh station and EV processes with a fresh run id and a fresh bus; --faults none runs only the clean sessions, --cycle-timeout-s (default 300) bounds a cycle. It answers the question "does the stack recover after each fault without a restart of anything but the session". The evidence folder defaults to <artifact-root>\t5-chademo.
Combined matrix and repeatability run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo qualify --cases all --clean 10 --run-id qual-<DATE>
qualify runs the case matrix and then the repeatability run under one manifest and judges the rows Q1 to Q5 (frame audit, bus errors, timing, deadlines, repeatability) from the evidence. A row whose cases did not all run is reported incomplete and never counts. --source-root names the folder that holds the System A profile (config/lane-f/profiles); the other options are those of repeatability.
5. Evidence
The one-PC matrix writes to --out (default <artifact-root>\t5-chademo) under a folder named after the run id; the two-PC station writes <artifact-root>\t5-chademo\t5-<timestamp> unless --out is given.
| File | Content |
|---|---|
RESULT.json | Schema chargelink.lane_f.v1: run id, status (passed, failed, incomplete or stopped), cycle counts, whether the operator stopped it, the verdict per cycle, the workload found at the start, whether the bench lock was held, and the claim boundary text. |
MANIFEST.json | Every file of the run with size and SHA-256, written last. |
cycle-NNN\CYCLE.json | Case, title, kind, the ledger rows the case covers, verdict, the pre-cycle and post-cycle checks (fresh folder, empty bus, plant safe, owner active; all nodes detached, plant safe again) and the named checks with their result and detail, for example energy_transfer_reaches_the_ev_target. |
cycle-NNN\traces\can-bus.jsonl, protocol\can-bus-summary.json | Every CAN frame with timestamp, identifier, length and payload (schema chargelink.t5.can_bus_trace.v1) and the per-identifier summary. |
cycle-NNN\traces\plant.jsonl | Plant snapshots: voltage, current, contactors, latch, pilot lines, isolation, emergency stop, watchdog. |
cycle-NNN\owner\owner-journal.jsonl | Owner grants and revocations. |
cycle-NNN\roles\case1-…, case2-…, case3-…, over_target-…, over_maximum-… station and EV reports | Cases that run several sessions or sub-cases (k6, k9) write one report pair per sub-case instead of a single pair. |
cycle-NNN\roles\station-report.json, roles\ev-report.json | Per role: finished, killed or timed out, frames sent and received, bus errors, the shutdown record (kind, cause, times), the owner outcome, the phase and event timeline and the message-timing statistics. |
A complete 29-cycle run writes 238 files. The evidence is plain JSON and JSON Lines; nothing in it is a credential, so the whole folder can be archived or attached to a support case. Verify MANIFEST.json hashes before you rely on a copied run.
6. Reading a result
status: passedwith all cycles passed is the only outcome that supports a statement such as "the ChargeLink System A station and EV pass the 29-case matrix on build X".- A
failedcycle names the failing check inCYCLE.json; read the station and EV reports and the CAN trace around the timestamp in the check detail. blockedmeans the cycle never ran (pre-checks failed). Typical causes on the two-PC lane: PC2 did not connect within--ev-wait-s, the hub port is in use, or a previous run left the plant unsafe. Restart with a fresh run id.stoppedrecords an operator stop;incompletea run that ended without a verdict for every requested cycle.- The run record and
QUALIFICATION.jsoncarry two flags:lane_f_test_supportandlane_f_relaxed_checks_used. A run counts only when both arefalse; a run made with test support or relaxed checks is engineering diagnosis, not evidence. - A timing check margin close to the limit on a loaded PC is a scheduling artefact, not a protocol defect: the roles are Windows processes, not real-time controllers. Re-run on an idle machine before reporting it.
7. Bench safety when real hardware is present
When the Kvaser backend is attached to a physical bus, the bench is a live electrical environment even though ChargeLink only drives CAN. Use an isolated, current-limited supply or an approved HIL interface; verify CAN-H, CAN-L, reference ground and termination with the bench powered down; keep the emergency stop accessible; start with contactors inhibited. The plant in this release is simulated: the station's voltage and current values are the model's, not measurements, and must not be used to control a real power stage.
8. Earlier DC-CAN lanes (still available)
These are the scripted DC-CAN lanes of the kit.
The following commands predate the System A stack and remain in the binary. They use a minimal fixture frame catalogue and a closure simulator, and are useful only as software smoke tests; they are not the System A implementation and their adapter kinds (peak-pcan, vector-xl, kvaser-canlib, socketcan, slcan, lawicel, usbtin) are descriptors that never open hardware.
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can catalog
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can virtual-run --protocol chademo --profile dc_can_virtual_evse --frame-count 8 --sample-period-ms 50
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo-live-run --run-id chademo-live-01
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo-can-adapter-loop --run-id chademo-loop-01 --adapter-kind peak-pcan --adapter-mode loopback --channel PCAN_USBBUS1 --bitrate-kbps 500
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo-fault-campaign --run-id chademo-fault-01
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo-longrun-campaign --run-id chademo-longrun-01 --cycles 25 --mode loopback
dc-can release-gate still reports status: blocked_until_future_evidence and compliance_claim: none_dc_can_foundation_only; the gate has not been re-scored for the System A stack. The chademo-session conformance package (21 cases, 20 executable, 1 blocked pending a physical CAN backend) in the Test Package Catalog is likewise the earlier package and is not the System A case matrix.

