1
1
use std:: { io:: Read , result} ;
2
2
3
- use flate2:: read:: ZlibDecoder ;
3
+ use flate2:: { read:: { ZlibDecoder , GzDecoder } , DecompressError } ;
4
4
use hidapi:: { HidApi , HidDevice , HidError } ;
5
5
use once_cell:: sync:: OnceCell ;
6
6
use serde:: Deserialize ;
7
7
use serde_json:: Value ;
8
- use tracing:: error;
8
+ use tracing:: { error, info } ;
9
9
10
10
#[ derive( thiserror:: Error , Debug ) ]
11
11
pub enum Error {
@@ -21,6 +21,10 @@ pub enum Error {
21
21
ConfigReadFailed ,
22
22
#[ error( "protocol error: {0}" ) ]
23
23
ProtocolError ( & ' static str ) ,
24
+ #[ error( "deflate error: {0}" ) ]
25
+ DeflateError ( #[ from] DecompressError ) ,
26
+ #[ error( "IO error: {0}" ) ]
27
+ IOError ( #[ from] std:: io:: Error ) ,
24
28
}
25
29
26
30
type Result < T , E = Error > = result:: Result < T , E > ;
@@ -134,7 +138,8 @@ impl SteamDevice {
134
138
}
135
139
136
140
const 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 ;
138
143
139
144
#[ derive( Deserialize , Debug ) ]
140
145
pub struct ViveConfig {
@@ -175,11 +180,11 @@ const VIVE_PRO_2_MODES: [Mode; 6] = [
175
180
Mode :: new ( 5 , 2896 , 2448 , 120.0 ) ,
176
181
] ;
177
182
178
- pub struct ViveDevice ( HidDevice ) ;
179
- impl ViveDevice {
183
+ pub struct VivePro2Device ( HidDevice ) ;
184
+ impl VivePro2Device {
180
185
pub fn open_first ( ) -> Result < Self > {
181
186
let api = get_hidapi ( ) ?;
182
- let device = api. open ( VIVE_VID , VIVE_PID ) ?;
187
+ let device = api. open ( VIVE_VID , VIVE_PRO_2_PID ) ?;
183
188
Ok ( Self ( device) )
184
189
}
185
190
pub fn open ( sn : & str ) -> Result < Self > {
@@ -188,7 +193,7 @@ impl ViveDevice {
188
193
. device_list ( )
189
194
. find ( |dev| dev. serial_number ( ) == Some ( sn) )
190
195
. 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 {
192
197
return Err ( Error :: NotAVive ) ;
193
198
}
194
199
let open = api. open_serial ( device. vendor_id ( ) , device. product_id ( ) , sn) ?;
@@ -285,7 +290,7 @@ impl ViveDevice {
285
290
286
291
serde_json:: from_str ( & string) . map_err ( |_| Error :: ConfigReadFailed )
287
292
}
288
- /// Always returns at least one mode
293
+ // Always returns at least one mode
289
294
pub fn query_modes ( & self ) -> Vec < Mode > {
290
295
VIVE_PRO_2_MODES . into_iter ( ) . collect ( )
291
296
}
@@ -328,3 +333,109 @@ impl ViveDevice {
328
333
Ok ( ( ) )
329
334
}
330
335
}
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