Browse Source

CV1 Support (#63)

* Applied patch by ThibG with initial rotation support for the CV1, needs cleaning up

* Removed duplicate code for branch, just left ID's for CV1 in and work from there

* Added message type 11 check

* Add proper support for DK2/CV1 sensors

* Add support to turn CV1's display on

* Restrict 0x1d packet to CV1

* Take the absolute value of projection offset to fix CV1 issue

* removed unused variable

* Reports correct rift versions. Opens correct interface on CV1.
Fredrik Hultin 8 years ago
parent
commit
c29be8b7dd
4 changed files with 107 additions and 20 deletions
  1. 53 2
      src/drv_oculus_rift/packet.c
  2. 44 15
      src/drv_oculus_rift/rift.c
  3. 6 2
      src/drv_oculus_rift/rift.h
  4. 4 1
      src/openhmd.c

+ 53 - 2
src/drv_oculus_rift/packet.c

@@ -55,8 +55,8 @@ bool decode_sensor_display_info(pkt_sensor_display_info* info, const unsigned ch
 	info->lens_separation = READFIXED;
 	info->eye_to_screen_distance[0] = READFIXED;
 	info->eye_to_screen_distance[1] = READFIXED;
-	
-	info->distortion_type_opts = 0;	
+
+	info->distortion_type_opts = 0;
 
 	for(int i = 0; i < 6; i++)
 		info->distortion_k[i] = READFLOAT;
@@ -128,6 +128,41 @@ bool decode_tracker_sensor_msg(pkt_tracker_sensor* msg, const unsigned char* buf
 	return true;
 }
 
+bool decode_tracker_sensor_msg_dk2(pkt_tracker_sensor* msg, const unsigned char* buffer, int size)
+{
+	if(!(size == 64)){
+		LOGE("invalid packet size (expected 62 or 64 but got %d)", size);
+		return false;
+	}
+
+	SKIP_CMD;
+	msg->last_command_id = READ16;
+	msg->num_samples = READ8;
+	buffer += 2; // unused: nb_samples_since_start
+	msg->temperature = READ16;
+	msg->timestamp = READ32;
+
+	int actual = OHMD_MIN(msg->num_samples, 2);
+	for(int i = 0; i < actual; i++){
+		decode_sample(buffer, msg->samples[i].accel);
+		buffer += 8;
+
+		decode_sample(buffer, msg->samples[i].gyro);
+		buffer += 8;
+	}
+
+	// Skip empty samples
+	buffer += (2 - actual) * 16;
+
+	for(int i = 0; i < 3; i++){
+		msg->mag[i] = READ16;
+	}
+
+	// TODO: positional tracking data and frame data
+
+	return true;
+}
+
 // TODO do we need to consider HMD vs sensor "centric" values
 void vec3f_from_rift_vec(const int32_t* smp, vec3f* out_vec)
 {
@@ -154,6 +189,22 @@ int encode_keep_alive(unsigned char* buffer, const pkt_keep_alive* keep_alive)
 	return 5; // keep alive packet size
 }
 
+int encode_enable_components(unsigned char* buffer, bool display, bool audio)
+{
+	uint8_t flags = 0;
+
+	WRITE8(RIFT_CMD_ENABLE_COMPONENTS);
+	WRITE16(0); // last command ID
+
+	if (display)
+		flags |= 1;
+	if (audio)
+		flags |= 2;
+	flags |= 4; // I don't know what it is. Wireless?
+	WRITE8(flags);
+	return 4;
+}
+
 void dump_packet_sensor_range(const pkt_sensor_range* range)
 {
 	(void)range;

+ 44 - 15
src/drv_oculus_rift/rift.c

@@ -34,6 +34,19 @@ typedef struct {
 	vec3f raw_mag, raw_accel, raw_gyro;
 } rift_priv;
 
+typedef enum {
+	REV_DK1,
+	REV_DK2,
+	REV_CV1
+} rift_revision;
+
+typedef struct {
+	const char* name;
+	int id;
+	int iface;
+	rift_revision rev;
+} rift_devices;
+
 static rift_priv* rift_priv_get(ohmd_device* device)
 {
 	return (rift_priv*)device;
@@ -85,7 +98,13 @@ static void set_coordinate_frame(rift_priv* priv, rift_coordinate_frame coordfra
 
 static void handle_tracker_sensor_msg(rift_priv* priv, unsigned char* buffer, int size)
 {
-	if(!decode_tracker_sensor_msg(&priv->sensor, buffer, size)){
+	if (buffer[0] == RIFT_IRQ_SENSORS
+	  && !decode_tracker_sensor_msg(&priv->sensor, buffer, size)){
+		LOGE("couldn't decode tracker sensor message");
+	}
+
+	if (buffer[0] == RIFT_IRQ_SENSORS_DK2
+	  && !decode_tracker_sensor_msg_dk2(&priv->sensor, buffer, size)){
 		LOGE("couldn't decode tracker sensor message");
 	}
 
@@ -139,7 +158,7 @@ static void update_device(ohmd_device* device)
 		}
 
 		// currently the only message type the hardware supports (I think)
-		if(buffer[0] == RIFT_IRQ_SENSORS){
+		if(buffer[0] == RIFT_IRQ_SENSORS || buffer[0] == RIFT_IRQ_SENSORS_DK2) {
 			handle_tracker_sensor_msg(priv, buffer, size);
 		}else{
 			LOGE("unknown message type: %u", buffer[0]);
@@ -253,6 +272,13 @@ static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
 	// apply sensor config
 	set_coordinate_frame(priv, priv->coordinate_frame);
 
+	// Turn the screens on
+	if (desc->revision == REV_CV1)
+	{
+		size = encode_enable_components(buf, true, true);
+		send_feature_report(priv, buf, size);
+	}
+
 	// set keep alive interval to n seconds
 	pkt_keep_alive keep_alive = { 0, KEEP_ALIVE_VALUE };
 	size = encode_keep_alive(buf, &keep_alive);
@@ -301,37 +327,40 @@ cleanup:
 }
 
 #define OCULUS_VR_INC_ID 0x2833
-#define RIFT_ID_COUNT 3
+#define RIFT_ID_COUNT 4
 
 static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 {
 	// enumerate HID devices and add any Rifts found to the device list
 
-	int ids[RIFT_ID_COUNT] = {
-		0x0001 /* DK1 */,
-		0x0021 /* DK2 */,
-		0x2021 /* DK2 alternative id */,
+	rift_devices rd[RIFT_ID_COUNT] = {
+		{ "Rift (DK1)", 0x0001,	-1, REV_DK1 },
+		{ "Rift (DK2)", 0x0021,	-1, REV_DK2 },
+		{ "Rift (DK2)", 0x2021,	-1, REV_DK2 },
+		{ "Rift (CV1)", 0x0031,	 0, REV_CV1 },
 	};
 
 	for(int i = 0; i < RIFT_ID_COUNT; i++){
-		struct hid_device_info* devs = hid_enumerate(OCULUS_VR_INC_ID, ids[i]);
+		struct hid_device_info* devs = hid_enumerate(OCULUS_VR_INC_ID, rd[i].id);
 		struct hid_device_info* cur_dev = devs;
 
 		if(devs == NULL)
 			continue;
 
 		while (cur_dev) {
-			ohmd_device_desc* desc = &list->devices[list->num_devices++];
+			if(rd[i].iface == -1 || cur_dev->interface_number == rd[i].iface){
+				ohmd_device_desc* desc = &list->devices[list->num_devices++];
 
-			strcpy(desc->driver, "OpenHMD Rift Driver");
-			strcpy(desc->vendor, "Oculus VR, Inc.");
-			strcpy(desc->product, "Rift (Devkit)");
+				strcpy(desc->driver, "OpenHMD Rift Driver");
+				strcpy(desc->vendor, "Oculus VR, Inc.");
+				strcpy(desc->product, rd[i].name);
 
-			desc->revision = i;
+				desc->revision = rd[i].rev;
 
-			strcpy(desc->path, cur_dev->path);
+				strcpy(desc->path, cur_dev->path);
 
-			desc->driver_ptr = driver;
+				desc->driver_ptr = driver;
+			}
 
 			cur_dev = cur_dev->next;
 		}

+ 6 - 2
src/drv_oculus_rift/rift.h

@@ -18,7 +18,8 @@ typedef enum {
 	RIFT_CMD_SENSOR_CONFIG = 2,
 	RIFT_CMD_RANGE = 4,
 	RIFT_CMD_KEEP_ALIVE = 8,
-	RIFT_CMD_DISPLAY_INFO = 9
+	RIFT_CMD_DISPLAY_INFO = 9,
+	RIFT_CMD_ENABLE_COMPONENTS = 0x1d
 } rift_sensor_feature_cmd;
 
 typedef enum {
@@ -27,7 +28,8 @@ typedef enum {
 } rift_coordinate_frame;
 
 typedef enum {
-	RIFT_IRQ_SENSORS = 1
+	RIFT_IRQ_SENSORS = 1,
+	RIFT_IRQ_SENSORS_DK2 = 11
 } rift_irq_cmd;
 
 typedef enum {
@@ -97,11 +99,13 @@ bool decode_sensor_range(pkt_sensor_range* range, const unsigned char* buffer, i
 bool decode_sensor_display_info(pkt_sensor_display_info* info, const unsigned char* buffer, int size);
 bool decode_sensor_config(pkt_sensor_config* config, const unsigned char* buffer, int size);
 bool decode_tracker_sensor_msg(pkt_tracker_sensor* msg, const unsigned char* buffer, int size);
+bool decode_tracker_sensor_msg_dk2(pkt_tracker_sensor* msg, const unsigned char* buffer, int size);
 
 void vec3f_from_rift_vec(const int32_t* smp, vec3f* out_vec);
 
 int encode_sensor_config(unsigned char* buffer, const pkt_sensor_config* config);
 int encode_keep_alive(unsigned char* buffer, const pkt_keep_alive* keep_alive);
+int encode_enable_components(unsigned char* buffer, bool display, bool audio);
 
 void dump_packet_sensor_range(const pkt_sensor_range* range);
 void dump_packet_sensor_config(const pkt_sensor_config* config);

+ 4 - 1
src/openhmd.c

@@ -459,7 +459,10 @@ void ohmd_calc_default_proj_matrices(ohmd_device_properties* props)
 	// and with the given value offset the projection matrix.
 	float screen_center = props->hsize / 4.0f;
 	float lens_shift = screen_center - props->lens_sep / 2.0f;
-	float proj_offset = 4.0f * lens_shift / props->hsize;
+	// XXX: on CV1, props->hsize > props->lens_sep / 2.0,
+	// I am not sure about the implications, but just taking the absolute
+	// value of the offset seems to work.
+	float proj_offset = fabs(4.0f * lens_shift / props->hsize);
 
 	// Setup the base projection matrix. Each eye mostly have the
 	// same projection matrix with the exception of the offset.