From 94be8ccdbfb2f44c9bc569428537444030ba8eeb Mon Sep 17 00:00:00 2001 From: mwturvey Date: Fri, 17 Mar 2017 13:46:34 -0700 Subject: Wired Watchman Now Emit Light & IMU Data --- data_recorder.c | 2 + src/survive_vive.c | 101 +++++++++++++++++++++++++++++++++++++++++------- test.c | 3 ++ winbuild/libsurvive.sln | 20 ++++++++++ 4 files changed, 111 insertions(+), 15 deletions(-) diff --git a/data_recorder.c b/data_recorder.c index 5504d42..206c6c3 100644 --- a/data_recorder.c +++ b/data_recorder.c @@ -1,6 +1,8 @@ //Data recorder mod with GUI showing light positions. +#ifdef __linux__ #include +#endif #include #include #include diff --git a/src/survive_vive.c b/src/survive_vive.c index 1929b1a..d4a853d 100755 --- a/src/survive_vive.c +++ b/src/survive_vive.c @@ -39,13 +39,15 @@ struct SurviveViveData; const short vidpids[] = { - 0x0bb4, 0x2c87, 0, //The main HTC HMD device - 0x28de, 0x2000, 0, //Valve lighthouse + 0x0bb4, 0x2c87, 0, //Valve HMD Button and face proximity sensor + 0x28de, 0x2000, 0, //Valve HMD IMU & Lighthouse Sensors 0x28de, 0x2101, 0, //Valve Watchman 0x28de, 0x2101, 1, //Valve Watchman 0x28de, 0x2022, 0, //HTC Tracker + 0x28de, 0x2012, 0, //Valve Watchman, USB connected #ifdef HIDAPI - 0x28de, 0x2000, 1, //Valve lighthouse(B) (only used on HIDAPI, for lightcap) + 0x28de, 0x2000, 1, //Valve HMD lighthouse(B) (only used on HIDAPI, for lightcap) + 0x28de, 0x2012, 1, //Valve Watchman, USB connected (only used on HIDAPI, for lightcap) #endif }; //length MAX_USB_INTERFACES*2 @@ -55,8 +57,10 @@ const char * devnames[] = { "Watchman 1", "Watchman 2", "Tracker 0", + "Wired Watchman 1", #ifdef HIDAPI - "Lightcap", + "HMD Lightcap", + "Wired Watchman 1 Lightcap", #endif }; //length MAX_USB_INTERFACES @@ -66,12 +70,14 @@ const char * devnames[] = { #define USB_DEV_WATCHMAN1 2 #define USB_DEV_WATCHMAN2 3 #define USB_DEV_TRACKER0 4 +#define USB_DEV_W_WATCHMAN1 5 // Wired Watchman attached via USB #ifdef HIDAPI -#define USB_DEV_LIGHTHOUSEB 5 -#define MAX_USB_DEVS 6 +#define USB_DEV_LIGHTHOUSEB 6 +#define USB_DEV_W_WATCHMAN1_LIGHTCAP 7 +#define MAX_USB_DEVS 8 #else -#define MAX_USB_DEVS 5 +#define MAX_USB_DEVS 6 #endif #define USB_IF_HMD 0 @@ -79,8 +85,10 @@ const char * devnames[] = { #define USB_IF_WATCHMAN1 2 #define USB_IF_WATCHMAN2 3 #define USB_IF_TRACKER0 4 -#define USB_IF_LIGHTCAP 5 -#define MAX_INTERFACES 6 +#define USB_IF_W_WATCHMAN1 5 +#define USB_IF_LIGHTCAP 6 +#define USB_IF_W_WATCHMAN1_LIGHTCAP 7 +#define MAX_INTERFACES 8 typedef struct SurviveUSBInterface SurviveUSBInterface; typedef struct SurviveViveData SurviveViveData; @@ -299,7 +307,7 @@ static inline int hid_get_feature_report_timeout(USBHANDLE device, uint16_t ifac return -1; } -int survive_usb_init( struct SurviveViveData * sv, struct SurviveObject * hmd, struct SurviveObject *wm0, struct SurviveObject * wm1, struct SurviveObject * tr0 ) +int survive_usb_init( struct SurviveViveData * sv, struct SurviveObject * hmd, struct SurviveObject *wm0, struct SurviveObject * wm1, struct SurviveObject * tr0 , struct SurviveObject * ww0 ) { struct SurviveContext * ctx = sv->ctx; #ifdef HIDAPI @@ -463,11 +471,14 @@ int survive_usb_init( struct SurviveViveData * sv, struct SurviveObject * hmd, s if( sv->udev[USB_DEV_WATCHMAN1] && AttachInterface( sv, wm0, USB_IF_WATCHMAN1, sv->udev[USB_DEV_WATCHMAN1], 0x81, survive_data_cb, "Watchman 1" ) ) { return -8; } if( sv->udev[USB_DEV_WATCHMAN2] && AttachInterface( sv, wm1, USB_IF_WATCHMAN2, sv->udev[USB_DEV_WATCHMAN2], 0x81, survive_data_cb, "Watchman 2")) { return -9; } if( sv->udev[USB_DEV_TRACKER0] && AttachInterface( sv, tr0, USB_IF_TRACKER0, sv->udev[USB_DEV_TRACKER0], 0x81, survive_data_cb, "Tracker 1")) { return -10; } + if( sv->udev[USB_DEV_W_WATCHMAN1] && AttachInterface( sv, ww0, USB_IF_W_WATCHMAN1, sv->udev[USB_DEV_W_WATCHMAN1], 0x81, survive_data_cb, "Wired Watchman 1")) { return -11; } #ifdef HIDAPI //Tricky: use other interface for actual lightcap. XXX THIS IS NOT YET RIGHT!!! if( sv->udev[USB_DEV_LIGHTHOUSEB] && AttachInterface( sv, hmd, USB_IF_LIGHTCAP, sv->udev[USB_DEV_LIGHTHOUSEB], 0x82, survive_data_cb, "Lightcap")) { return -12; } + if( sv->udev[USB_DEV_W_WATCHMAN1_LIGHTCAP] && AttachInterface( sv, ww0, USB_IF_W_WATCHMAN1_LIGHTCAP, sv->udev[USB_DEV_W_WATCHMAN1_LIGHTCAP], 0x82, survive_data_cb, "Wired Watchman 1 Lightcap")) { return -13; } #else if( sv->udev[USB_DEV_LIGHTHOUSE] && AttachInterface( sv, hmd, USB_IF_LIGHTCAP, sv->udev[USB_DEV_LIGHTHOUSE], 0x82, survive_data_cb, "Lightcap")) { return -12; } + if( sv->udev[USB_DEV_W_WATCHMAN1] && AttachInterface( sv, ww0, USB_IF_W_WATCHMAN1_LIGHTCAP, sv->udev[USB_DEV_W_WATCHMAN1], 0x82, survive_data_cb, "Wired Watchman 1 Lightcap")) { return -13; } #endif SV_INFO( "All enumerated devices attached." ); @@ -508,8 +519,19 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c if( r != sizeof( vive_magic_enable_lighthouse2 ) ) return 5; } + if (sv->udev[USB_DEV_W_WATCHMAN1]) + { + static uint8_t vive_magic_enable_lighthouse[5] = { 0x04 }; + r = update_feature_report( sv->udev[USB_DEV_W_WATCHMAN1], 0, vive_magic_enable_lighthouse, sizeof( vive_magic_enable_lighthouse ) ); + if( r != sizeof( vive_magic_enable_lighthouse ) ) return 5; + + static uint8_t vive_magic_enable_lighthouse2[5] = { 0x07, 0x02 }; //Switch to 0x25 mode (able to get more light updates) + r = update_feature_report( sv->udev[USB_DEV_W_WATCHMAN1], 0, vive_magic_enable_lighthouse2, sizeof( vive_magic_enable_lighthouse2 ) ); + if( r != sizeof( vive_magic_enable_lighthouse2 ) ) return 5; + } + #if 0 - for( i = 0; i < 256; i++ ) + for( int i = 0; i < 256; i++ ) { static uint8_t vive_controller_haptic_pulse[64] = { 0xff, 0x8f, 0xff, 0, 0, 0, 0, 0, 0, 0 }; r = update_feature_report( sv->udev[USB_DEV_WATCHMAN1], 0, vive_controller_haptic_pulse, sizeof( vive_controller_haptic_pulse ) ); @@ -518,6 +540,14 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c OGUSleep( 1000 ); } #endif + + if (sv->udev[USB_DEV_TRACKER0]) + { + static uint8_t vive_magic_power_on[64] = { 0x04, 0x78, 0x29, 0x38 }; + r = update_feature_report( sv->udev[USB_DEV_TRACKER0], 0, vive_magic_power_on, sizeof( vive_magic_power_on ) ); + if( r != sizeof( vive_magic_power_on ) ) return 5; + } + SV_INFO( "Powered unit on." ); } else @@ -550,7 +580,7 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c if( r != sizeof( vive_magic_power_off2 ) ) return 5; } } - + return 0; } void survive_vive_usb_close( struct SurviveViveData * sv ) @@ -584,6 +614,7 @@ int survive_vive_usb_poll( struct SurviveContext * ctx, void * v ) OGUnlockMutex( GlobalRXUSBMutx ); OGUSleep( 100 ); OGUnlockMutex( GlobalRXUSBMutx ); + return 0; #else struct SurviveViveData * sv = v; int r = libusb_handle_events( sv->usbctx ); @@ -642,6 +673,7 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno, OGUSleep(1000); } + // Send Report 16 to prepare the device for reading config info memset( cfgbuff, 0, sizeof( cfgbuff ) ); cfgbuff[0] = 0x10; if( ( ret = hid_get_feature_report_timeout( dev, iface, cfgbuff, sizeof( cfgbuff ) ) ) < 0 ) @@ -651,6 +683,7 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno, } + // Now do a bunch of Report 17 until there are no bytes left cfgbuff[1] = 0xaa; cfgbuff[0] = 0x11; do @@ -996,6 +1029,7 @@ void survive_data_cb( SurviveUSBInterface * si ) break; } case USB_IF_LIGHTHOUSE: + case USB_IF_W_WATCHMAN1: { int i; //printf( "%d -> ", size ); @@ -1055,7 +1089,7 @@ void survive_data_cb( SurviveUSBInterface * si ) // TODO: Looks like this will need to be handle_tracker, since // it appears the interface is sufficiently different. // More work needd to reverse engineer it. - handle_watchman( w, readdata); + //handle_wired_watchman( w, readdata, size); } else { @@ -1077,6 +1111,20 @@ void survive_data_cb( SurviveUSBInterface * si ) } break; } + case USB_IF_W_WATCHMAN1_LIGHTCAP: + { + int i; + for( i = 0; i < 7; i++ ) + { + LightcapElement le; + le.sensor_id = POP2; + le.length = POP2; + le.timestamp = POP4; + if( le.sensor_id == 0xff ) break; + handle_lightcap( obj, &le ); + } + break; + } } } @@ -1234,6 +1282,8 @@ int survive_vive_close( SurviveContext * ctx, void * driver ) SurviveViveData * sv = driver; survive_vive_usb_close( sv ); + + return 0; } @@ -1244,6 +1294,7 @@ int DriverRegHTCVive( SurviveContext * ctx ) SurviveObject * wm0 = calloc( 1, sizeof( SurviveObject ) ); SurviveObject * wm1 = calloc( 1, sizeof( SurviveObject ) ); SurviveObject * tr0 = calloc( 1, sizeof( SurviveObject ) ); + SurviveObject * ww0 = calloc( 1, sizeof( SurviveObject ) ); SurviveViveData * sv = calloc( 1, sizeof( SurviveViveData ) ); sv->ctx = ctx; @@ -1269,9 +1320,12 @@ int DriverRegHTCVive( SurviveContext * ctx ) tr0->ctx = ctx; memcpy( tr0->codename, "TR0", 4 ); memcpy( tr0->drivername, "HTC", 4 ); + ww0->ctx = ctx; + memcpy( ww0->codename, "WW0", 4 ); + memcpy( ww0->drivername, "HTC", 4 ); //USB must happen last. - if( r = survive_usb_init( sv, hmd, wm0, wm1, tr0) ) + if( r = survive_usb_init( sv, hmd, wm0, wm1, tr0, ww0) ) { //TODO: Cleanup any libUSB stuff sitting around. goto fail_gracefully; @@ -1281,20 +1335,35 @@ int DriverRegHTCVive( SurviveContext * ctx ) if( sv->udev[USB_DEV_HMD] && LoadConfig( sv, hmd, 1, 0, 0 )) { SV_INFO( "HMD config issue." ); } if( sv->udev[USB_DEV_WATCHMAN1] && LoadConfig( sv, wm0, 2, 0, 1 )) { SV_INFO( "Watchman 0 config issue." ); } if( sv->udev[USB_DEV_WATCHMAN2] && LoadConfig( sv, wm1, 3, 0, 1 )) { SV_INFO( "Watchman 1 config issue." ); } - if( sv->udev[USB_DEV_TRACKER0] && LoadConfig( sv, tr0, 4, 0, 1 )) { SV_INFO( "Tracker 0 config issue." ); } + if( sv->udev[USB_DEV_TRACKER0] && LoadConfig( sv, tr0, 4, 0, 0 )) { SV_INFO( "Tracker 0 config issue." ); } + if( sv->udev[USB_DEV_W_WATCHMAN1] && LoadConfig( sv, ww0, 5, 0, 0 )) { SV_INFO( "Wired Watchman 0 config issue." ); } hmd->timebase_hz = wm0->timebase_hz = wm1->timebase_hz = 48000000; + tr0->timebase_hz = ww0->timebase_hz = hmd->timebase_hz; + hmd->pulsedist_max_ticks = wm0->pulsedist_max_ticks = wm1->pulsedist_max_ticks = 500000; + tr0->pulsedist_max_ticks = ww0->pulsedist_max_ticks = hmd->pulsedist_max_ticks; + hmd->pulselength_min_sync = wm0->pulselength_min_sync = wm1->pulselength_min_sync = 2200; + tr0->pulselength_min_sync = ww0->pulselength_min_sync = hmd->pulselength_min_sync; + hmd->pulse_in_clear_time = wm0->pulse_in_clear_time = wm1->pulse_in_clear_time = 35000; + tr0->pulse_in_clear_time = ww0->pulse_in_clear_time = hmd->pulse_in_clear_time; + hmd->pulse_max_for_sweep = wm0->pulse_max_for_sweep = wm1->pulse_max_for_sweep = 1800; + tr0->pulse_max_for_sweep = ww0->pulse_max_for_sweep = hmd->pulse_max_for_sweep; hmd->pulse_synctime_offset = wm0->pulse_synctime_offset = wm1->pulse_synctime_offset = 20000; + tr0->pulse_synctime_offset = ww0->pulse_synctime_offset = hmd->pulse_synctime_offset; + hmd->pulse_synctime_slack = wm0->pulse_synctime_slack = wm1->pulse_synctime_slack = 5000; + tr0->pulse_synctime_slack = ww0->pulse_synctime_slack = hmd->pulse_synctime_slack; hmd->timecenter_ticks = hmd->timebase_hz / 240; wm0->timecenter_ticks = wm0->timebase_hz / 240; wm1->timecenter_ticks = wm1->timebase_hz / 240; + tr0->timecenter_ticks = tr0->timebase_hz / 240; + ww0->timecenter_ticks = ww0->timebase_hz / 240; /* int i; int locs = hmd->nr_locations; @@ -1322,6 +1391,7 @@ int DriverRegHTCVive( SurviveContext * ctx ) if( sv->udev[USB_DEV_WATCHMAN1] ) { survive_add_object( ctx, wm0 ); } if( sv->udev[USB_DEV_WATCHMAN2] ) { survive_add_object( ctx, wm1 ); } if( sv->udev[USB_DEV_TRACKER0] ) { survive_add_object( ctx, tr0 ); } + if( sv->udev[USB_DEV_W_WATCHMAN1] ) { survive_add_object( ctx, ww0 ); } survive_add_driver( ctx, sv, survive_vive_usb_poll, survive_vive_close, survive_vive_send_magic ); @@ -1331,6 +1401,7 @@ fail_gracefully: free( wm0 ); free( wm1 ); free( tr0 ); + free( ww0 ); survive_vive_usb_close( sv ); free( sv ); return -1; diff --git a/test.c b/test.c index a7da490..e34a7a8 100755 --- a/test.c +++ b/test.c @@ -1,4 +1,6 @@ +#ifdef __linux__ #include +#endif #include #include #include @@ -56,6 +58,7 @@ int main() dump_iface( survive_get_so_by_name( ctx, "WM0" ), "WM0" ); dump_iface( survive_get_so_by_name( ctx, "WM1" ), "WM1" ); dump_iface( survive_get_so_by_name( ctx, "TR0" ), "TR0" ); + dump_iface( survive_get_so_by_name( ctx, "WW0" ), "WW0" ); while(survive_poll(ctx) == 0) { diff --git a/winbuild/libsurvive.sln b/winbuild/libsurvive.sln index 8924631..b525975 100644 --- a/winbuild/libsurvive.sln +++ b/winbuild/libsurvive.sln @@ -7,6 +7,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "calibrate", "calibrate\cali EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsurvive", "libsurvive\libsurvive.vcxproj", "{435CFD2C-8724-42EE-8FDE-71EF7D2C6B2F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_recorder", "data_recorder\data_recorder.vcxproj", "{265C4E2C-66CB-4954-97CA-194D69B5A673}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{EF083B79-F1D7-408A-9902-502B9A0639E0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -31,6 +35,22 @@ Global {435CFD2C-8724-42EE-8FDE-71EF7D2C6B2F}.Release|x64.Build.0 = Release|x64 {435CFD2C-8724-42EE-8FDE-71EF7D2C6B2F}.Release|x86.ActiveCfg = Release|Win32 {435CFD2C-8724-42EE-8FDE-71EF7D2C6B2F}.Release|x86.Build.0 = Release|Win32 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Debug|x64.ActiveCfg = Debug|x64 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Debug|x64.Build.0 = Debug|x64 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Debug|x86.ActiveCfg = Debug|Win32 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Debug|x86.Build.0 = Debug|Win32 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Release|x64.ActiveCfg = Release|x64 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Release|x64.Build.0 = Release|x64 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Release|x86.ActiveCfg = Release|Win32 + {265C4E2C-66CB-4954-97CA-194D69B5A673}.Release|x86.Build.0 = Release|Win32 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Debug|x64.ActiveCfg = Debug|x64 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Debug|x64.Build.0 = Debug|x64 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Debug|x86.ActiveCfg = Debug|Win32 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Debug|x86.Build.0 = Debug|Win32 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Release|x64.ActiveCfg = Release|x64 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Release|x64.Build.0 = Release|x64 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Release|x86.ActiveCfg = Release|Win32 + {EF083B79-F1D7-408A-9902-502B9A0639E0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE -- cgit v1.2.3