IEC 61851-23/-24 System A (CHAdeMO) Runbook
ChargeLink implements the DC charging control communication of IEC 61851-23 / IEC 61851-24 System A (CHAdeMO), the CAN-based DC scheme of those standards. ChargeLink plays the station (charger) role with a simulated System A plant, or the EV (vehicle) role. Both roles run on one PC (dc-can chademo run) or on two PCs (dc-can chademo evse on the charger PC, dc-can chademo ev on the vehicle PC), with CAN over the network through ChargeLink's virtual CAN hub or on a real CAN bus (Kvaser Leaf v3), against a simulated power stage. Each session runs from start-up through the insulation check and energy transfer to shutdown, and the station judges it against ChargeLink's timing and state rules. Both roles run with ChargeLink at the other end. Testing a third-party EV or charger is not supported in 0.5.0. chademo in command names is the product identifier for IEC 61851-23/-24 System A (CHAdeMO).
$CL = 'C:\Program Files\DEVlink\ChargeLink\<VERSION>\charger\bin\chargelink.exe'
$Data = "$env:ProgramData\DEVlink\ChargeLink\data"
The kit has a charger\ and a vehicle\ folder.
Before you start
| Item | Requirement |
|---|---|
| Windows PC | The ChargeLink PC with a ChargeLink licence; a licensed command is refused on an unlicensed host. |
| CAN interface | For a physical bus: a Kvaser CAN adapter with Kvaser CANlib (canlib32.dll from the Kvaser driver package). ChargeLink is used with the Kvaser Leaf v3 (classic CAN, hardware timestamps of 50 µs). Kvaser virtual channels work for a driver check without hardware. For a software bus: none; the station serves the virtual CAN hub over TCP. |
| CAN wiring | A 1:1 D-sub 9 cable with a 120 Ω terminator at each end of the bus. The roles set the System A bus parameters themselves. |
| Network | The plant link (TCP, default port 47101) and, with the virtual hub, the CAN hub (TCP, default port 47100). Loopback needs no firewall rule. To listen on any other address, pass --allow-network and open the two ports on the station PC's firewall for the vehicle PC's address only. |
| TLS material | None. CAN carries no TLS, and the hub and the plant link are plaintext links. Keep them on an isolated network. |
Check the adapter and the cable before the first session:
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 # 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 # at the other end: 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. Check the driver and channels with Kvaser's own tools as well; a missing DLL or channel is reported as a startup error, not as a protocol result.
Bench safety. 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.
Case matrix on one PC
dc-can chademo run runs the CHAdeMO case matrix on one PC: the charger and the vehicle on a virtual CAN bus, with a simulated power stage, no network and no CAN hardware. Each case is judged; the result is passed or not passed, with an evidence folder per run. The command needs a ChargeLink licence. Run it first on a new installation:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo run --cases all --run-id matrix-<DATE>
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo run --cases n1,k1,k5b --run-id matrix-quick
| Option | Meaning |
|---|---|
--cases <list|all> | Comma-separated case identifiers, or all (default) for all 29 cases: bus_self_test (the self-test of the set-up), n1 and n2 (normal sessions, stopped by the vehicle and by the charger) and k1 to k20 (faults: emergency stop, insulation and earth leakage, welded contactor, power-stage communication loss, vehicle aborts and silence, frame errors, CP3 and connector faults, incompatible vehicle, side B over-voltage and over-current, CAN bus-off and error-passive, a vehicle that never reports or permits, coupler disconnect, CP broken). The case table lists each case. |
--run-id <name> | The run ID (default: generated). |
--out <folder> | The evidence folder (default: the CHAdeMO evidence folder under the artifact root). |
--json, --runtime-root, --artifact-root | The global options. |
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), in about four minutes. The result records the other workload found on the PC at the start.
The case matrix, and the station and vehicle roles run against each other, are described in Self-test without a device under test.
ChargeLink as charger
The station role sends the periodic station messages of IEC 61851-23/-24 System A on the CAN bus, runs the simulated System A plant (voltage, current, contactors, latch, the CP, CP2, CP3 and CS pilot lines, isolation), and judges each session. The vehicle-side contactor, switches and measurements of the plant reach the station over the plant link, which the ChargeLink EV role connects to. Every station session runs with the ChargeLink EV role on the plant link. Testing a third-party EV is not supported in 0.5.0 (see Limits).
Commands
Validate the settings first. The dry run binds the hub and plant-link ports to prove they are free, then registers a dry-run session; it opens no CAN channel:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json dc-can chademo evse --dry-run --cases all
It answers "status": "validated" with session_status dry_run_validated, profile_id iec61851_23_24_system_a_station, role evse, the bind addresses, ev_wait_s, the case list and the claim boundary.
Station with CAN on a Kvaser channel (replace the address with the station PC's address on the network to the vehicle side):
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-station-<DATE>
Station with CAN on the virtual hub:
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-station-<DATE>
| Option | Meaning |
|---|---|
--can-backend hub|kvaser | hub (default): CAN over TCP through the virtual hub at --hub-bind (default 127.0.0.1:47100). kvaser: CAN on the Kvaser channel --kvaser-channel (the CANlib channel number; 0 is the first channel, virtual channels count). |
--plant-link-bind | Address the plant link listens on (default 127.0.0.1:47101). |
--allow-network | Required whenever the hub or the plant link listens on anything but loopback. Without it the station refuses to bind. |
--cases | Case identifiers (table below), comma-separated, or all for every case except the one-process bus self-test (19 cases). Default n1. |
--sessions N | Repeats the case list N times; 0 repeats until chargelink evse stop --run-id <id>. |
--ev-wait-s | How long the station waits for the EV of each session (default 300); 0 waits until stopped. |
--listening-file | Writes the addresses the hub and plant link actually listen on to this file (JSON) once a session's sockets are bound. With port 0 in --hub-bind and --plant-link-bind the station takes free ports itself. |
--run-id, --out | Run id and evidence folder. |
Start the station first; the EV role retries until the station serves the next session. The station decides which case runs in each session and tells the EV what to do through the plant link. Progress: chargelink --json runtime list shows the run with its role and run id while it is active, and chargelink --json evse status works as for the ISO 15118 roles.
Station phases
The station reports its progress with these phase names, as 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. A good session ends in Finished with a normal shutdown.
Rules the station enforces
ChargeLink checks these rules from the evidence of every session. The trace records every CAN frame with its bus timestamp, so the message-timing rule (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.
| 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 plant 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.
Cases
| Case | Title | What is judged |
|---|---|---|
bus_self_test | Virtual bus, plant and owner self-test | The virtual bus, plant and owner work before any protocol case runs (case 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. |
ChargeLink as vehicle
The EV role sends the periodic EV messages of IEC 61851-23/-24 System A: it requests current, enables charging, closes its contactor and asks to stop. It puts its frames on a Kvaser channel or on the station's virtual hub, and it always connects to a ChargeLink station's plant link (--plant-link), which serves the vehicle-side plant values and tells the EV what each session runs. The EV role runs only against the ChargeLink station. Testing a third-party charger is not supported in 0.5.0 (see Limits).
Commands
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 dry run answers "mode": "dry_run", "status": "validated", session_status dry_run_validated, profile_id iec61851_23_24_system_a_ev, role evcc, a generated run id, and the settings it would use (backend, hub, plant link, connect_wait_s and the run directory <artifact-root>\t5-chademo\…); it opens no socket and no CAN channel.
EV with CAN on a Kvaser channel:
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-ev-<DATE>
EV with CAN on the station's virtual hub:
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-ev-<DATE>
--sessionscounts sessions, one per case the station offers;0runs untilchargelink evcc stop --run-id <id>, and a stop lets the current session finish. The EV needs no case list.--connect-wait-sbounds how long the EV retries until the station serves the next session (default 300);0retries until stopped.--listening-filereads the hub and plant-link addresses from the station's listening file in place of--huband--plant-link.chargelink --json evcc statusshows the run while it is active.
A good session ends with the EV report finished (not killed or timed out), frames sent and received, no bus errors and a normal shutdown record.
Results and evidence
The station writes <artifact-root>\t5-chademo\t5-<timestamp> unless --out is given; the case matrix writes to --out (default <artifact-root>\t5-chademo) under a folder named after the run id. The EV writes its own session-NNN\ev-report.json per session; keep it with the station's run folder. For run ids, manifests and archiving, see Trace, Evidence and Reports.
| File | Content |
|---|---|
RESULT.json | 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, 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 rule IDs 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, 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\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. |
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. |
A complete 29-cycle case matrix 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 the MANIFEST.json hashes before you rely on a copied run.
Reading the verdict
- The run is passed or not passed.
status: passedwith all cycles passed is the only passed outcome, and the only one that supports a statement such as "the ChargeLink System A station and EV pass the 29-case matrix on version 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 because its pre-checks failed (bus not empty, plant not safe, owner not active, or no EV within--ev-wait-s). A blocked cycle never counts as a pass.stoppedrecords an operator stop;incompletea run that ended without a verdict for every requested cycle.- The run record states whether diagnostic settings were used. A run made with them is a diagnosis run and does not count as evidence.
Limits
- Third-party devices. Both roles run only with ChargeLink at the other end. Testing a third-party EV or charger is not supported in 0.5.0.
- Station role. Every station session runs with the ChargeLink EV role on the plant link, which supplies the vehicle-side contactor, switch and measurement values of the simulated plant. With
--plant bench --plant-grpc-endpoint, the station uses a HIL bench power stage for one normal session; it still serves ChargeLink's own EV and is not a set-up for a real vehicle. - EV role. The EV role needs a ChargeLink station's plant link (
--plant-link); it does not run against a real charger. - Simulated plant. The station's voltage and current values are the model's, not measurements, and must not be used to control a real power stage. There is no power stage, no pilot-circuit hardware and no connector latch hardware.
- CAN adapters. Physical CAN uses Kvaser CANlib only (classic CAN).
- Timing. The roles are Windows processes, not real-time controllers. A timing margin close to its limit on a loaded PC is a scheduling artefact, not a protocol defect.
- No transport security. The virtual hub and the plant link are plaintext TCP links.
- No conformance claim. A passing run is evidence of ChargeLink's CAN layer, timing and state rules; it is not a CHAdeMO conformance or certification statement.
- Scripted DC-CAN commands. The
dc-cancommands (dc-can catalog,virtual-run,chademo-live-run,chademo-can-adapter-loop,chademo-fault-campaign,chademo-longrun-campaign) play fixed, pre-scripted frames; they are not the System A session. See Scripted DC-CAN Sequences.
Troubleshooting
| Symptom | Likely cause | Action |
|---|---|---|
The station dry run fails with CL-CONFIG-001 "cannot be bound", although nothing listens on the port | On a PC that runs Docker Desktop or WSL, Windows reserves a block of ports (on one reference PC 43500 to 47350) that netstat does not show; the defaults 47100 and 47101 fall inside it. The error message names this cause. | Use ports outside the block on both sides, for example --hub-bind 127.0.0.1:52100 --plant-link-bind 127.0.0.1:52101 on the station and --hub <STATION>:52100 --plant-link <STATION>:52101 on the EV. |
| The station refuses to bind a non-loopback address | --allow-network missing | Add --allow-network and open TCP 47100 and 47101 on the station PC's firewall for the EV's address only. |
Cycles are blocked | The EV did not connect within --ev-wait-s, the hub port is in use, or a previous run left the plant unsafe | Check the addresses and the firewall; start the station first; restart with a fresh run id. |
A startup error names canlib32.dll or the channel | Kvaser driver not installed, or the channel number does not exist | Install the Kvaser driver package; list the channels with dc-can chademo kvaser-check and pass an existing --kvaser-channel. |
kvaser-check --expect receives fewer frames than sent | Cable, termination or bus wiring | Check the 1:1 cable, the two 120 Ω terminators and CAN-H, CAN-L and ground with the bench powered down. |
| A timing check fails by a small margin | The PC was loaded during the run | Re-run on an idle machine before reporting it. |
For general failures (licence, ports, firewall) see Troubleshooting.

