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,109 @@ 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 file = File :: create ( "/home/lanza/Projets/HMD_JSON.gz" )
373+ . map_err ( |_| Error :: ProtocolError ( "Impossible de créer le fichier" ) ) ?;
374+ file. write ( gz_file_buffer. as_slice ( ) )
375+ . map_err ( |_| Error :: ProtocolError ( "Impossible d’écrire le fichier" ) ) ?;
376+
377+ let mut dec = GzDecoder :: new ( gz_file_buffer. as_slice ( ) ) ;
378+ let mut config = String :: new ( ) ;
379+ dec. read_to_string ( & mut config) ?;
380+
381+ info ! ( "config: {config}" ) ;
382+
383+ serde_json:: from_str ( & config) . map_err ( |_| Error :: ConfigReadFailed )
384+ }
385+ pub fn read_stream ( & self , filename : & [ u8 ] ) -> Result < Vec :: < u8 > > {
386+ let mut report = [ 0u8 ; 65 ] ;
387+
388+ report[ 0 ] = 0x00 ; // id 0 -> root of the Application collection.
389+ report[ 1 ] = 0x10 ; // the command I presume ?
390+ report[ 2 ] = 0x00 ; // commant 2nd part ?
391+ report[ 3 ] = filename. len ( ) as u8 ; // payload size
392+ report[ 4 ] = 0xff ; // separator ?
393+ report[ 5 ..] [ ..filename. len ( ) ] . copy_from_slice ( filename) ;
394+
395+ let total_len = {
396+ self . 0 . send_feature_report ( & report) ?;
397+
398+ loop {
399+ self . 0 . get_feature_report ( & mut report) ?;
400+ if report[ 0 ] != 0x00 { return Err ( Error :: ProtocolError ( "unknown data received." ) ) }
401+ if report[ 1 ] == 0x10 { break ; }
402+ }
403+
404+ let mut total_len = [ 0u8 ; 4 ] ;
405+ total_len. copy_from_slice ( & report[ 5 ..9 ] ) ;
406+ u32:: from_le_bytes ( total_len) as usize
407+ } ;
408+ info ! ( "config read length : {total_len}" ) ;
409+
410+ let mut position = 0x0 as usize ;
411+ let mut out = Vec :: < u8 > :: with_capacity ( total_len) ;
412+
413+ while position < total_len {
414+ report = [ 0u8 ; 65 ] ;
415+ report[ 1 ] = 0x11 ;
416+ report[ 2 ] = 0x00 ;
417+ report[ 3 ] = 0x08 ; //payload size;
418+ report[ 4 ] = 0x80 ; // separator ?
419+ report[ 5 ..9 ] . copy_from_slice ( & u32:: to_le_bytes ( position as u32 ) ) ; // start position
420+ report[ 9 ] = 0x38 ;
421+
422+ self . 0 . send_feature_report ( & report) ?;
423+ loop {
424+ self . 0 . get_feature_report ( & mut report) ?;
425+ if report[ 0 ] != 0x00 { return Err ( Error :: ProtocolError ( "unknown data received." ) ) }
426+ if report[ 1 ] == 0x11 { break ; }
427+ }
428+
429+ let size = ( report[ 3 ] - 0x04 ) as usize ;
430+ out. extend_from_slice ( & report[ 5 ..5 + size] ) ;
431+
432+ position = position + size;
433+ info ! ( "position: {position}, size: {size}" ) ;
434+ }
435+ if position != total_len {
436+ return Err ( Error :: ProtocolError ( "config size mismatch" ) ) ;
437+ }
438+
439+ Ok ( out)
440+ }
441+ }
0 commit comments