Add Coherent HOPS / Verdi-G (Genesis CX-Vis) laser driver, DLL and native pyftdi#113
Merged
Conversation
VerdiGDevice is a LaserSourceDevice (OnOff / Shutter / Power / Interlock) for a
Coherent laser on a HOPS ("High Output Power Supply") supply; the lab head reports
as a Genesis CX-Vis (G532). The supply is not serial: its FTDI FT2232
(0x0403:0x6010) is driven as bit-banged I2C, with the power DAC, ADC,
shutter/enable GPIO, and the head identity/calibration EEPROM all on one I2C bus.
VerdiGDevice drives that bus through an interchangeable HOPSInterface, selected
with interface="auto" (native first, then the DLL; or "native"/"dll"/an instance):
- HOPSNativeInterface (hopsnative.py): pure-Python pyftdi I2C, no DLL
(macOS/Linux). Hardware-confirmed end to end on the lab unit (identity, on/off,
shutter, remote, power setpoint, temperature). interlock()/faults() raise
HOPSInterface.NotSupported until the ?FF decode is reverse-engineered.
- HOPSDLLInterface (hopsdll.py): Coherent's CohrHOPS.dll (ASCII command set;
Windows/Linux), with the CohrHOPS ctypes binding.
Tests in testVerdiG.py: debug, native-on-mock, and read-modify-write always run;
the hardware class skips when no laser is reachable. scratch-hops/ (vendor DLLs
and reverse-engineering prototypes) is gitignored.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01841beMNdCw3zYf6fdBUoy7
Reconstructed by intercepting CohrHOPS.dll and decoding its I2C traffic. Three numbered docs to read in order, plus the bus diagram: 1. Overview & runbook -- the macOS-writes / Windows-runs / Parallels workflow used to reach the laser, and how to reproduce it. 2. USB / CohrHOPS.dll command protocol. 3. I2C wire protocol (device addresses, registers, calibration) and the bus diagram (SVG + PNG) -- what the native pyftdi transport replays. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01841beMNdCw3zYf6fdBUoy7
Add a "Commands implemented by the driver" section to Coherent-HOPS-2-USB-and-DLL-Protocol.md: the exact ASCII queries, diagnostics, and settings HOPSDLLInterface exchanges through CohrHOPS.dll, each with its description and return value, plus the ?FF fault-bit decode. Notes that the native pyftdi transport maps the same operations onto I2C. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01841beMNdCw3zYf6fdBUoy7
Two read-only status monitors under examples/verdig/ (stream once per second, Ctrl-C to stop; neither takes remote control, so the front panel stays usable): - temperature_monitor_native.py: main temperature over native pyftdi I2C (no DLL). - status_monitor_dll.py: full status (four servo temperatures, power, shutter, emission, interlock/faults) over Coherent's CohrHOPS.dll. Plus a short README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01841beMNdCw3zYf6fdBUoy7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Use at your own risk: reverse-engineered without Coherent
Adds computer control for the Coherent Vergi G laser (the 532 nm pump). It presents as a "Verdi-G" but is actually a Genesis CX-Vis (head G532) on a HOPS (High Output Power Supply) whose USB is not a serial port: the FT2232 is driven as bit-banged I2C, so no serial framing ever answers. Two working control paths are provided for the same laser.
All the work here was obtained by reverse engineering the windows CohrHOPS.dll provided by Coherent. I want to use macOS or Linux, so I created this pure-Python version (with the help of Claude and no help from Coherent). Thank you to https://github.com/AllenNeuralDynamics/coherent-lasers which gave me critical information to get started. Using Claude is a great way of getting things done, but Claude is not the greatest for architecture, therefore I iterated several hours to get clean code that was easy to use and followed the
PyHardwareLibrarystrategy.Why a driver is needed
You can't talk to the laser directly and send text commands for the Verdi G series. The computer reaches an FTDI FT2232 over USB, and that device is connected (through the I2C protocol) to other chips/devices (identified with a number
0x29,0x48, etc...) that provide services or information; its channel A is an I2C master, and all control lives on that one I2C bus — power DAC0x29, ADC0x48, and the shutter/enable/remote I/O expander0x25in the supply, plus the head's identity/calibration EEPROM0x52across the umbilical, inside the laser head. There is no serial/host path to the head, so every command must speak HOPS: through Coherent'sCohrHOPS.dll, or natively over pyftdi I2C.Strategy
For the details on how I reconstructed from the sniffed I2C traffic; see
hardwarelibrary/manuals/Coherent-HOPS-3-I2C-Wire-Protocol.md.Since I had a working Windows DLL, I used AllenNeuralDynamics code to talk to the Verdi, but I intercepted the calls and dumped the parameters of the functions that were called. This allowed me to decode the ASCII commands and the corresponding I2C devices/registers to create a Pure-Python version without the need for this Windows-only, binary, proprietary-for-no-reason DLL.
Since everything goes through the High Output Power Supply (which I suppose is a very general device that Coherent reuses on many systems and then connects various things through I2C to it), the trick is to create a "HOPS Interface" using either the coherent-provided DLL or pure-Python. Then the
LaserSourceDevice:VerdiGDevicecreates one or the other, and will use the appropriate one but will otherwise be unaware of the details.What's added
sources/verdig.py—VerdiGDevice(+DebugVerdiGDevice) and the abstractHOPSInterface.VerdiGDevicecombines OnOff / Shutter / Power / Interlock anddelegates every hook to whichever transport it holds;
VerdiGDevice(interface="auto")tries native first, then the DLL (or force onewith
"native"/"dll"/ an instance).sources/hopsnative.py—HOPSNativeInterface(+HOPSNativeI2C,MockHOPSBus): the pure-Python pyftdi I2C transport, no DLL, so the laserruns natively on macOS/Linux.
sources/hopsdll.py—HOPSDLLInterface(+ theCohrHOPSctypesbinding): the transport over Coherent's
CohrHOPS.dll(Windows/Linux).manuals/— a HOPS USB-protocol reference; a reproducible runbook for themacOS-writes / Windows-runs / Parallels workflow used to reach the laser; a
decode of the HOPS I2C protocol sniffed with a logging
CohrFTCI2C.dllproxy;and the bus diagram (SVG + PNG).
testVerdiG.py: 22 tests (the 3 hardware tests skip when no laser is attached).Verification status
HOPSNativeInterface, the default): hardware-confirmed end toend on the lab Genesis CX-Vis via
interface="auto"(identity, on/off,shutter, remote write+read, power setpoint, power=0, temperature).
HOPSDLLInterface): hardware-confirmed for the read path and theREM/PCMDwrite path; the emission-enable (KSWCMD) and shutter (SHCMD)writes are per the DLL spec but not yet exercised.
full
?FFfault/interlock decode,?PLIM, and the ADC power-read scale — soVerdiGDevicekeepsInterlockControlin its capabilities butinterlock()/faults()raiseHOPSInterface.NotSupportedon native, and the temperaturecalibration is a two-point fit valid only ~32-40 C.
Notes
scratch-hops/and are intentionally not part of this PR.Generated with Claude Code
https://claude.ai/code/session_01841beMNdCw3zYf6fdBUoy7