Remote-triggered DDI/SPC measurements (Using USB and VCP backends)
- Overview
- Project Maintenance Philosophy
- Compatibility (Verified)
- USB Backend
- Mahr Platform Guide
- Mitutoyo ID-C Platform Guide
- Example Usage
- Smoke Test (First-Time Validation)
- Using the Library in Your Own Scripts
- Code Map (Where to Look)
- Architecture
- Troubleshooting
- Appendix A: Initialization Sequence
- Appendix B: Trigger Sequence
- Appendix C: Capture Interpretation
- Appendix D: Driver Switching and Recovery
- Appendix E: Mitutoyo 543-700B Command Findings
- License, Authorship, and Acknowledgments
- Trademark, Affiliation, and Interoperability Notice
This project provides an open-source DDI measurement framework with two validated backend paths under one CLI and library API: a Mahr pure-USB FTDI path (mahr) and a Mitutoyo USB-ITN-SF VCP/COM path (mitutoyo_idc). It is designed for fixtured and CNC-adjacent workflows where touching the gauge would disturb the setup, enabling deterministic remote triggering, automation-ready capture, and raw payload visibility for both ecosystems. The architecture separates transport and protocol layers so family-specific behavior (Mahr FTDI control/bulk signaling vs. Mitutoyo VCP trigger/read flow) is handled cleanly while keeping a unified user workflow.
The repository now supports two families through one CLI flow:
mahr(pure USB FTDI path)mitutoyo_idc(USB-ITN-SF VCP/COM path)
This repository has two equal priorities:
- Simplicity of use for callers (
prime_ddi→trigger_measurement→read_measurement) - Preservation of discovery context so protocol knowledge is not lost over time
- Keep top-level usage simple and stable.
- Keep internals understandable, especially in protocol-sensitive paths.
- Keep raw observability available for diagnostics and future reverse engineering.
- Do not remove comments that explain why protocol steps exist.
- Do not flatten transport/protocol logic if it hides capture-backed behavior.
- Do not delete code simply because it looks "old" when it still documents validated device behavior.
Deprecated runtime code may be removed only after its insight is preserved in durable form:
- README section with rationale and replacement behavior
- reference to capture/test evidence
- recovery notes for known failure states
If the insight is unique and not yet captured elsewhere, keep the code (or move the context into comments/docs first) before deletion.
Remote triggering is a core requirement for this effort because it enables repeatable, non‑disturbing, fixtured measurement. The DDI device remains mechanically stable, the part moves independently, and the measurement event is initiated without touching the gauge. This eliminates operator‑induced variation and allows the measurement cycle to be integrated into automated or semi‑automated projects.
Traditional machinist practice typically evolved around hand‑held, operator‑driven measurement, where the user physically presses the button on the indicator. In that environment, the operator is part of the measurement system: they position the gauge, feel the contact, decide when the reading is valid, and trigger the measurement manually. Because this workflow dominated for decades, vendors optimized their software and hardware ecosystems around human presence, not automation. MarCom, SPC keyboards, wireless buttons, foot switches, and RS‑232 forwarding all reflect this assumption.
This effort operates with a differing assumption. When the gauge is rigidly fixtured and the part is moved by machine i.e., CNC or fixture, pressing the button on the DDI may not be possible, introduces mechanical disturbance, potentially creates timing issues, and of course may cause operator‑dependent variation. In these conditions, remote triggering is not optional—it is the only way to obtain stable, repeatable, automation‑ready measurements. The DDI protocol supports this electrically, but vendor software does not necessarily expose it or allow for easy integration within user projects. This effort restores that capability by controlling the DDI interface directly to issue the required measurement trigger sequence remotely.
Remote triggering is therefore treated as a primary feature of the DDI. The DDI driver, initialization sequence, and measurement routines are all designed to support deterministic, non‑contact triggering across Mahr and Mitutoyo devices. This enables projects that traditional machinist tools and vendor software do not address, and it is one of the primary motivations for the existence of this effort.
This effort intentionally uses different USB backends for each family because the validated driver path differs by hardware ecosystem.
-
mahrUSB backend:- Uses direct USB control/data through PyUSB/libusb
- Requires WinUSB binding (no COM port)
- Best when deterministic pure-USB FTDI control is needed
-
mitutoyo_idcUSB backend:- Uses Mitutoyo VCP driver path (
ITVCP64.sys) through COM/pyserial - Requires a COM port from USB-ITN-SF and USB-ITPAK VCP driver installation
- Best when using officially supported Mitutoyo driver stack
- Uses Mitutoyo VCP driver path (
These are not interchangeable at runtime: selecting the wrong family/driver mode will fail detection.
Verified combinations for this repository:
- Mahr 1087Ri + 16 ExU 4102357 cable
- Mitutoyo 543-700B ID-C0512NXB DDI + 06AGQ0001F USB-ITN-SF cable
Other combinations may work, but are not currently verified.
| Family | Example Hardware | Cable | Driver Mode Required | Transport Used by This Repo | CLI Family | Notes |
|---|---|---|---|---|---|---|
| Mahr | Mahr 1087Ri | 16 ExU 4102357 (FTDI) | WinUSB (via Zadig) | PyUSB/libusb direct USB | mahr |
Pure-USB path; no COM port required |
| Mitutoyo ID-C DDI | 543-700B ID-C0512NXB | 06AGQ0001F USB-ITN-SF | Mitutoyo VCP (ITVCP64.sys) |
COM/VCP (pyserial) |
mitutoyo_idc |
Requires installed USB-ITPAK VCP driver |
- Mahr 1087Ri (verified) or compatible Mahr DDI indicator
- 16 ExU 4102357 cable (Mahr FTDI)
- Windows 11
Install WinUSB using Zadig:
- Download Zadig: https://zadig.akeo.ie
- Plug in the MarConnect cable
- Select the device with:
- VID: 0403
- PID: 6001
- Manufacturer: FTDI
- Replace the driver with WinUSB
- Unplug and replug the cable
This allows PyUSB to communicate directly with the Mahr FTDI chip.
After replacing the FTDI driver with WinUSB, the cable will no longer enumerate as a COM port. This is expected. Windows will continue to bind the device to WinUSB every time it is plugged in, because Zadig updates the driver association in the Windows driver store. Unplugging and replugging the cable does not revert it to the FTDI Virtual COM Port (VCP) driver.
This means:
- Device Manager will no longer show USB Serial Port (COMx).
- Software that depends on COM ports (e.g., MarCom, legacy SPC tools, pyserial scripts) will not detect the device.
- The cable will appear only under Universal Serial Bus devices as a WinUSB device.
This is the correct configuration for PyUSB and for this project’s Mahr pure‑USB backend.
Please see Appendix D: Driver Switching and Recovery below if you need to revert to COM port mode.
pip install pyusbEnsure libusb-1.0.dll is placed next to ddi_init.py.
- Mitutoyo 543-700B ID-C0512NXB DDI (verified)
- 06AGQ0001F USB-ITN-SF cable (verified)
- Windows 11
For mitutoyo_idc mode, the USB-ITN-SF cable must be bound to the Mitutoyo VCP driver (ITVCP64.sys) so a COM port is available.
Reference documentation:
- USB-ITPAK V3.0 No. 99MAM030A2, Date of publication: June 1, 2024 (1)
- Section: "2.3 Installing the VCP Driver"
- USB-ITPAK software/manuals download page: https://mitutoyo.eu/downloads/free-software-and-updates-and-free-trials/free-software-u-wave-wireless-data-transmission-and-digital-read-out
High-level procedure:
- Download and install USB-ITPAK from the official Mitutoyo page above.
- Follow the manual section "2.3 Installing the VCP Driver".
- Confirm Device Manager shows
USB-ITN (COMx)usingITVCP64.sys. - Use that COM port with this tool via
--port.
Notes:
- Do not use Zadig/WinUSB for the Mitutoyo
mitutoyo_idcpath. - Mitutoyo path uses COM/VCP (
pyserial), not direct PyUSB FTDI.
Use the included CLI script.
Mahr:
python ddi_remote_measurement.py --family mahrMitutoyo ID-C (requires COM port):
python ddi_remote_measurement.py --family mitutoyo_idc --port COM5Expected output (default mode):
2.8360
Multiple measurements:
python ddi_remote_measurement.py --family mitutoyo_idc --port COM5 --trials 3 --trial-delay 0.2Raw outputs:
python ddi_remote_measurement.py --family mitutoyo_idc --port COM5 --raw_ascii
python ddi_remote_measurement.py --family mitutoyo_idc --port COM5 --raw_hexUse the included manual smoke-test runner to validate core workflow and raw modes:
prime_ddi(...)trigger_measurement(...)read_measurement(...)- CLI
--raw_ascii/--raw_hex
Mahr:
python ddi_smoke_test.py --family mahrMitutoyo ID-C:
python ddi_smoke_test.py --family mitutoyo_idc --port COM5Optional:
python ddi_smoke_test.py --family mitutoyo_idc --port COM5 --trials 5 --trial-delay 0.2
python ddi_smoke_test.py --family mitutoyo_idc --port COM5 --skip-cli-checkThe runner prints stage-by-stage pass/fail information and exits non-zero on failure.
Note on raw_ascii output:
raw_asciimeans decoded ASCII text from device bytes, not necessarily alphabetic characters.- For these devices, measurement payloads are often ASCII digits (for example
00005440or-00.0105). raw_hexshows the same bytes in hexadecimal form so you can compare text-vs-bytes directly.
Example successful output (Mitutoyo ID-C):
=== readDDI smoke test ===
family=mitutoyo_idc trials=3 cli_check=True
[1/4] prime_ddi baseline check
baseline ascii: 00005440
baseline hex: 0x30303030353434300D
[2/4] trigger/read trial checks
trial 1: 00005440
trial 2: 00005440
trial 3: 00005440
summary: nonempty=3/3, parseable=3/3
[3/4] raw mode rendering check (library path)
raw ascii/hex rendering OK
[4/4] CLI default/raw checks
default output: 0.0005
raw_ascii: 00005440
raw_hex: 0x30303030353434300D
PASS: smoke test completed.
Example successful output (Mahr):
=== readDDI smoke test ===
family=mahr trials=3 cli_check=True
[1/4] prime_ddi baseline check
baseline ascii: -00.0105
baseline hex: 0x2D30302E303130350D
[2/4] trigger/read trial checks
trial 1: -00.0105
trial 2: -00.0105
trial 3: -00.0105
summary: nonempty=3/3, parseable=3/3
[3/4] raw mode rendering check (library path)
raw ascii/hex rendering OK
[4/4] CLI default/raw checks
default output: -0.0105
raw_ascii: -00.0105
raw_hex: 0x2D30302E303130350D
PASS: smoke test completed.
from ddi_init import prime_ddi, trigger_measurement, read_measurement
dev, ep_in, baseline = prime_ddi("mahr")
print("Baseline raw:", baseline.decode("ascii", errors="replace").strip())
for _ in range(5):
trigger_measurement(dev)
m = read_measurement(ep_in)
print("Measurement raw:", m.decode("ascii", errors="replace").strip())from ddi_init import prime_ddi, trigger_measurement, read_measurement
dev, ep_in, baseline = prime_ddi("mitutoyo_idc", mitutoyo_com_port="COM5")
print("Baseline raw:", baseline.decode("ascii", errors="replace").strip())
for _ in range(5):
trigger_measurement(dev)
m = read_measurement(ep_in)
print("Measurement raw:", m.decode("ascii", errors="replace").strip())Mitutoyo notes:
- Use
mitutoyo_com_portwith the exactUSB-ITN (COMx)value from Device Manager. mitutoyo_idcmode requires Mitutoyo VCP driverITVCP64.sys(not Zadig/WinUSB).- If
mitutoyo_com_portis omitted, the module defaultMITUTOYO_COM_PORTis used.
These two examples cover the common library workflows.
Use this map when onboarding, debugging, or proposing changes.
-
ddi_init.pyprime_ddi(...): one-time session setup + baseline readtrigger_measurement(...): family-aware remote triggerread_measurement(...): family-aware raw measurement read
-
ddi_remote_measurement.py- user-facing CLI wrapper around the stable workflow
- retry policy, output modes, and lightweight parsing for automation
mitutoyo_command_probe.py- exploratory command probing for Mitutoyo VCP path
- tiered scan mode, write-fault handling, JSON evidence export
captures/- packet captures and decoded traces used to validate behavior
- Appendix sections in this README
- capture interpretation, command findings, and recovery behavior
- If a change affects trigger/init timing or token behavior, update both:
- inline "why this is here" comments in code
- relevant README appendix/policy sections
- Preserve raw observability paths (
raw_ascii,raw_hex, probe JSON) unless a replacement is documented.
The driver is organized into four layers:
- Mahr backend: USB discovery + interface claim on Mahr FTDI device
- Mitutoyo backend: COM/VCP port open via Mitutoyo driver
The Mahr 1087 Ri requires a precise FTDI UART configuration:
- SetData 7E1
- RTS/DTR high
- Flow control off
- Intermediate baud
- RTS/DTR off
- 5× Reset/GetModemStat (SPC enable handshake)
- RTS/DTR high
- Final baud 19200
- SetData 7E2
- Idle: DTR low
This sequence was reverse‑engineered from USB captures of MarCom.
Every bulk packet begins with:
byte0: modem status
byte1: line status
For Mahr:
11 60
[sign][digits].[digits]\r
Example:
+02.7725\r
- Trigger → measurement: ~40–50 ms
- FTDI idle packets: ~32 ms interval
The Mahr gauge interprets a DTR rising edge as a remote measurement request after the FTDI UART engine is configured correctly.
+---------------------+
| USB Device Found |
+----------+----------+
|
v
+----------+----------+
| Claim Interface 0 |
+----------+----------+
|
v
+----------+----------+
| FTDI Init Start |
+----------+----------+
|
-------------------------------------------------
| | | |
v v v v
+-----------+ +-------------+ +-----------+ +-----------+
| SetData | | Flow Ctrl | | SetBaud | | ModemCtrl |
| (7E1) | | Off | | (09C4) | | (RTS/DTR) |
+-----------+ +-------------+ +-----------+ +-----------+
|
v
+----------+----------+
| SPC Handshake |
| (5× Reset/Stat) |
+----------+----------+
|
v
+----------+----------+
| Final UART Config |
| (7E2 @ 19200) |
+----------+----------+
|
v
+----------+----------+
| Idle: DTR Low |
+----------+----------+
|
v
+----------+----------+
| Trigger (DTR ↑) |
+----------+----------+
|
v
+----------+----------+
| Measurement Ready |
+---------------------+
Mitutoyo ID-C uses the validated VCP trigger path in this repository (Z\r over COM).
- Mahr (
mahr): trigger is a Mahr FTDI control-line pulse (DTR low→high rising edge). - Mitutoyo (
mitutoyo_idc): trigger is a VCP write ofZ\r(0x5A0D) to the USB-ITN-SF COM port.
- Mahr backend reads from Mahr FTDI bulk endpoint and returns:
[2‑byte FTDI status header][ASCII payload]
The driver:
-
strips the header
-
accumulates payload
-
stops at
\r -
Mitutoyo backend reads chunked VCP bytes, parses status/value fragments, and returns the raw value token (for example
00005040\r).
This function:
- Opens the selected backend (Mahr FTDI USB or Mitutoyo VCP/COM)
- Runs vendor‑specific init
- Performs a warm‑up trigger
- Reads and discards warm‑up output
- Performs up to 3 real triggers
- Returns the first valid measurement
bmRequestType: 0x40
bRequest: 0x04
wValue: 0x0207
wIndex: 0x0000
bRequest: 0x01
wValue: 0x0101
bRequest: 0x02
wValue: 0x0000
bRequest: 0x03
wValue: 0x09C4
Reset: bRequest=0x00
GetModemStat: bRequest=0x05
bRequest: 0x03
wValue: 0x0271
bRequest: 0x04
wValue: 0x1207
bRequest: 0x01
wValue: 0x0000
Validated path in this repository for mitutoyo_idc:
- Open Mitutoyo VCP COM port (
ITVCP64.sys) with 9600, 7E2 framing. - Send trigger payload:
ASCII: "Z\r"
HEX: 5A 0D
- Read chunked response bytes from COM.
- Parse measurement token from digit chunks (for example
00005040).
Notes:
- In USB captures, this maps to host→device control activity on EP0 via the Mitutoyo stack.
- This backend intentionally uses the VCP path, not direct FTDI/PyUSB.
bRequest: 0x01
wValue: 0x0100
bRequest: 0x01
wValue: 0x0101
Measurement arrives ~40–50 ms later.
Write to COM port: "Z\r"
Hex: 5A 0D
Typical response pattern (chunked):
- status/header-like token (for example
Q9F...) - digit token (for example
00005040) - terminator fragment (
...\r)
The Mahr FTDI chip emits periodic bulk‑IN packets even when idle:
11 60
These are status headers, not measurements.
A real measurement:
STATUS: 11 60
PAYLOAD: 2b 30 32 2e 37 37 32 35 0d
ASCII: "+02.7725\r"
For the validated Mitutoyo path, captures show repeated host→device trigger-related control activity before measurements, while user-space interaction remains a COM write of Z\r through ITVCP64.sys.
This appendix is intentionally split by platform:
- C.1 Mahr: direct FTDI USB packet semantics
- C.2 Mitutoyo: VCP-trigger semantics with control-transfer correlation
If you need to return the cable to COM‑port mode, you must manually reinstall the FTDI Virtual COM Port driver. Zadig does not provide an "undo" button; it replaces the driver association in the Windows driver store.
To restore the original FTDI VCP driver:
- Open Zadig again.
- Select the same device (VID 0403, PID 6001, Manufacturer FTDI).
- In the driver selection box, choose:
- USB Serial (FTDI)
- or FTDI (VCP)
- FTDI CDM
(The exact label depends on your FTDI driver version.)
- Click Replace Driver.
- Unplug and replug the cable.
- Verify in Device Manager that you now see:
- USB Serial Converter under USB Controllers
- USB Serial Port (COMx) under Ports (COM & LPT)
Once restored, the cable will behave like a normal FTDI serial device again and MarCom will detect it.
If Zadig does not show any of the FTDI VCP options:
- USB Serial (FTDI)
- FTDI (VCP)
- FTDI CDM
…and the device appears only under Universal Serial Bus devices as a WinUSB Device, then Windows is no longer associating the hardware with the FTDI driver class. This happens because Zadig updates the driver binding in the Windows driver store, and Windows will continue to load WinUSB for this VID/PID until the FTDI drivers are explicitly reinstalled.
To restore the FTDI VCP driver options, use one of the following procedures:
- Download the official FTDI VCP driver package from FTDI:
https://ftdichip.com/drivers/vcp-drivers/ - Run the installer (CDMxxxxxx.exe).
- Unplug and replug the cable.
- Open Zadig again.
- The FTDI driver options should now appear in the right‑hand driver list.
- Select USB Serial (FTDI) (or equivalent) and click Replace Driver to restore COM‑port behavior.
- Open Device Manager.
- Expand Universal Serial Bus devices.
- Right‑click the WinUSB‑bound device (VID 0403 / PID 6001).
- Select Uninstall device.
- Check Delete the driver software for this device if available.
- Unplug and replug the cable.
- Windows should now prompt for a driver or automatically install the FTDI driver if present in the driver store.
- If it does not, install the FTDI CDM package as in Option A.
MarCom bundles FTDI's CDM drivers. Reinstalling MarCom will:
- restore the FTDI driver association
- repopulate the Windows driver store
- allow Zadig to see the FTDI VCP options again
After reinstalling MarCom, unplug and replug the cable, then reopen Zadig.
- Switching to WinUSB is required for PyUSB and this project's pure‑USB DDI driver
- After switching to WinUSB, the cable will not revert to a COM port automatically
- Zadig modifies the driver association persistently; unplugging does not revert it
- To restore COM port behavior, you must manually reinstall the FTDI VCP driver using one of the methods above
- Once restored, you can switch between WinUSB and FTDI drivers as needed
If you installed the Mitutoyo VCP driver and need to return to HID-class behavior:
- Open Device Manager.
- Locate the Mitutoyo USB-ITN-SF device (VID
0FE7, PID4001), See Details->Hardware Ids for the USB-ITN (COMx) device. - Open Update driver / Browse my computer / Let me pick.
- Select the appropriate HID-class device option (or uninstall current device and driver package so Windows re-enumerates with default class binding).
- Unplug/replug and confirm the device appears under the HID class instead of COM Ports.
Important:
- Exact device class labels can vary by installed package and Windows build.
- Always follow the official Mitutoyo USB-ITPAK manual guidance for your release when changing driver mode.
- Official reference: USB-ITPAK V3.0 No. 99MAM030A2, section "2.3 Installing the VCP Driver".
mitutoyo_idcmode in this repository requires Mitutoyo VCP (ITVCP64.sys) and a COM port.- If COM is missing, verify the VCP driver is installed and bound.
- If you intentionally switch away from VCP (for example to HID), this repository’s Mitutoyo VCP backend will no longer communicate until VCP is restored.
This appendix records command/response findings observed on:
- Indicator: Mitutoyo 543-700B ID-C0512NXB
- Cable: USB-ITN-SF (VCP path)
- Tooling:
mitutoyo_command_probe.pyand700B_test_01.pcapng
Q* command traffic appears before Z trigger traffic in the captured initialization/control phase.
- First observed
Q*frame:1526 - First observed
Zframe:3002
This supports the interpretation that Q* is likely identification/status/config query traffic, while Z is measurement trigger/read traffic (with \r used as the command terminator for these tokens).
From the sequence probe (Q0A,Q01,Q02,Q3D,Q03,...,P930101,Z):
-
Q01returned serial-number field data:- Example ASCII:
QAF010863498712\r - Parsed value: serial
63498712
- Example ASCII:
-
Q02returned code-number field data:- Example ASCII:
QAF0208543-700B\r - Parsed value: code no.
543-700B
- Example ASCII:
-
Q3Dreturned model field data:- Example ASCII:
QAF3D0BID-C0512NXB\r - Parsed value: model
ID-C0512NXB
- Example ASCII:
-
Q03returned status/flag-like field data:- Example ASCII:
QAF0300\r
- Example ASCII:
-
Q0Areturned an additional metadata/config-like block:- Example ASCII:
QAF0A06000000250400\r
- Example ASCII:
-
P930101returned an acknowledge/parameter-like response:- Example ASCII:
PAF930106\r
- Example ASCII:
-
P8D00was confirmed as a zero command on 543-700B:- Single-shot command:
P8D00\r - Validation method: live observation of DDI display behavior during controlled fixture test
- Single-shot command:
-
P920101was observed to power off / disable active display state on 543-700B:- Single-shot command:
P920101\r - Response observed:
PAF920106\r - Validation method: live observation of DDI display behavior during controlled fixture test
- Additional behavior: after
P920101,Ztrigger can return empty response until device power is restored
- Single-shot command:
-
Zreturned measurement-style response frames:- Example ASCII:
Q9F75000000250400\r - Additional observed example:
Q9F78000279454400\r(contains magnitude2794, i.e. ~2.794in current unit scaling) - Post-recovery observed example:
Q9F7A000279504400\r(magnitude matches observed DDI display ~2.795)
- Example ASCII:
-
Recovery finding after
P920101disable state:- Software recovery attempts using
P940101,P930101,P8E00,P8D00did not restoreZresponses in the same powered session - Power-cycle of the DDI restored normal operation (
Q01query response + validZmeasurement response)
- Software recovery attempts using
Observed behavior is consistent with this practical state model:
-
ON / Measurement-EnabledQ*queries respondZreturns measurement frames
-
P920101issued- transitions device to
OFF / Measurement-Latched-Disabled
- transitions device to
-
OFF / Measurement-Latched-DisabledQ*may still respondZmay return empty- tested software commands (
P940101,P930101,P8E00,P8D00) did not clear latch in-session
-
Power-cycle- restores
ON / Measurement-Enabled Q*andZboth return valid responses again
- restores
Z\r: trigger/read measurement pathQ*\r: query/identify/status pathP*\r: parameter/action path (state-changing commands confirmed)
- Unsupported tokens can produce COM write failures (
Win32 error 31) on this setup. - Keep exploratory tests tiered and one-token-at-a-time after baseline checks.
- Use known-stable baseline commands (
Z,R,1) to confirm communications before testing new tokens.
mitutoyo_command_probe.py opens the Mitutoyo VCP port (9600, 7E2), sends each candidate token as ASCII (by default appending \r), then captures response bytes for a short window and summarizes responses per command.
For each command token, the script records:
- payload bytes sent (
payload_hex) - response bytes (
response_hex) - decoded ASCII response (
response_ascii) - simple measurement-like flag (
measurement_like)
It also supports:
- write retries on serial faults (
--write-retries) - continue-on-error logging (default) or strict abort (
--fail-fast) - tiered scan mode (
--tiered-scan) to run baseline-safe tokens first, then exploratory tokens one-by-one
Outputs can be written to JSON for later diffing and analysis (--json-out).
Baseline-safe confirmation (Z, R, 1):
py mitutoyo_command_probe.py --port COM5 --candidates Z,R,1 --repeat 3 --read-window 0.30 --settle-ms 300 --write-retries 4 --json-out probe_confirm_safe_tokens.jsonTiered scan with stop on first fault:
py mitutoyo_command_probe.py --port COM5 --candidates Z,R,Q,?,P,S,T,D,M,A,B,C,1,2,3 --tiered-scan --tier0-candidates Z,R,1 --tier1-candidates Q,?,P,S,T,D,M,A,B,C,2,3 --tier-stop-on-error --repeat 3 --read-window 0.30 --settle-ms 300 --write-retries 4 --json-out probe_tiered.jsonSingle-shot zero candidate test (confirmed zero token on this setup):
py mitutoyo_command_probe.py --port COM5 --candidates P8D00 --repeat 1 --read-window 0.40 --settle-ms 500 --write-retries 4 --fail-fast --json-out probe_single_P8D00.jsonYou are still using the FTDI VCP driver.
Install WinUSB via Zadig.
Check:
- Gauge is awake
- Cable fully inserted
- Initialization completed
- Trigger is being sent
Normal for warm‑up.
prime_ddi() handles this.
- Confirm USB-ITN-SF is using
ITVCP64.sys. - Confirm Device Manager shows
USB-ITN (COMx). - Pass that exact port with
--port.
- This can happen with intermittent status-only reads.
- The CLI includes per-trial retries; increase trial delay if needed.
- Use
--raw_asciior--raw_hexto inspect response payloads directly.
+----------------------+
| Start Measurement |
+----------+-----------+
|
v
+----------+-----------+
| prime_ddi() called? |
+----+-------------+---+
| |
No Yes
| |
v v
+-------------+---+ +-----+----------------+
| Call prime_ddi() | | Trigger measurement |
+------------------+ +----------+----------+
|
v
+----------+----------+
| read_measurement() |
+----------+----------+
|
v
+--------------------+--------------------+
| Measurement ends with '\r'? |
+-----------+------------------------------+
|
+----------+----------+
| |
No Yes
| |
v v
+---------------+---------+ +--------+----------------+
| Increase timeout / | | Print measurement |
| check cable / gauge | | (success) |
+--------------------------+ +-------------------------+
- License: This project is released under the MIT License. See LICENSE.
- Third-party components: Bundled third-party binaries (including
libusb-1.0.dll) are licensed separately; see docs/legal/THIRD_PARTY_NOTICES.md. - Authorship: The project author is onetablespoon.
- AI-Assisted Development Acknowledgment: Parts of implementation, refactoring, and documentation were developed with assistance from GitHub Copilot (including multiple model variants) under maintainer direction and review.
Mitutoyo and Mahr are trademarks of their respective owners.
This project is an independent, community-developed compatibility effort and is not affiliated with, endorsed by, or sponsored by Mitutoyo or Mahr.
The project focuses on interoperability with user-owned hardware and does not include or redistribute vendor proprietary firmware or source code.
Legal note: this repository is provided for technical interoperability and research purposes; users are responsible for compliance with applicable laws, regulations, and agreements in their jurisdiction.