Skip to content

Cosmos (elite) support. #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions bin/driver-proxy/src/server/driver_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::os::raw::c_char;
use std::rc::Rc;
use tracing::{error, info};
use valve_pm::{StationCommand, StationControl, StationState};
use vive_hid::{SteamDevice, ViveDevice};
use vive_hid::{SteamDevice, ViveCosmosDevice};

use crate::driver_context::DRIVER_CONTEXT;
use crate::factory::TOKIO_RUNTIME;
Expand Down Expand Up @@ -46,7 +46,7 @@ impl IVRServerDriverHost for DriverHost {
// Steam part is opened for checking if this is really a needed HMD device
let _steam = Rc::new(SteamDevice::open(&sn)?);
// We don't know for sure this device serial
let vive = Rc::new(ViveDevice::open_first()?);
let vive = Rc::new(ViveCosmosDevice::open_first()?);

let mode = {
let res = HMD_RESOLUTION.get();
Expand All @@ -62,24 +62,24 @@ impl IVRServerDriverHost for DriverHost {
.clone();
HMD_RESOLUTION.set(mode.id as i32);

vive.set_mode(mode.id)?;
// vive.set_mode(mode.id)?;
mode
};
{
let nc = NOISE_CANCEL.get();
NOISE_CANCEL.set(nc);

vive.toggle_noise_canceling(nc)?;
}
{
let mut brightness = BRIGHTNESS.get();
if brightness == 0 {
brightness = 130;
}
BRIGHTNESS.set(brightness);

vive.set_brightness(brightness as u8)?;
}
// {
// let nc = NOISE_CANCEL.get();
// NOISE_CANCEL.set(nc);

// vive.toggle_noise_canceling(nc)?;
// }
// {
// let mut brightness = BRIGHTNESS.get();
// if brightness == 0 {
// brightness = 130;
// }
// BRIGHTNESS.set(brightness);

// vive.set_brightness(brightness as u8)?;
// }

let config = vive.read_config()?;

Expand Down
122 changes: 114 additions & 8 deletions crates/vive-hid/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::{io::Read, result};

use flate2::read::ZlibDecoder;
use flate2::{ read::{ZlibDecoder, GzDecoder}, DecompressError };
use hidapi::{HidApi, HidDevice, HidError};
use once_cell::sync::OnceCell;
use serde::Deserialize;
use serde_json::Value;
use tracing::error;
use tracing::{ error, info };

#[derive(thiserror::Error, Debug)]
pub enum Error {
Expand All @@ -21,6 +21,10 @@ pub enum Error {
ConfigReadFailed,
#[error("protocol error: {0}")]
ProtocolError(&'static str),
#[error("deflate error: {0}")]
DeflateError(#[from] DecompressError),
#[error("IO error: {0}")]
IOError(#[from] std::io::Error),
}

type Result<T, E = Error> = result::Result<T, E>;
Expand Down Expand Up @@ -134,7 +138,8 @@ impl SteamDevice {
}

const VIVE_VID: u16 = 0x0bb4;
const VIVE_PID: u16 = 0x0342;
const VIVE_PRO_2_PID: u16 = 0x0342;
const VIVE_COSMOS_PID: u16 = 0x0313;

#[derive(Deserialize, Debug)]
pub struct ViveConfig {
Expand Down Expand Up @@ -175,11 +180,11 @@ const VIVE_PRO_2_MODES: [Mode; 6] = [
Mode::new(5, 2896, 2448, 120.0),
];

pub struct ViveDevice(HidDevice);
impl ViveDevice {
pub struct VivePro2Device(HidDevice);
impl VivePro2Device {
pub fn open_first() -> Result<Self> {
let api = get_hidapi()?;
let device = api.open(VIVE_VID, VIVE_PID)?;
let device = api.open(VIVE_VID, VIVE_PRO_2_PID)?;
Ok(Self(device))
}
pub fn open(sn: &str) -> Result<Self> {
Expand All @@ -188,7 +193,7 @@ impl ViveDevice {
.device_list()
.find(|dev| dev.serial_number() == Some(sn))
.ok_or(Error::DeviceNotFound)?;
if device.vendor_id() != VIVE_VID || device.product_id() != VIVE_PID {
if device.vendor_id() != VIVE_VID || device.product_id() != VIVE_PRO_2_PID {
return Err(Error::NotAVive);
}
let open = api.open_serial(device.vendor_id(), device.product_id(), sn)?;
Expand Down Expand Up @@ -285,7 +290,7 @@ impl ViveDevice {

serde_json::from_str(&string).map_err(|_| Error::ConfigReadFailed)
}
/// Always returns at least one mode
// Always returns at least one mode
pub fn query_modes(&self) -> Vec<Mode> {
VIVE_PRO_2_MODES.into_iter().collect()
}
Expand Down Expand Up @@ -328,3 +333,104 @@ impl ViveDevice {
Ok(())
}
}

const VIVE_COSMOS_MODES: [Mode; 1] = [
Mode::new(0, 2880, 1700, 90.0),
];

pub struct ViveCosmosDevice(HidDevice);
use std::fs::File;
use std::io::prelude::*;
impl ViveCosmosDevice {

pub fn open_first() -> Result<Self> {
let api = get_hidapi()?;
let device = api.open(VIVE_VID, VIVE_COSMOS_PID)?;
Ok(Self(device))
}
pub fn open(sn: &str) -> Result<Self> {
let api = get_hidapi()?;
let device = api
.device_list()
.find(|dev| dev.serial_number() == Some(sn))
.ok_or(Error::DeviceNotFound)?;
if device.vendor_id() != VIVE_VID || device.product_id() != VIVE_COSMOS_PID {
return Err(Error::NotAVive);
}
let open = api.open_serial(device.vendor_id(), device.product_id(), sn)?;
Ok(Self(open))
}
// Always returns at least one mode
pub fn query_modes(&self) -> Vec<Mode> {
VIVE_COSMOS_MODES.into_iter().collect()
}
pub fn read_config(&self) -> Result<ViveConfig> {
let gz_file_buffer = self.read_stream(b"HMD_JSON.gz")?;

info!("received gzipped config file");

let mut dec = GzDecoder::new(gz_file_buffer.as_slice());
let mut config = String::new();
dec.read_to_string(&mut config)?;

info!("config: {config}");

serde_json::from_str(&config).map_err(|_| Error::ConfigReadFailed)
}
pub fn read_stream(&self, filename: &[u8]) -> Result<Vec::<u8>> {
let mut report = [0u8; 65];

report[0] = 0x00; // id 0 -> root of the Application collection.
report[1] = 0x10; // the command I presume ?
report[2] = 0x00; // commant 2nd part ?
report[3] = filename.len() as u8; // payload size
report[4] = 0xff; // separator ?
report[5..][..filename.len()].copy_from_slice(filename);

let total_len = {
self.0.send_feature_report(&report)?;

loop {
self.0.get_feature_report(&mut report)?;
if report[0] != 0x00 { return Err(Error::ProtocolError("unknown data received.")) }
if report[1] == 0x10 { break; }
}

let mut total_len = [0u8; 4];
total_len.copy_from_slice(&report[5..9]);
u32::from_le_bytes(total_len) as usize
};
info!("config read length : {total_len}");

let mut position = 0x0 as usize;
let mut out = Vec::<u8>::with_capacity(total_len);

while position < total_len {
report = [0u8;65];
report[1] = 0x11;
report[2] = 0x00;
report[3] = 0x08; //payload size;
report[4] = 0x80; // separator ?
report[5..9].copy_from_slice(&u32::to_le_bytes(position as u32)); // start position
report[9] = 0x38 ;

self.0.send_feature_report(&report)?;
loop {
self.0.get_feature_report(&mut report)?;
if report[0] != 0x00 { return Err(Error::ProtocolError("unknown data received.")) }
if report[1] == 0x11 { break; }
}

let size = (report[3] - 0x04) as usize;
out.extend_from_slice(&report[5..5 + size]);

position = position + size;
info!("position: {position}, size: {size}");
}
if position != total_len {
return Err(Error::ProtocolError("config size mismatch"));
}

Ok(out)
}
}