Files
HPCS6500/README.md
T
grabowski 54242da04b Rewrite the driver in Rust; move the testbench tools out
The repository is now only the HPCS 6500 driver: a Rust library (serial
transport, every protocol command, block parsing, USBPcap captures, a
simulated instrument) and the hpcs6500 CLI with the flags of the former
hpcs6500.py, plus dump/capture for reverse engineering.

The lamp station, lamp export, TM-30, label printer and LED calibration
move to B4L/lamp-testbench. Golden tests pin the Rust output to the Python
driver's: parsed values bit-exact, report text, CSV and number formatting.
The Python driver is at tag python-final.
2026-10-22 17:01:47 +07:00

6.6 KiB

HPCS 6500 — open-source driver

Rust driver and command line tool for the HPCS 6500 spectrophotometer / integrating sphere. It talks to the instrument directly over its USB serial port and replaces the vendor software for measurement automation and data extraction.

This repository is only the driver. The lamp measurement station, the lamp comparison export (TM-30, label printing) and the LED light calibration are in the testbench repository, B4L/lamp-testbench, which pulls this repository in as a submodule (the same layout as mppt-testbench).

What it reads

  • Photometric: luminous flux (lm), efficacy (lm/W), CCT (K), Duv
  • Colour: CRI Ra and R1-R15, SDCM, TLCI-2012, CIE xy / uv / u'v', CIE 1931 XYZ
  • Radiometric: total, UV, blue, yellow, red, far-red and IR flux (mW)
  • Spectrum: 350 points, 380-1050 nm
  • Electrical: voltage, current, power, power factor, frequency
  • Harmonics: 50 voltage and current harmonics, UThd, AThd, one cycle of both waveforms
  • Power supply: the built-in AC (100-240 V, 50/60 Hz) and DC (1-60 V, 0-5 A) supply

Install

cargo install --git https://git.b4l.co.th/B4L/HPCS6500-py   # puts `hpcs6500` on the PATH
# or, in a checkout:
cargo build --release                                       # target/release/hpcs6500(.exe)

Windows needs no driver: the instrument is an STM32 virtual COM port (VID 0483, PID 5741) and is found automatically. Linux: add yourself to the dialout group.

Command line

The flags are the ones of the former Python tool: uv run hpcs6500.py ... is now hpcs6500 ....

hpcs6500                                  # single reading (vendor single-test flow)
hpcs6500 --continuous                     # continuous readings, PSU on while measuring
hpcs6500 --continuous --count 10 --csv out.csv
hpcs6500 --quick --continuous             # lumen + CCT only
hpcs6500 --spectrum --harmonics           # full spectrum and harmonics
hpcs6500 --json                           # one JSON object per reading on stdout
hpcs6500 --passive --continuous           # read only, while the vendor software drives the instrument
hpcs6500 --port COM42                     # pick the port
hpcs6500 ports                            # list serial ports, the instrument is marked

# power supply
hpcs6500 --psu-status
hpcs6500 --mode ac --voltage 230 --frequency 50
hpcs6500 --mode dc --voltage 12 --current 1.0
hpcs6500 --psu-on        /   hpcs6500 --psu-off
hpcs6500 --integration 500                # ms, 0 = auto

Ctrl+C stops a continuous run cleanly: the supply is switched off and the instrument reset. The text output and the CSV files are character for character those of the Python tool, so scripts that read them keep working.

Without the instrument

--simulate talks to a simulated instrument that answers every command of the protocol: with a capture it replays the readings recorded in it, without one it uses a built-in sample reading.

hpcs6500 --simulate                                   # built-in sample
hpcs6500 --simulate captures/run.pcap --continuous    # replay a capture

USB captures (reverse engineering)

hpcs6500 --parse captures/run.pcap [--quick] [--spectrum] [--json]   # readings in a capture
hpcs6500 dump captures/run.pcap        # traffic timeline + <name>_TX.bin / _RX.bin
hpcs6500 capture                       # record the vendor software with USBPcap (admin, Windows)

capture starts USBPcapCMD on every root hub, waits for Ctrl+C, keeps the largest file and dumps it. Captures go to captures/ (not in git).

Library

[dependencies]
hpcs6500 = { git = "https://git.b4l.co.th/B4L/HPCS6500-py", default-features = false }

default-features = false leaves out the command line tool's dependencies.

use hpcs6500::{Hpcs6500, Mode};

let port = hpcs6500::find_port().ok_or(hpcs6500::Error::NotFound)?;
let mut dev = Hpcs6500::open(&port)?;
dev.identify()?;                       // "HPCS6500"
dev.set_mode(Mode::Ac)?;
dev.set_ac_voltage(230.0)?;
dev.set_ac_frequency(50.0)?;
dev.psu_on()?;
dev.send_test_config(false)?;          // the vendor's single-test configuration
let r = dev.take_single_reading()?;    // trigger, poll, read both blocks, reset
dev.psu_off()?;
println!("{:.0} lm  {:.0} K  Ra {:.1}", r.flux_lm(), r.cct_k(), r.ra());
println!("{:?}", r.get("Phi_eb_mW"));  // every field by its CSV name
let nm = r.spectrum_nm();              // with r.spectrum
Item
Hpcs6500::open(port) / with_transport(t, name) the instrument over the serial port or any Transport
identify, poll_state, wait_for_data
take_single_reading, take_reading(psu), read_current single test, one continuous reading, passive read
start_measurement, stop_measurement, reset, send_test_config the raw sequence steps
psu_on, psu_off, set_mode, set_ac_voltage, set_ac_frequency, set_dc_voltage, set_dc_current, read_psu_settings built-in supply
set_integration_time(ms) 0 = auto
read_measurement_block, read_electrical_block raw 3904 / 1584-byte blocks
set_cancel_flag(flag), pause(d) long waits end with Error::Cancelled when the flag goes up (Ctrl+C)
Reading values by FIELDS, get(name), scalars(), spectrum, spectrum_nm(), electrical with harmonics; serializes to the Python driver's JSON keys
pcap::read_messages, pcap::readings, pcap::blocks USBPcap captures
sim::Simulator simulated instrument (sample(), from_pcap(path)), logs every frame
format::* the text report and the CSV export
pyfmt::* Python-compatible number formatting (repr, .6g, .2f, round)

Every method returns Result; errors say what was expected and what came back (no acknowledge for command 0x72 (got nothing)).

Protocol

The binary protocol is documented byte by byte in PROTOCOL.md: command bytes, block layouts, field offsets and the measurement sequences. It was reverse-engineered from USB captures of the vendor software.

Development

cargo test                  # protocol, simulator, golden tests
cargo clippy --all-targets -- -D warnings

tests/golden/ holds the output of the former Python driver for real readings (tests/fixtures/): the parsed values (bit-exact), the text report, the CSV row and 2,000 number-formatting cases. The Rust driver reproduces all of them exactly. Where captures/ is present, the --parse reports of real captures are compared too.

The Python driver this replaces is at tag python-final.