11use std:: { io:: Read , result} ;
22
3- use flate2:: read:: ZlibDecoder ;
3+ use flate2:: { read:: { ZlibDecoder , GzDecoder } , DecompressError } ;
44use hidapi:: { HidApi , HidDevice , HidError } ;
55use once_cell:: sync:: OnceCell ;
66use serde:: Deserialize ;
77use serde_json:: Value ;
8- use tracing:: error;
8+ use tracing:: { error, info } ;
99
1010#[ derive( thiserror:: Error , Debug ) ]
1111pub enum Error {
@@ -21,6 +21,10 @@ pub enum Error {
2121 ConfigReadFailed ,
2222 #[ error( "protocol error: {0}" ) ]
2323 ProtocolError ( & ' static str ) ,
24+ #[ error( "deflate error: {0}" ) ]
25+ DeflateError ( #[ from] DecompressError ) ,
26+ #[ error( "IO error: {0}" ) ]
27+ IOError ( #[ from] std:: io:: Error ) ,
2428}
2529
2630type Result < T , E = Error > = result:: Result < T , E > ;
@@ -134,7 +138,8 @@ impl SteamDevice {
134138}
135139
136140const VIVE_VID : u16 = 0x0bb4 ;
137- const VIVE_PID : u16 = 0x0342 ;
141+ const VIVE_PRO_2_PID : u16 = 0x0342 ;
142+ const VIVE_COSMOS_PID : u16 = 0x0313 ;
138143
139144#[ derive( Deserialize , Debug ) ]
140145pub struct ViveConfig {
@@ -175,11 +180,11 @@ const VIVE_PRO_2_MODES: [Mode; 6] = [
175180 Mode :: new ( 5 , 2896 , 2448 , 120.0 ) ,
176181] ;
177182
178- pub struct ViveDevice ( HidDevice ) ;
179- impl ViveDevice {
183+ pub struct VivePro2Device ( HidDevice ) ;
184+ impl VivePro2Device {
180185 pub fn open_first ( ) -> Result < Self > {
181186 let api = get_hidapi ( ) ?;
182- let device = api. open ( VIVE_VID , VIVE_PID ) ?;
187+ let device = api. open ( VIVE_VID , VIVE_PRO_2_PID ) ?;
183188 Ok ( Self ( device) )
184189 }
185190 pub fn open ( sn : & str ) -> Result < Self > {
@@ -188,7 +193,7 @@ impl ViveDevice {
188193 . device_list ( )
189194 . find ( |dev| dev. serial_number ( ) == Some ( sn) )
190195 . ok_or ( Error :: DeviceNotFound ) ?;
191- if device. vendor_id ( ) != VIVE_VID || device. product_id ( ) != VIVE_PID {
196+ if device. vendor_id ( ) != VIVE_VID || device. product_id ( ) != VIVE_PRO_2_PID {
192197 return Err ( Error :: NotAVive ) ;
193198 }
194199 let open = api. open_serial ( device. vendor_id ( ) , device. product_id ( ) , sn) ?;
@@ -285,7 +290,7 @@ impl ViveDevice {
285290
286291 serde_json:: from_str ( & string) . map_err ( |_| Error :: ConfigReadFailed )
287292 }
288- /// Always returns at least one mode
293+ // Always returns at least one mode
289294 pub fn query_modes ( & self ) -> Vec < Mode > {
290295 VIVE_PRO_2_MODES . into_iter ( ) . collect ( )
291296 }
@@ -328,3 +333,104 @@ impl ViveDevice {
328333 Ok ( ( ) )
329334 }
330335}
336+
337+ const VIVE_COSMOS_MODES : [ Mode ; 1 ] = [
338+ Mode :: new ( 0 , 2880 , 1700 , 90.0 ) ,
339+ ] ;
340+
341+ pub struct ViveCosmosDevice ( HidDevice ) ;
342+ use std:: fs:: File ;
343+ use std:: io:: prelude:: * ;
344+ impl ViveCosmosDevice {
345+
346+ pub fn open_first ( ) -> Result < Self > {
347+ let api = get_hidapi ( ) ?;
348+ let device = api. open ( VIVE_VID , VIVE_COSMOS_PID ) ?;
349+ Ok ( Self ( device) )
350+ }
351+ pub fn open ( sn : & str ) -> Result < Self > {
352+ let api = get_hidapi ( ) ?;
353+ let device = api
354+ . device_list ( )
355+ . find ( |dev| dev. serial_number ( ) == Some ( sn) )
356+ . ok_or ( Error :: DeviceNotFound ) ?;
357+ if device. vendor_id ( ) != VIVE_VID || device. product_id ( ) != VIVE_COSMOS_PID {
358+ return Err ( Error :: NotAVive ) ;
359+ }
360+ let open = api. open_serial ( device. vendor_id ( ) , device. product_id ( ) , sn) ?;
361+ Ok ( Self ( open) )
362+ }
363+ // Always returns at least one mode
364+ pub fn query_modes ( & self ) -> Vec < Mode > {
365+ VIVE_COSMOS_MODES . into_iter ( ) . collect ( )
366+ }
367+ pub fn read_config ( & self ) -> Result < ViveConfig > {
368+ let gz_file_buffer = self . read_stream ( b"HMD_JSON.gz" ) ?;
369+
370+ info ! ( "received gzipped config file" ) ;
371+
372+ let mut dec = GzDecoder :: new ( gz_file_buffer. as_slice ( ) ) ;
373+ let mut config = String :: new ( ) ;
374+ dec. read_to_string ( & mut config) ?;
375+
376+ info ! ( "config: {config}" ) ;
377+
378+ serde_json:: from_str ( & config) . map_err ( |_| Error :: ConfigReadFailed )
379+ }
380+ pub fn read_stream ( & self , filename : & [ u8 ] ) -> Result < Vec :: < u8 > > {
381+ let mut report = [ 0u8 ; 65 ] ;
382+
383+ report[ 0 ] = 0x00 ; // id 0 -> root of the Application collection.
384+ report[ 1 ] = 0x10 ; // the command I presume ?
385+ report[ 2 ] = 0x00 ; // commant 2nd part ?
386+ report[ 3 ] = filename. len ( ) as u8 ; // payload size
387+ report[ 4 ] = 0xff ; // separator ?
388+ report[ 5 ..] [ ..filename. len ( ) ] . copy_from_slice ( filename) ;
389+
390+ let total_len = {
391+ self . 0 . send_feature_report ( & report) ?;
392+
393+ loop {
394+ self . 0 . get_feature_report ( & mut report) ?;
395+ if report[ 0 ] != 0x00 { return Err ( Error :: ProtocolError ( "unknown data received." ) ) }
396+ if report[ 1 ] == 0x10 { break ; }
397+ }
398+
399+ let mut total_len = [ 0u8 ; 4 ] ;
400+ total_len. copy_from_slice ( & report[ 5 ..9 ] ) ;
401+ u32:: from_le_bytes ( total_len) as usize
402+ } ;
403+ info ! ( "config read length : {total_len}" ) ;
404+
405+ let mut position = 0x0 as usize ;
406+ let mut out = Vec :: < u8 > :: with_capacity ( total_len) ;
407+
408+ while position < total_len {
409+ report = [ 0u8 ; 65 ] ;
410+ report[ 1 ] = 0x11 ;
411+ report[ 2 ] = 0x00 ;
412+ report[ 3 ] = 0x08 ; //payload size;
413+ report[ 4 ] = 0x80 ; // separator ?
414+ report[ 5 ..9 ] . copy_from_slice ( & u32:: to_le_bytes ( position as u32 ) ) ; // start position
415+ report[ 9 ] = 0x38 ;
416+
417+ self . 0 . send_feature_report ( & report) ?;
418+ loop {
419+ self . 0 . get_feature_report ( & mut report) ?;
420+ if report[ 0 ] != 0x00 { return Err ( Error :: ProtocolError ( "unknown data received." ) ) }
421+ if report[ 1 ] == 0x11 { break ; }
422+ }
423+
424+ let size = ( report[ 3 ] - 0x04 ) as usize ;
425+ out. extend_from_slice ( & report[ 5 ..5 + size] ) ;
426+
427+ position = position + size;
428+ info ! ( "position: {position}, size: {size}" ) ;
429+ }
430+ if position != total_len {
431+ return Err ( Error :: ProtocolError ( "config size mismatch" ) ) ;
432+ }
433+
434+ Ok ( out)
435+ }
436+ }
0 commit comments