‹ projects

reverb-m1

Native wired VR on Apple silicon: Reverb G1 display bring-up and stereo demo
git clone https://umhau.org/code/reverb-m1.git
Log | Files | Refs

hmdwake.swift (3502B)


      1 // Wakes the HP Reverb G1 (sequence from Monado wmr_hmd_activate_reverb), starts the IMU, and logs
      2 // every control-device report with timestamps. Args: `passive` = send nothing, just listen.
      3 // SIGUSR1 = resend screen_on, SIGUSR2 = screen off then on.
      4 import Foundation
      5 import IOKit.hid
      6 setvbuf(stdout, nil, _IOLBF, 0)
      7 
      8 func hex(_ b: [UInt8]) -> String { b.map { String(format: "%02x", $0) }.joined(separator: " ") }
      9 func log(_ s: String) { print(String(format: "%.3f ", Date().timeIntervalSince1970) + s) }
     10 var managers: [IOHIDManager] = []  // must outlive the devices, or they get closed
     11 func open(_ vid: Int, _ pid: Int) -> IOHIDDevice? {
     12     let m = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
     13     IOHIDManagerSetDeviceMatching(m, [kIOHIDVendorIDKey: vid, kIOHIDProductIDKey: pid] as CFDictionary)
     14     guard IOHIDManagerOpen(m, IOOptionBits(kIOHIDOptionsTypeNone)) == kIOReturnSuccess else { return nil }
     15     managers.append(m)
     16     return (IOHIDManagerCopyDevices(m) as? Set<IOHIDDevice>)?.first
     17 }
     18 guard let ctl = open(0x03f0, 0x0c6a) else { log("QHMD control device not found"); exit(1) }
     19 log("opened QHMD control device")
     20 
     21 func setFeature(_ b: [UInt8], _ what: String) {
     22     let r = IOHIDDeviceSetReport(ctl, kIOHIDReportTypeFeature, CFIndex(b[0]), b, b.count)
     23     log("set \(what): " + (r == kIOReturnSuccess ? "ok" : String(format: "err 0x%08x", r)))
     24 }
     25 func getFeature(_ id: UInt8) {
     26     var b = [UInt8](repeating: 0, count: 64); b[0] = id; var n = CFIndex(64)
     27     let r = IOHIDDeviceGetReport(ctl, kIOHIDReportTypeFeature, CFIndex(id), &b, &n)
     28     log("get 0x\(String(format: "%02x", id)): " + (r == kIOReturnSuccess ? "ok (feature payload omitted for privacy)" : String(format: "err 0x%08x", r)))
     29 }
     30 
     31 let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: 64)
     32 IOHIDDeviceRegisterInputReportCallback(ctl, buf, 64, { _, _, _, _, _, r, n in
     33     log("control report received (payload omitted for privacy)")
     34 }, nil)
     35 IOHIDDeviceScheduleWithRunLoop(ctl, CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue)
     36 
     37 if CommandLine.arguments.contains("passive") {
     38     log("PASSIVE: listening only")
     39 } else {
     40     usleep(300_000)
     41     for _ in 0..<4 {
     42         var c = [UInt8](repeating: 0, count: 64); c[0] = 0x50; c[1] = 0x01
     43         setFeature(c, "activate 0x50"); getFeature(0x50); usleep(10_000)
     44     }
     45     getFeature(0x09); getFeature(0x08); getFeature(0x06)
     46     setFeature([0x04, 0x01], "screen_on")
     47     if let sens = open(0x045e, 0x0659) {
     48         var c = [UInt8](repeating: 0, count: 64); c[0] = 0x02; c[1] = 0x07
     49         let r = IOHIDDeviceSetReport(sens, kIOHIDReportTypeOutput, 0x02, c, c.count)
     50         log("imu_on: " + (r == kIOReturnSuccess ? "ok" : String(format: "err 0x%08x", r)))
     51         let sb = UnsafeMutablePointer<UInt8>.allocate(capacity: 512)
     52         IOHIDDeviceRegisterInputReportCallback(sens, sb, 512, { _, _, _, _, _, _, _ in }, nil) // keep stream drained
     53         IOHIDDeviceScheduleWithRunLoop(sens, CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue)
     54     } else { log("HoloLens Sensors not found") }
     55 }
     56 signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN)
     57 let s1 = DispatchSource.makeSignalSource(signal: SIGUSR1, queue: .main)
     58 s1.setEventHandler { setFeature([0x04, 0x01], "screen_on (USR1)") }; s1.resume()
     59 let s2 = DispatchSource.makeSignalSource(signal: SIGUSR2, queue: .main)
     60 s2.setEventHandler { setFeature([0x04, 0x00], "screen_off (USR2)"); usleep(500_000); setFeature([0x04, 0x01], "screen_on (USR2)") }; s2.resume()
     61 CFRunLoopRun()