From 1d0a3ef8b28e212eda4735da66f2f26e6c1a7cc5 Mon Sep 17 00:00:00 2001 From: cnlohr Date: Wed, 30 Nov 2016 02:10:28 -0500 Subject: I'm learning. --- Makefile | 4 +- include/survive.h | 2 +- src/survive.c | 3 +- src/survive_data.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++++ src/survive_internal.h | 17 ++- src/survive_usb.c | 67 +++++----- test.c | 13 +- 7 files changed, 413 insertions(+), 44 deletions(-) create mode 100644 src/survive_data.c diff --git a/Makefile b/Makefile index b213a03..1e6c706 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ all : test -CFLAGS:=-Iinclude -fPIC -g +CFLAGS:=-Iinclude -fPIC -g -Os LDFLAGS:=-lpthread -lusb-1.0 test : test.c lib/libsurvive.so gcc -o $@ $^ $(LDFLAGS) $(CFLAGS) -lib/libsurvive.so : src/os_generic.o src/survive.o src/survive_usb.o +lib/libsurvive.so : src/os_generic.o src/survive.o src/survive_usb.o src/survive_data.o gcc -o $@ $^ $(LDFLAGS) -shared clean : diff --git a/include/survive.h b/include/survive.h index 67ab55d..ea762c5 100644 --- a/include/survive.h +++ b/include/survive.h @@ -3,7 +3,7 @@ struct SurviveContext; -struct SurviveContext * survive_init( ); +struct SurviveContext * survive_init( void(*faultfunction)( struct SurviveContext * ctx, const char * fault ) ); void survive_close( struct SurviveContext * ctx ); int survive_poll(); diff --git a/src/survive.c b/src/survive.c index 0ae5aef..a6a8b9e 100644 --- a/src/survive.c +++ b/src/survive.c @@ -3,10 +3,11 @@ #include #include -struct SurviveContext * survive_init( ) +struct SurviveContext * survive_init( void(*ff)( struct SurviveContext * ctx, const char * fault ) ) { int r = 0; struct SurviveContext * ret = calloc( 1, sizeof( struct SurviveContext ) ); + ret->faultfunction = ff; if( r = survive_usb_init( ret ) ) { return 0; diff --git a/src/survive_data.c b/src/survive_data.c new file mode 100644 index 0000000..9635af7 --- /dev/null +++ b/src/survive_data.c @@ -0,0 +1,351 @@ + +//Based off of vl_hid_reports (HTC Vive USB HID reports). Who would license a header un the GPL??? + +#include "survive_internal.h" +#include + +#define POP1 (*(readdata++)) +#define POP2 (*(((uint16_t*)((readdata+=2)-2)))) +#define POP4 (*(((uint32_t*)readdata)++)) + + +struct LightpulseStructure +{ + uint8_t id; //Random divisible-by-2 numbers + uint8_t type; //Always 0 + int16_t unknown1; //About 7,500 + int16_t unknown2; //About -3,600 + int16_t unknown3; //About 89 to 107 + int16_t unknown4; //Normally around 0. + int16_t unknown5; //About -45, to -50 + uint32_t timestamp; + uint8_t unknown6; +} __attribute__((packed)); + + +static void handle_lightdata( struct LightpulseStructure * p ) +{ + //TODO: Wat? + //printf( "%4d %4d (%6d %6d %6d %6d %6d) %10d %6d\n", p->id, p->type, p->unknown1, p->unknown2, p->unknown3, p->unknown4, p->unknown5, p->timestamp, p->unknown6 ); +} + +/* +struct vive_controller_analog_trigger_message { + __u8 squeeze; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_button_message { + __u8 buttons; +} __attribute__((packed)); + +struct vive_controller_touch_move_message { + __le16 pos[2]; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_touch_press_message { + __u8 buttons; + __le16 pos[2]; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_imu_message { + __u8 time3; + __le16 accel[3]; + __le16 gyro[3]; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_ping_message { + __u8 charge : 7; + __u8 charging : 1; + __u8 unknown1[2]; + __le16 accel[3]; + __le16 gyro[3]; + __u8 unknown2[5]; +} __attribute__((packed)); + +struct vive_controller_message { + __u8 time1; + __u8 sensor_id; + __u8 time2; + __u8 type; + union { + struct vive_controller_analog_trigger_message analog_trigger; + struct vive_controller_button_message button; + struct vive_controller_touch_move_message touch_move; + struct vive_controller_touch_press_message touch_press; + struct vive_controller_imu_message imu; + struct vive_controller_ping_message ping; + __u8 unknown[25]; + }; +} __attribute__((packed)); +*/ + +static void handle_watchman( int whichwatch, uint8_t * readdata ) +{ + uint8_t time1 = POP1; + uint8_t sensor_id = POP1; + uint8_t time2 = POP1; + uint8_t type = POP1; + int i; + + switch(type) + { + case 0xe1: //Ping + break; + case 0xe8: //IMU + break; + case 0xf2: //Touch + break; + case 0xf4: //Analog + break; + case 0xf1: //Button down. Much more to do! + break; + default: + printf( "BN: %d %d %d %d %02x: ", whichwatch, time1, sensor_id, time2, type ); + for( i = 0; i < 26; i++ ) + printf( "%02x ", readdata[i] ); + printf("\n" ); + //It's a light! +/* printf( "WM: %d %d %d %d %02x: ", whichwatch, time1, sensor_id, time2, type ); + for( i = 0; i < 26; i++ ) + printf( "%02x ", readdata[i] ); + printf("\n" );*/ + + break; + + }; + +/*enum class vl_controller_type : uint8_t { + PING = 0xe1, + IMU = 0xe8, + TOUCH = 0xf2, + ANALOG_TRIGGER = 0xf4,*/ +} + + +void survive_data_cb( struct SurviveUSBInterface * si ) +{ + int size = si->actual_len; + +#if 0 + int i; + printf( "%16s: %d: ", si->hname, len ); + for( i = 0; i < size; i++ ) + { + printf( "%02x ", si->buffer[i] ); + } + printf( "\n" ); + return; +#endif + + int iface = si->which_interface_am_i; + uint8_t * readdata = si->buffer; + + int id = POP1; +// printf( "%16s Size: %2d ID: %d / %d\n", si->hname, size, id, iface ); + + + switch( si->which_interface_am_i ) + { + case USB_IF_HMD: + { + readdata+=2; + int lens = POP1; //Lens + int lens_sep = POP2; //Lens Separation + readdata+=2; + int btn = POP1; //Button + readdata+=3; + readdata++; //Proxchange, No change = 0, Decrease = 1, Increase = 2 + readdata++; + int proximity = POP2; //Proximity << how close to face are you? Less than 80 = not on face. + int ipd = POP2; //IPD << what is this? + + //TODO: Store in thing. + break; + } + case USB_IF_LIGHTHOUSE: + { + int i; + for( i = 0; i < 3; i++ ) + { + handle_lightdata( (struct LightpulseStructure *)readdata ); + readdata+= 17; + } + break; + } + case USB_IF_WATCHMAN1: + case USB_IF_WATCHMAN2: + { + if( id == 35 ) + { + handle_watchman( si->which_interface_am_i-USB_IF_WATCHMAN1, readdata); + } + else if( id == 36 ) + { + handle_watchman( si->which_interface_am_i-USB_IF_WATCHMAN1, readdata); + handle_watchman( si->which_interface_am_i-USB_IF_WATCHMAN1, readdata+29 ); + } + else + { + printf( "Unknown watchman code\n" ); + } + break; + } + case USB_IF_LIGHTCAP: + { + int i; + for( i = 0; i < size; i++ ) + { + printf( "%02x ", si->buffer[i] ); + } + printf( "\n" ); + + break; + } + } +} + + +/* + * + * Copyright 2016 Philipp Zabel + * SPDX-License-Identifier: LGPL-2.0+ + */ +#if 0 + +struct vive_headset_power_report { + __u8 id; + __le16 type; + __u8 len; + __u8 unknown1[9]; + __u8 reserved1[32]; + __u8 unknown2; + __u8 reserved2[18]; +} __attribute__((packed)); + +struct vive_headset_mainboard_device_info_report { + __u8 id; + __le16 type; + __u8 len; + __be16 edid_vid; + __le16 edid_pid; + __u8 unknown1[4]; + __le32 display_firmware_version; + __u8 unknown2[48]; +} __attribute__((packed)); + +struct vive_firmware_version_report { + __u8 id; + __le32 firmware_version; + __le32 unknown1; + __u8 string1[16]; + __u8 string2[16]; + __u8 hardware_version_micro; + __u8 hardware_version_minor; + __u8 hardware_version_major; + __u8 hardware_revision; + __le32 unknown2; + __u8 fpga_version_minor; + __u8 fpga_version_major; + __u8 reserved[13]; +} __attribute__((packed)); + +struct vive_headset_imu_sample { + __s16 acc[3]; + __s16 rot[3]; + __le32 time_ticks; + __u8 seq; +} __attribute__((packed)); + +struct vive_headset_imu_report { + __u8 report_id; + struct vive_headset_imu_sample samples[3]; +} __attribute__((packed)); + + + +struct vive_controller_analog_trigger_message { + __u8 squeeze; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_button_message { + __u8 buttons; +} __attribute__((packed)); + +struct vive_controller_touch_move_message { + __le16 pos[2]; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_touch_press_message { + __u8 buttons; + __le16 pos[2]; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_imu_message { + __u8 time3; + __le16 accel[3]; + __le16 gyro[3]; + __u8 unknown[4]; +} __attribute__((packed)); + +struct vive_controller_ping_message { + __u8 charge : 7; + __u8 charging : 1; + __u8 unknown1[2]; + __le16 accel[3]; + __le16 gyro[3]; + __u8 unknown2[5]; +} __attribute__((packed)); + +struct vive_controller_message { + __u8 time1; + __u8 sensor_id; + __u8 time2; + __u8 type; + union { + struct vive_controller_analog_trigger_message analog_trigger; + struct vive_controller_button_message button; + struct vive_controller_touch_move_message touch_move; + struct vive_controller_touch_press_message touch_press; + struct vive_controller_imu_message imu; + struct vive_controller_ping_message ping; + __u8 unknown[25]; + }; +} __attribute__((packed)); + +struct vive_controller_report1 { + __u8 report_id; + struct vive_controller_message message; +} __attribute__((packed)); + +struct vive_controller_report2 { + __u8 report_id; + struct vive_controller_message message[2]; +} __attribute__((packed)); + +struct vive_headset_lighthouse_pulse2 { + uint8_t sensor_id; + uint16_t length; + uint32_t timestamp; +} __attribute__((packed)); + +struct vive_headset_lighthouse_pulse_report2 { + __u8 report_id; + struct vive_headset_lighthouse_pulse2 samples[9]; +} __attribute__((packed)); + +struct vive_controller_poweroff_report { + __u8 id; + __u8 command; + __u8 len; + __u8 magic[4]; +} __attribute__((packed)); + + +#endif diff --git a/src/survive_internal.h b/src/survive_internal.h index b29b25b..70249e3 100644 --- a/src/survive_internal.h +++ b/src/survive_internal.h @@ -7,7 +7,7 @@ #include #define SV_INFO( x... ) printf( x ) -#define SV_ERROR( x... ) fprintf( stderr, x ) +#define SV_ERROR( x... ) { char stbuff[1024]; sprintf( stbuff, x ); ctx->faultfunction( ctx, stbuff ); } //XXX TODO This one needs to be rewritten. #define SV_KILL() exit(0) @@ -31,9 +31,6 @@ struct SurviveContext; struct SurviveUSBInterface; - -//XXX TODO: Roll this into the main structure. - typedef void (*usb_callback)( struct SurviveUSBInterface * ti ); struct SurviveUSBInterface @@ -43,21 +40,29 @@ struct SurviveUSBInterface int actual_len; uint8_t buffer[INTBUFFSIZE]; usb_callback cb; - int which_interface_am_i; - const char * hname; //human names + int which_interface_am_i; //for indexing into uiface + const char * hname; //human-readable names }; struct SurviveContext { + //USB Subsystem struct libusb_context* usbctx; + void(*faultfunction)( struct SurviveContext * ctx, const char * fault ); struct libusb_device_handle * udev[MAX_USB_DEVS]; struct SurviveUSBInterface uiface[MAX_INTERFACES]; }; + +//USB Subsystem + void survive_usb_close( struct SurviveContext * t ); int survive_usb_init( struct SurviveContext * t ); int survive_usb_poll( struct SurviveContext * ctx ); +//Accept Data from backend. +void survive_data_cb( struct SurviveUSBInterface * si ); + #endif diff --git a/src/survive_usb.c b/src/survive_usb.c index 704b4b5..0958070 100644 --- a/src/survive_usb.c +++ b/src/survive_usb.c @@ -19,30 +19,31 @@ const char * devnames[] = { static void handle_transfer(struct libusb_transfer* transfer) { struct SurviveUSBInterface * iface = transfer->user_data; + struct SurviveContext * ctx = iface->ctx; - if( transfer->status != LIBUSB_TRANSFER_COMPLETED ) + if( transfer->status != LIBUSB_TRANSFER_COMPLETED ) { SV_ERROR("Transfer problem %d with %s", transfer->status, iface->hname ); SV_KILL(); - return; - } + return; + } iface->actual_len = transfer->actual_length; iface->cb( iface ); - if( libusb_submit_transfer(transfer) ) + if( libusb_submit_transfer(transfer) ) { - SV_ERROR( "Error resubmitting transfer for %s\n", iface->hname ); + SV_ERROR( "Error resubmitting transfer for %s", iface->hname ); SV_KILL(); } } -static int AttachInterface( struct SurviveContext * t, int which_interface_am_i, libusb_device_handle * devh, int endpoint, usb_callback cb, const char * hname ) +static int AttachInterface( struct SurviveContext * ctx, int which_interface_am_i, libusb_device_handle * devh, int endpoint, usb_callback cb, const char * hname ) { - struct SurviveUSBInterface * iface = &t->uiface[which_interface_am_i]; - iface->ctx = t; + struct SurviveUSBInterface * iface = &ctx->uiface[which_interface_am_i]; + iface->ctx = ctx; iface->which_interface_am_i = which_interface_am_i; iface->hname = hname; struct libusb_transfer * tx = iface->transfer = libusb_alloc_transfer(0); @@ -51,7 +52,7 @@ static int AttachInterface( struct SurviveContext * t, int which_interface_am_i, if (!iface->transfer) { - SV_ERROR( "Error: failed on libusb_alloc_transfer for %s\n", hname ); + SV_ERROR( "Error: failed on libusb_alloc_transfer for %s", hname ); return 4; } @@ -60,15 +61,15 @@ static int AttachInterface( struct SurviveContext * t, int which_interface_am_i, int rc = libusb_submit_transfer( tx ); if( rc ) { - SV_ERROR( "Error: Could not submit transfer for %s (Code %d)\n", hname, rc ); + SV_ERROR( "Error: Could not submit transfer for %s (Code %d)", hname, rc ); return 6; } return 0; } - -void debug_cb( struct SurviveUSBInterface * si ) +/* +static void debug_cb( struct SurviveUSBInterface * si ) { int i; int len = si->actual_len; @@ -78,11 +79,11 @@ void debug_cb( struct SurviveUSBInterface * si ) printf( "%02x ", si->buffer[i] ); } printf( "\n" ); -} +}*/ -int survive_usb_init( struct SurviveContext * t ) +int survive_usb_init( struct SurviveContext * ctx ) { - int r = libusb_init( &t->usbctx ); + int r = libusb_init( &ctx->usbctx ); if( r ) { SV_ERROR( "libusb fault %d\n", r ); @@ -91,11 +92,11 @@ int survive_usb_init( struct SurviveContext * t ) int i; libusb_device** devs; - int ret = libusb_get_device_list(t->usbctx, &devs); + int ret = libusb_get_device_list(ctx->usbctx, &devs); if( ret < 0 ) { - SV_ERROR( "Couldn't get list of USB devices %d\n", ret ); + SV_ERROR( "Couldn't get list of USB devices %d", ret ); return ret; } @@ -125,39 +126,45 @@ int survive_usb_init( struct SurviveContext * t ) } } + if( d == 0 ) + { + SV_ERROR( "Couldn't find device %s (%04x:%04x.%d)", devnames[i], vid, pid, which ); + return -99; + } + struct libusb_config_descriptor *conf; ret = libusb_get_config_descriptor(d, 0, &conf); if( ret ) continue; - ret = libusb_open(d, &t->udev[i]); + ret = libusb_open(d, &ctx->udev[i]); - if( !t->udev[i] || ret ) + if( !ctx->udev[i] || ret ) { - SV_ERROR( "Error: cannot open device \"%s\" with vid/pid %04x:%04x\n", devnames[i], vid, pid ); + SV_ERROR( "Error: cannot open device \"%s\" with vid/pid %04x:%04x", devnames[i], vid, pid ); return -5; } - libusb_set_auto_detach_kernel_driver( t->udev[i], 1 ); + libusb_set_auto_detach_kernel_driver( ctx->udev[i], 1 ); for (int j = 0; j < conf->bNumInterfaces; j++ ) { - if( libusb_claim_interface(t->udev[i], j) ) + if( libusb_claim_interface(ctx->udev[i], j) ) { - SV_ERROR( "Could not claim interface %d of %s\n", j, devnames[i] ); + SV_ERROR( "Could not claim interface %d of %s", j, devnames[i] ); return -9; } } - SV_INFO( "Successfully enumerated %s (%d, %d)\n", devnames[i], did, conf->bNumInterfaces ); + SV_INFO( "Successfully enumerated %s (%d, %d)", devnames[i], did, conf->bNumInterfaces ); } libusb_free_device_list( devs, 1 ); - if( AttachInterface( t, USB_IF_HMD, t->udev[USB_DEV_HMD], 0x81, debug_cb, "Mainboard" ) ) { return -6; } - if( AttachInterface( t, USB_IF_LIGHTHOUSE, t->udev[USB_DEV_LIGHTHOUSE], 0x81, debug_cb, "Lighthouse" ) ) { return -6; } - if( AttachInterface( t, USB_IF_WATCHMAN1, t->udev[USB_DEV_WATCHMAN1], 0x81, debug_cb, "Watchman 1" ) ) { return -6; } - if( AttachInterface( t, USB_IF_WATCHMAN2, t->udev[USB_DEV_WATCHMAN2], 0x81, debug_cb, "Watchman 2" ) ) { return -6; } - if( AttachInterface( t, USB_IF_LIGHTCAP, t->udev[USB_DEV_LIGHTHOUSE], 0x82, debug_cb, "Lightcap" ) ) { return -6; } + if( AttachInterface( ctx, USB_IF_HMD, ctx->udev[USB_DEV_HMD], 0x81, survive_data_cb, "Mainboard" ) ) { return -6; } + if( AttachInterface( ctx, USB_IF_LIGHTHOUSE, ctx->udev[USB_DEV_LIGHTHOUSE], 0x81, survive_data_cb, "Lighthouse" ) ) { return -7; } + if( AttachInterface( ctx, USB_IF_WATCHMAN1, ctx->udev[USB_DEV_WATCHMAN1], 0x81, survive_data_cb, "Watchman 1" ) ) { return -8; } + if( AttachInterface( ctx, USB_IF_WATCHMAN2, ctx->udev[USB_DEV_WATCHMAN2], 0x81, survive_data_cb, "Watchman 2" ) ) { return -9; } + if( AttachInterface( ctx, USB_IF_LIGHTCAP, ctx->udev[USB_DEV_LIGHTHOUSE], 0x82, survive_data_cb, "Lightcap" ) ) { return -10; } SV_INFO( "All devices attached.\n" ); @@ -182,7 +189,7 @@ int survive_usb_poll( struct SurviveContext * ctx ) int r = libusb_handle_events( ctx->usbctx ); if( r ) { - SV_ERROR( "Libusb poll failed.\n" ); + SV_ERROR( "Libusb poll failed." ); } return r; } diff --git a/test.c b/test.c index b7f9627..2a99d2b 100644 --- a/test.c +++ b/test.c @@ -1,12 +1,17 @@ #include #include - - +#include #include +void survivefault( struct SurviveContext * ctx, const char * fault ) +{ + fprintf( stderr, "Error: %s\n", fault ); + exit( -1 ); +} + int main() { - struct SurviveContext * ctx = survive_init( &ctx ); + struct SurviveContext * ctx = survive_init( &survivefault ); if( !ctx ) { @@ -16,7 +21,7 @@ int main() while(survive_poll(ctx) == 0) { - + //Do stuff. } } -- cgit v1.2.3