#!/usr/bin/env python3 """Passively sample SteamVR's VR_CameraPassthroughState shared memory. Only reads a tmpfs file. It makes no SteamVR calls, takes no locks and opens no devices, so it cannot disturb passthrough or tracking. Readings may occasionally tear (the writer holds a mutex we deliberately ignore); that is acceptable for exploration. Per-frame records are found by their gamma marker (1/2.2 as float32). For each record whose frame counter changed, one CSV row is written with the raw fields around the marker, so we can see which ones track light. With --raw PATH, every snapshot is also appended to PATH as [float64 time][STATE_SIZE bytes] so it can be re-parsed offline. Usage: shm_sampler.py [--seconds N] [--hz N] [--out PATH] [--raw PATH] [--shm PATH] """ import argparse import glob import os import struct import sys import time GAMMA = struct.pack("= 0: yield start, pos pos = buf.find(GAMMA, pos + 4) def main(): ap = argparse.ArgumentParser() ap.add_argument("--seconds", type=float, default=120) ap.add_argument("--hz", type=float, default=20) ap.add_argument("--out", default="shm_samples.csv") ap.add_argument("--raw") ap.add_argument("--shm") args = ap.parse_args() path = args.shm or find_state_file() header = ["t", "offset", "stream", "id", "frame", "ts0", "ts1", "fx", "fy", "cx", "cy"] header += [f"g{i}" for i in range(FIELDS_AFTER_GAMMA)] + ["owner", "seq", "config"] last_frame = {} t0 = time.monotonic() raw = open(args.raw, "wb") if args.raw else None with open(args.out, "w") as out, open(path, "rb") as f: out.write(",".join(header) + "\n") while time.monotonic() - t0 < args.seconds: f.seek(0) buf = f.read(STATE_SIZE) now = time.monotonic() - t0 if raw: raw.write(struct.pack("= 0x20E8 else 0 row = [f"{now:.3f}", hex(start), str(stream), str(ident), str(frame), f"{ts0:.4f}", f"{ts1:.4f}", f"{fx:.1f}", f"{fy:.1f}", f"{cx:.1f}", f"{cy:.1f}"] row += [f"{v:.6g}" for v in fields] + [str(owner), str(seq), config] out.write(",".join(row) + "\n") time.sleep(1 / args.hz) if raw: raw.close() if __name__ == "__main__": main()