Corsair_Virtuoso_XT_Headset.js aktualisiert
This commit is contained in:
parent
efc5969c24
commit
fc32de2be1
@ -1,376 +1,556 @@
|
||||
export function Name() { return "Corsair Virtuoso Device"; }
|
||||
export function VendorId() { return 0x1B1C; }
|
||||
export function ProductId() { return Object.keys(CORSAIRdeviceLibrary.PIDLibrary); }
|
||||
export function Publisher() { return "WhirlwindFx"; }
|
||||
export function Documentation(){ return "troubleshooting/corsair"; }
|
||||
export function Size() { return [1, 1]; }
|
||||
/* global
|
||||
shutdownColor:readonly
|
||||
LightingMode:readonly
|
||||
forcedColor:readonly
|
||||
micLedMode:readonly
|
||||
micMuteColor:readonly
|
||||
idleTimeout:readonly
|
||||
SidetoneAmount:readonly
|
||||
*/
|
||||
export function ControllableParameters() {
|
||||
return [
|
||||
{"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"},
|
||||
{"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"},
|
||||
{"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"},
|
||||
{"property":"micLedMode", "group":"lighting", "label":"Microphone LED Mode", "type":"combobox", "values":["Canvas", "MuteState"], "default":"Canvas"},
|
||||
{"property":"micMuteColor", "group":"lighting", "label":"Microphone Mute Color", "min":"0", "max":"360", "type":"color", "default":"#ff0000"},
|
||||
{"property":"SidetoneAmount", "group":"", "label":"Sidetone", "step":"1", "type":"number", "min":"0", "max":"100", "default":"0"},
|
||||
];
|
||||
}
|
||||
|
||||
export function Initialize() {
|
||||
CORSAIR.Initialize();
|
||||
}
|
||||
|
||||
export function Render() {
|
||||
CORSAIR.sendColors();
|
||||
|
||||
if(CORSAIR.getWirelessSupport()){
|
||||
CORSAIR.fetchBattery();
|
||||
}
|
||||
}
|
||||
|
||||
export function Shutdown(SystemSuspending) {
|
||||
|
||||
if(SystemSuspending){
|
||||
// Go Dark on System Sleep/Shutdown
|
||||
CORSAIR.sendColors("#000000");
|
||||
}else{
|
||||
const headsetMode = CORSAIR.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
device.write([0x02, headsetMode, 0x01, 0x03, 0x00, 0x01], 64); // Hardware mode
|
||||
}
|
||||
}
|
||||
|
||||
export function onSidetoneAmountChanged() {
|
||||
CORSAIR.setSidetone();
|
||||
}
|
||||
|
||||
export function onidleTimeoutChanged() {
|
||||
CORSAIR.setIdleTimeout();
|
||||
}
|
||||
|
||||
export class CORSAIR_Device_Protocol {
|
||||
constructor() {
|
||||
this.Config = {
|
||||
DeviceProductID: 0x0000,
|
||||
DeviceName: "Corsair Virtuoso Device",
|
||||
DeviceEndpoint: { "interface": 0, "usage": 0x0000, "usage_page": 0x0000, "collection": 0x0000 },
|
||||
LedNames: [],
|
||||
LedPositions: [],
|
||||
Leds: [],
|
||||
Wireless: false, // True equals to 0x09 and false to 0x08,
|
||||
pollingInterval: 500,
|
||||
lastMicStatePolling: 0,
|
||||
lastMicState: 0,
|
||||
lastBatteryPolling: 0,
|
||||
pollingBatteryInterval: 300000, // 5 Minutes
|
||||
};
|
||||
|
||||
this.chargingStates = Object.freeze({
|
||||
1 : 2,
|
||||
2 : 1,
|
||||
3 : 4
|
||||
});
|
||||
}
|
||||
|
||||
getDeviceProperties(deviceID) { return CORSAIRdeviceLibrary.LEDLibrary[deviceID];};
|
||||
|
||||
getDeviceProductId() { return this.Config.DeviceProductID; }
|
||||
setDeviceProductId(productID) { this.Config.DeviceProductID = productID; }
|
||||
|
||||
getDeviceName() { return this.Config.DeviceName; }
|
||||
setDeviceName(deviceName) { this.Config.DeviceName = deviceName; }
|
||||
|
||||
getDeviceEndpoint() { return this.Config.DeviceEndpoint; }
|
||||
setDeviceEndpoint(deviceEndpoint) { this.Config.DeviceEndpoint = deviceEndpoint; }
|
||||
|
||||
getLedNames() { return this.Config.LedNames; }
|
||||
setLedNames(ledNames) { this.Config.LedNames = ledNames; }
|
||||
|
||||
getLedPositions() { return this.Config.LedPositions; }
|
||||
setLedPositions(ledPositions) { this.Config.LedPositions = ledPositions; }
|
||||
|
||||
getLeds() { return this.Config.Leds; }
|
||||
setLeds(leds) { this.Config.Leds = leds; }
|
||||
|
||||
getDeviceImage() { return this.Config.image; }
|
||||
setDeviceImage(image) { this.Config.image = image; }
|
||||
|
||||
getWirelessSupport() { return this.Config.Wireless; }
|
||||
setWirelessSupport(wireless) { this.Config.Wireless = wireless; }
|
||||
|
||||
Initialize() {
|
||||
//Initializing vars
|
||||
this.setDeviceProductId(device.productId());
|
||||
|
||||
const DeviceProperties = this.getDeviceProperties(this.getDeviceProductId());
|
||||
this.setDeviceName(DeviceProperties.name);
|
||||
this.setDeviceEndpoint(DeviceProperties.endpoint);
|
||||
this.setLedNames(DeviceProperties.LedNames);
|
||||
this.setLedPositions(DeviceProperties.LedPositions);
|
||||
this.setLeds(DeviceProperties.Leds);
|
||||
this.setDeviceImage(DeviceProperties.image);
|
||||
|
||||
if(DeviceProperties.wireless){
|
||||
this.setWirelessSupport(DeviceProperties.wireless);
|
||||
device.addFeature("battery");
|
||||
device.addProperty({"property":"idleTimeout", "group":"", "label":"Device Sleep Timeout (Minutes)", "type":"combobox", "values":["Off", "1", "2", "3", "4", "5", "10", "15", "20", "25", "30"], "default":"10"});
|
||||
}
|
||||
|
||||
device.log("Device model found: " + this.getDeviceName());
|
||||
device.setName("Corsair " + this.getDeviceName());
|
||||
device.setSize(DeviceProperties.size);
|
||||
device.setControllableLeds(this.getLedNames(), this.getLedPositions());
|
||||
device.setImageFromUrl(this.getDeviceImage());
|
||||
device.set_endpoint(
|
||||
DeviceProperties.endpoint[`interface`],
|
||||
DeviceProperties.endpoint[`usage`],
|
||||
DeviceProperties.endpoint[`usage_page`],
|
||||
DeviceProperties.endpoint[`collection`]
|
||||
);
|
||||
|
||||
this.modernDirectLightingMode();
|
||||
this.fetchBattery();
|
||||
}
|
||||
|
||||
modernDirectLightingMode() {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
console.log("Setting Software Mode!");
|
||||
device.write([0x02, headsetMode, 0x01, 0x03, 0x00, 0x02], 64); // Enable Software Mode
|
||||
device.write([0x02, headsetMode, 0x0D, 0x00, 0x01], 64); //Open lighting endpoint
|
||||
device.pause(1000);
|
||||
|
||||
const HWBrightnessPacket = [0x02, headsetMode, 0x02, 0x02, 0x00];
|
||||
|
||||
device.clearReadBuffer();
|
||||
device.write(HWBrightnessPacket, 64);
|
||||
device.pause(100);
|
||||
|
||||
const HWBrightness = device.read(HWBrightnessPacket, 64);
|
||||
|
||||
if (HWBrightness[4] !== 0xe8 || HWBrightness[5] !== 0x03) {
|
||||
device.write([0x02, headsetMode, 0x01, 0x02, 0x00, 0xe8, 0x03], 64); //Hardware Brightness 100%
|
||||
}
|
||||
}
|
||||
|
||||
sendColors(overrideColor) {
|
||||
|
||||
const deviceLedPositions = this.getLedPositions();
|
||||
const deviceLeds = this.getLeds();
|
||||
const RGBData = [];
|
||||
|
||||
for (let iIdx = 0; iIdx < deviceLeds.length; iIdx++) {
|
||||
const iPxX = deviceLedPositions[iIdx][0];
|
||||
const iPxY = deviceLedPositions[iIdx][1];
|
||||
let color;
|
||||
|
||||
if(deviceLeds[iIdx] === 2 && micLedMode === "MuteState"){
|
||||
const micState = this.fetchMicStatus();
|
||||
|
||||
if (micState === 1) {
|
||||
color = hexToRgb(micMuteColor);
|
||||
} else {
|
||||
color = device.color(iPxX, iPxY);
|
||||
}
|
||||
}else if (overrideColor){
|
||||
color = hexToRgb(overrideColor);
|
||||
}else if (LightingMode === "Forced") {
|
||||
color = hexToRgb(forcedColor);
|
||||
}else {
|
||||
color = device.color(iPxX, iPxY);
|
||||
}
|
||||
|
||||
RGBData[(deviceLeds[iIdx])] = color[0];
|
||||
RGBData[(deviceLeds[iIdx])+3] = color[1];
|
||||
RGBData[(deviceLeds[iIdx])+6] = color[2];
|
||||
}
|
||||
|
||||
this.writeRGB(RGBData);
|
||||
}
|
||||
|
||||
writeRGB(RGBData) {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
device.write([0x02, headsetMode, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00].concat(RGBData), 64);
|
||||
}
|
||||
|
||||
fetchMicStatus(){
|
||||
|
||||
if(Date.now() - this.Config.lastMicStatePolling < this.Config.pollingInterval) {
|
||||
return this.Config.lastMicState;
|
||||
}
|
||||
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
const micStatusPacket = [0x02, headsetMode, 0x02, 0x46, 0x00];
|
||||
|
||||
device.pause(100);
|
||||
device.clearReadBuffer();
|
||||
device.write(micStatusPacket, 64);
|
||||
device.pause(50);
|
||||
|
||||
const micStatus = device.read(micStatusPacket, 64); // Index 5 returns 0 to unmutted/enable and 1 to muted/disabled
|
||||
this.Config.lastMicStatePolling = Date.now();
|
||||
|
||||
if (micStatus[3] === 0x46) {
|
||||
console.log("Invalid read on mic status.");
|
||||
|
||||
return this.Config.lastMicState;
|
||||
}
|
||||
|
||||
this.Config.lastMicState = micStatus[4];
|
||||
|
||||
return micStatus[4];
|
||||
|
||||
}
|
||||
|
||||
setSidetone() {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
const sidetoneValue = Math.round((SidetoneAmount / 100) * 1000);
|
||||
|
||||
console.log("Setting Sidetone!");
|
||||
device.write([0x02, headsetMode, 0x01, 0x47, 0x00, sidetoneValue & 0xFF, (sidetoneValue >> 8) & 0xFF], 64);
|
||||
}
|
||||
|
||||
setIdleTimeout() {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
if (idleTimeout === "Off") {
|
||||
console.log ("Setting Idle Timeout to: disabled");
|
||||
device.write([0x02, headsetMode, 0x01, 0x0D], 64);
|
||||
} else {
|
||||
device.write([0x02, headsetMode, 0x01, 0x0D, 0x01], 64);
|
||||
device.pause(1);
|
||||
|
||||
device.write([0x02, headsetMode, 0x01, 0x0D, 0x00, 0x01], 64);
|
||||
device.pause(1);
|
||||
|
||||
const timeoutValue = idleTimeout * 60000;
|
||||
const hexValue = timeoutValue.toString(16).padStart(6, '0');
|
||||
const littleEndianHex = hexValue.match(/../g).reverse();
|
||||
|
||||
const packet = [];
|
||||
packet[0] = 0x02;
|
||||
packet[1] = headsetMode;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = 0x0e;
|
||||
|
||||
packet[5] = parseInt(littleEndianHex[0], 16);
|
||||
packet[6] = parseInt(littleEndianHex[1], 16);
|
||||
packet[7] = parseInt(littleEndianHex[2], 16);
|
||||
|
||||
console.log ("Setting Idle Timeout to: " + idleTimeout);
|
||||
device.write(packet, 64);
|
||||
}
|
||||
}
|
||||
|
||||
fetchBattery(){
|
||||
|
||||
if(Date.now() - this.Config.lastBatteryPolling < this.Config.pollingBatteryInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
const batteryLevelPacket = [0x02, headsetMode, 0x02, 0x0F, 0x00];
|
||||
const batteryStatusPacket = [0x02, headsetMode, 0x02, 0x10, 0x00];
|
||||
|
||||
device.pause(1000);
|
||||
device.clearReadBuffer();
|
||||
device.write(batteryLevelPacket, 64);
|
||||
|
||||
device.pause(50);
|
||||
device.clearReadBuffer();
|
||||
device.write(batteryStatusPacket, 64);
|
||||
|
||||
const batteryLevelData = device.read(batteryLevelPacket, 64);
|
||||
const batteryStatusData = device.read(batteryStatusPacket, 64);
|
||||
|
||||
const batteryLevel = this.ReadInt32LittleEndian(batteryLevelData.slice(4, 7));
|
||||
const batteryStatus = batteryStatusData[4];
|
||||
|
||||
this.Config.lastBatteryPolling = Date.now();
|
||||
|
||||
device.log(`Battery Level is [${(batteryLevel ?? 0)/10}%]`);
|
||||
device.log(`Battery Status is [${this.chargingStates[batteryStatus ?? 0]}]`);
|
||||
|
||||
battery.setBatteryLevel((batteryLevel ?? 0)/ 10);
|
||||
battery.setBatteryState(this.chargingStates[batteryStatus ?? 0]);
|
||||
}
|
||||
|
||||
ReadInt32LittleEndian(array){
|
||||
return (array[0] & 0xFF) | ((array[1] << 8) & 0xFF00) | ((array[2] << 16) & 0xFF0000) | ((array[3] << 24) & 0xFF000000);
|
||||
}
|
||||
}
|
||||
|
||||
export class deviceLibrary {
|
||||
constructor(){
|
||||
this.PIDLibrary = {
|
||||
0x0A62: "Virtuoso XT",
|
||||
0x0A64: "Virtuoso XT", // Wireless
|
||||
};
|
||||
|
||||
this.LEDLibrary = {
|
||||
0x0A62: {
|
||||
name: "Virtuoso XT",
|
||||
size: [1, 2],
|
||||
LedNames: ["Logo", "Mic"],
|
||||
LedPositions: [[0, 0], [0, 1]],
|
||||
Leds: [0, 2],
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0005 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-xt.png"
|
||||
},
|
||||
0x0A64: {
|
||||
name: "Virtuoso XT Wireless",
|
||||
size: [1, 2],
|
||||
LedNames: ["Logo", "Mic"],
|
||||
LedPositions: [[0, 0], [0, 1]],
|
||||
Leds: [0, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0005 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-xt.png"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const CORSAIRdeviceLibrary = new deviceLibrary();
|
||||
const CORSAIR = new CORSAIR_Device_Protocol();
|
||||
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
const colors = [];
|
||||
colors[0] = parseInt(result[1], 16);
|
||||
colors[1] = parseInt(result[2], 16);
|
||||
colors[2] = parseInt(result[3], 16);
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
export function Validate(endpoint) {
|
||||
return endpoint.interface === 3;
|
||||
}
|
||||
|
||||
export function ImageUrl() {
|
||||
return "https://assets.signalrgb.com/devices/default/misc/usb-drive-render.png";
|
||||
}
|
||||
export function Name() { return "Corsair Headset Device"; }
|
||||
export function VendorId() { return 0x1B1C; }
|
||||
export function ProductId() { return Object.keys(CORSAIRdeviceLibrary.PIDLibrary); }
|
||||
export function Publisher() { return "WhirlwindFx"; }
|
||||
export function Documentation(){ return "troubleshooting/corsair"; }
|
||||
export function Size() { return [1, 1]; }
|
||||
/* global
|
||||
LightingMode:readonly
|
||||
forcedColor:readonly
|
||||
micLedMode:readonly
|
||||
micMuteColor:readonly
|
||||
idleTimeout:readonly
|
||||
SidetoneAmount:readonly
|
||||
*/
|
||||
export function ControllableParameters() {
|
||||
return [
|
||||
{"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"},
|
||||
{"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"},
|
||||
{"property":"micLedMode", "group":"lighting", "label":"Microphone LED Mode", "type":"combobox", "values":["Canvas", "MuteState"], "default":"Canvas"},
|
||||
{"property":"micMuteColor", "group":"lighting", "label":"Microphone Mute Color", "min":"0", "max":"360", "type":"color", "default":"#ff0000"},
|
||||
{"property":"SidetoneAmount", "group":"", "label":"Sidetone", "step":"1", "type":"number", "min":"0", "max":"100", "default":"0"},
|
||||
];
|
||||
}
|
||||
|
||||
export function Initialize() {
|
||||
CORSAIR.Initialize();
|
||||
}
|
||||
|
||||
export function Render() {
|
||||
CORSAIR.sendColors();
|
||||
|
||||
if(CORSAIR.getWirelessSupport()){
|
||||
CORSAIR.fetchBattery();
|
||||
}
|
||||
}
|
||||
|
||||
export function Shutdown(SystemSuspending) {
|
||||
|
||||
if(SystemSuspending){
|
||||
// Go Dark on System Sleep/Shutdown
|
||||
CORSAIR.sendColors("#000000");
|
||||
}else{
|
||||
const headsetMode = CORSAIR.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
device.write([0x02, headsetMode, 0x01, 0x03, 0x00, 0x01], 64); // Hardware mode
|
||||
}
|
||||
}
|
||||
|
||||
export function onSidetoneAmountChanged() {
|
||||
CORSAIR.setSidetone();
|
||||
}
|
||||
|
||||
export function onidleTimeoutChanged() {
|
||||
CORSAIR.setIdleTimeout();
|
||||
}
|
||||
|
||||
export class CORSAIR_Device_Protocol {
|
||||
constructor() {
|
||||
this.Config = {
|
||||
DeviceProductID: 0x0000,
|
||||
DeviceName: "Corsair Headset Device",
|
||||
DeviceEndpoint: { "interface": 0, "usage": 0x0000, "usage_page": 0x0000, "collection": 0x0000 },
|
||||
LedNames: [],
|
||||
LedPositions: [],
|
||||
Leds: [],
|
||||
Wireless: false, // True equals to 0x09 and false to 0x08,
|
||||
pollingInterval: 500,
|
||||
lastMicStatePolling: 0,
|
||||
lastMicState: 0,
|
||||
lastBatteryPolling: 0,
|
||||
pollingBatteryInterval: 300000, // 5 Minutes
|
||||
};
|
||||
|
||||
this.chargingStates = Object.freeze({
|
||||
1 : 2,
|
||||
2 : 1,
|
||||
3 : 4
|
||||
});
|
||||
}
|
||||
|
||||
getDeviceProperties(deviceID) { return CORSAIRdeviceLibrary.LEDLibrary[deviceID];};
|
||||
|
||||
getDeviceProductId() { return this.Config.DeviceProductID; }
|
||||
setDeviceProductId(productID) { this.Config.DeviceProductID = productID; }
|
||||
|
||||
getDeviceName() { return this.Config.DeviceName; }
|
||||
setDeviceName(deviceName) { this.Config.DeviceName = deviceName; }
|
||||
|
||||
getDeviceEndpoint() { return this.Config.DeviceEndpoint; }
|
||||
setDeviceEndpoint(deviceEndpoint) { this.Config.DeviceEndpoint = deviceEndpoint; }
|
||||
|
||||
getLedNames() { return this.Config.LedNames; }
|
||||
setLedNames(ledNames) { this.Config.LedNames = ledNames; }
|
||||
|
||||
getLedPositions() { return this.Config.LedPositions; }
|
||||
setLedPositions(ledPositions) { this.Config.LedPositions = ledPositions; }
|
||||
|
||||
getLeds() { return this.Config.Leds; }
|
||||
setLeds(leds) { this.Config.Leds = leds; }
|
||||
|
||||
getDeviceImage() { return this.Config.image; }
|
||||
setDeviceImage(image) { this.Config.image = image; }
|
||||
|
||||
getWirelessSupport() { return this.Config.Wireless; }
|
||||
setWirelessSupport(wireless) { this.Config.Wireless = wireless; }
|
||||
|
||||
Initialize() {
|
||||
//Initializing vars
|
||||
this.setDeviceProductId(device.productId());
|
||||
|
||||
const DeviceProperties = this.getDeviceProperties(this.getDeviceProductId());
|
||||
this.setDeviceName(DeviceProperties.name);
|
||||
this.setDeviceEndpoint(DeviceProperties.endpoint);
|
||||
this.setLedNames(DeviceProperties.LedNames);
|
||||
this.setLedPositions(DeviceProperties.LedPositions);
|
||||
this.setLeds(DeviceProperties.Leds);
|
||||
this.setDeviceImage(DeviceProperties.image);
|
||||
|
||||
if(DeviceProperties.wireless){
|
||||
this.setWirelessSupport(DeviceProperties.wireless);
|
||||
device.addFeature("battery");
|
||||
device.addProperty({"property":"idleTimeout", "group":"", "label":"Device Sleep Timeout (Minutes)", "type":"combobox", "values":["Off", "1", "2", "3", "4", "5", "10", "15", "20", "25", "30"], "default":"10"});
|
||||
}
|
||||
|
||||
device.log("Device model found: " + this.getDeviceName());
|
||||
device.setName("Corsair " + this.getDeviceName());
|
||||
device.setSize(DeviceProperties.size);
|
||||
device.setControllableLeds(this.getLedNames(), this.getLedPositions());
|
||||
device.setImageFromUrl(this.getDeviceImage());
|
||||
device.set_endpoint(
|
||||
DeviceProperties.endpoint[`interface`],
|
||||
DeviceProperties.endpoint[`usage`],
|
||||
DeviceProperties.endpoint[`usage_page`],
|
||||
DeviceProperties.endpoint[`collection`]
|
||||
);
|
||||
|
||||
this.modernDirectLightingMode();
|
||||
}
|
||||
|
||||
modernDirectLightingMode() {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
console.log("Setting Software Mode!");
|
||||
device.write([0x02, headsetMode, 0x01, 0x03, 0x00, 0x02], 64); // Enable Software Mode
|
||||
device.write([0x02, headsetMode, 0x0D, 0x00, 0x01], 64); //Open lighting endpoint
|
||||
device.pause(1000);
|
||||
|
||||
const HWBrightnessPacket = [0x02, headsetMode, 0x02, 0x02, 0x00];
|
||||
|
||||
device.clearReadBuffer();
|
||||
device.write(HWBrightnessPacket, 64);
|
||||
device.pause(100);
|
||||
|
||||
const HWBrightness = device.read(HWBrightnessPacket, 64);
|
||||
|
||||
if (HWBrightness[4] !== 0xe8 || HWBrightness[5] !== 0x03) {
|
||||
device.write([0x02, headsetMode, 0x01, 0x02, 0x00, 0xe8, 0x03], 64); //Hardware Brightness 100%
|
||||
}
|
||||
}
|
||||
|
||||
sendColors(overrideColor) {
|
||||
|
||||
const deviceLedPositions = this.getLedPositions();
|
||||
const deviceLedNames = this.getLedNames();
|
||||
const deviceLeds = this.getLeds();
|
||||
const RGBData = [];
|
||||
|
||||
for (let iIdx = 0; iIdx < deviceLeds.length; iIdx++) {
|
||||
const iPxX = deviceLedPositions[iIdx][0];
|
||||
const iPxY = deviceLedPositions[iIdx][1];
|
||||
let color;
|
||||
|
||||
if(deviceLedNames[iIdx] === "Mic" && micLedMode === "MuteState"){
|
||||
const micState = this.fetchMicStatus();
|
||||
|
||||
if (micState === 1) {
|
||||
color = hexToRgb(micMuteColor);
|
||||
} else {
|
||||
color = device.color(iPxX, iPxY);
|
||||
}
|
||||
}else if (overrideColor){
|
||||
color = hexToRgb(overrideColor);
|
||||
}else if (LightingMode === "Forced") {
|
||||
color = hexToRgb(forcedColor);
|
||||
}else {
|
||||
color = device.color(iPxX, iPxY);
|
||||
}
|
||||
|
||||
RGBData[(deviceLeds[iIdx])] = color[0];
|
||||
RGBData[(deviceLeds[iIdx])+3] = color[1];
|
||||
RGBData[(deviceLeds[iIdx])+6] = color[2];
|
||||
}
|
||||
|
||||
this.writeRGB(RGBData);
|
||||
}
|
||||
|
||||
writeRGB(RGBData) {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
device.write([0x02, headsetMode, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00].concat(RGBData), 64);
|
||||
}
|
||||
|
||||
fetchMicStatus(){
|
||||
|
||||
if(Date.now() - this.Config.lastMicStatePolling < this.Config.pollingInterval) {
|
||||
return this.Config.lastMicState;
|
||||
}
|
||||
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const micreadMode = this.getDeviceName().includes("HS80") === true ? 0xA6 : 0x46;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
const micStatusPacket = [0x02, headsetMode, 0x02, micreadMode, 0x00];
|
||||
|
||||
device.pause(100);
|
||||
device.clearReadBuffer();
|
||||
device.write(micStatusPacket, 64);
|
||||
device.pause(50);
|
||||
|
||||
const micStatus = device.read(micStatusPacket, 64); // Index 5 returns 0 to unmutted/enable and 1 to muted/disabled
|
||||
this.Config.lastMicStatePolling = Date.now();
|
||||
|
||||
if (micStatus[3] === micreadMode) {
|
||||
console.log("Invalid read on mic status.");
|
||||
|
||||
return this.Config.lastMicState;
|
||||
}
|
||||
|
||||
this.Config.lastMicState = micStatus[4];
|
||||
|
||||
return micStatus[4];
|
||||
|
||||
}
|
||||
|
||||
setSidetone() {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
const sidetoneValue = Math.round((SidetoneAmount / 100) * 1000);
|
||||
|
||||
console.log("Setting Sidetone!");
|
||||
device.write([0x02, headsetMode, 0x01, 0x47, 0x00, sidetoneValue & 0xFF, (sidetoneValue >> 8) & 0xFF], 64);
|
||||
}
|
||||
|
||||
setIdleTimeout() {
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
if (idleTimeout === "Off") {
|
||||
console.log ("Setting Idle Timeout to: disabled");
|
||||
device.write([0x02, headsetMode, 0x01, 0x0D], 64);
|
||||
} else {
|
||||
device.write([0x02, headsetMode, 0x01, 0x0D, 0x01], 64);
|
||||
device.pause(1);
|
||||
|
||||
device.write([0x02, headsetMode, 0x01, 0x0D, 0x00, 0x01], 64);
|
||||
device.pause(1);
|
||||
|
||||
const timeoutValue = idleTimeout * 60000;
|
||||
const hexValue = timeoutValue.toString(16).padStart(6, '0');
|
||||
const littleEndianHex = hexValue.match(/../g).reverse();
|
||||
|
||||
const packet = [];
|
||||
packet[0] = 0x02;
|
||||
packet[1] = headsetMode;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = 0x0e;
|
||||
|
||||
packet[5] = parseInt(littleEndianHex[0], 16);
|
||||
packet[6] = parseInt(littleEndianHex[1], 16);
|
||||
packet[7] = parseInt(littleEndianHex[2], 16);
|
||||
|
||||
console.log ("Setting Idle Timeout to: " + idleTimeout);
|
||||
device.write(packet, 64);
|
||||
}
|
||||
}
|
||||
|
||||
fetchBattery(){
|
||||
|
||||
if(Date.now() - this.Config.lastBatteryPolling < this.Config.pollingBatteryInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headsetMode = this.getWirelessSupport() === true ? 0x09 : 0x08;
|
||||
const endpoint = this.getDeviceEndpoint();
|
||||
device.set_endpoint(endpoint[`interface`], endpoint[`usage`], endpoint[`usage_page`]);
|
||||
|
||||
const batteryLevelPacket = [0x02, headsetMode, 0x02, 0x0F, 0x00];
|
||||
const batteryStatusPacket = [0x02, headsetMode, 0x02, 0x10, 0x00];
|
||||
|
||||
device.pause(1000);
|
||||
device.clearReadBuffer();
|
||||
device.write(batteryLevelPacket, 64);
|
||||
|
||||
device.pause(50);
|
||||
device.clearReadBuffer();
|
||||
device.write(batteryStatusPacket, 64);
|
||||
|
||||
const batteryLevelData = device.read(batteryLevelPacket, 64);
|
||||
const batteryStatusData = device.read(batteryStatusPacket, 64);
|
||||
|
||||
const batteryLevel = this.ReadInt32LittleEndian(batteryLevelData.slice(4, 7));
|
||||
const batteryStatus = batteryStatusData[4];
|
||||
|
||||
this.Config.lastBatteryPolling = Date.now();
|
||||
|
||||
device.log(`Battery Level is [${(batteryLevel ?? 0)/10}%]`);
|
||||
device.log(`Battery Status is [${this.chargingStates[batteryStatus ?? 0]}]`);
|
||||
|
||||
battery.setBatteryLevel((batteryLevel ?? 0)/ 10);
|
||||
battery.setBatteryState(this.chargingStates[batteryStatus ?? 0]);
|
||||
}
|
||||
|
||||
ReadInt32LittleEndian(array){
|
||||
return (array[0] & 0xFF) | ((array[1] << 8) & 0xFF00) | ((array[2] << 16) & 0xFF0000) | ((array[3] << 24) & 0xFF000000);
|
||||
}
|
||||
}
|
||||
|
||||
export class deviceLibrary {
|
||||
constructor(){
|
||||
this.PIDLibrary = {
|
||||
0x0A43: "Virtuoso",
|
||||
0x0A42: "Virtuoso",
|
||||
0x0A41: "Virtuoso",
|
||||
0x0A44: "Virtuoso",
|
||||
0x0A40: "Virtuoso",
|
||||
0x0A4B: "Virtuoso",
|
||||
0x0A4C: "Virtuoso",
|
||||
0x0A5C: "Virtuoso",
|
||||
0x0A3D: "Virtuoso SE",
|
||||
0x0A3E: "Virtuoso SE",
|
||||
0x0A34: "Virtuoso SE",
|
||||
0x0A62: "Virtuoso XT",
|
||||
0x0A64: "Virtuoso XT", // Wireless
|
||||
0x0A69: "HS80",
|
||||
//0x0A6A: "HS80", // PID for wired WHILE wireless dongle plugged in, doesnt control the headset
|
||||
0x0A6B: "HS80",
|
||||
0x0A71: "HS80", //White
|
||||
0x0A73: "HS80", //White
|
||||
};
|
||||
|
||||
this.LEDLibrary = {
|
||||
|
||||
// Virtuoso Standard
|
||||
0x0A43: {
|
||||
name: "Virtuoso",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A42: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A41: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A44: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A40: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A4B: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A4C: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
0x0A5C: {
|
||||
name: "Virtuoso Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-standard.png"
|
||||
},
|
||||
|
||||
// Virtuoso SE
|
||||
0x0A3D: {
|
||||
name: "Virtuoso SE",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-se.png"
|
||||
},
|
||||
0x0A3E: {
|
||||
name: "Virtuoso SE Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-se.png"
|
||||
},
|
||||
0x0A346: { // NEED TO CONFIRM
|
||||
name: "Virtuoso SE Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Left Cans", "Right Can", "Mic"],
|
||||
LedPositions: [[0, 2], [2, 2], [1, 0]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 4, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0005 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-se.png"
|
||||
},
|
||||
|
||||
// Virtuoso XT
|
||||
0x0A62: {
|
||||
name: "Virtuoso XT",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0005 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-xt.png"
|
||||
},
|
||||
0x0A64: {
|
||||
name: "Virtuoso XT Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0005 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/virtuoso-xt.png"
|
||||
},
|
||||
|
||||
// HS80
|
||||
/*
|
||||
0x0A6A: { // PID for wired WHILE wireless dongle plugged in
|
||||
name: "HS80 RGB",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
endpoint : { "interface": 0, "usage": 0x0001, "usage_page": 0xFF58, "collection": 0x0001 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/hs80.png"
|
||||
},
|
||||
*/
|
||||
0x0A69: {
|
||||
name: "HS80 RGB",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/hs80.png"
|
||||
},
|
||||
0x0A6B: {
|
||||
name: "HS80 RGB Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/hs80.png"
|
||||
},
|
||||
0x0A71: {
|
||||
name: "HS80 RGB White",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0004 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/hs80.png"
|
||||
},
|
||||
0x0A73: { //White
|
||||
name: "HS80 RGB White Wireless",
|
||||
size: [3, 3],
|
||||
LedNames: ["Logo", "Power", "Mic"],
|
||||
LedPositions: [[1, 0], [0, 2], [2, 2]],
|
||||
Leds: [0, 1, 2],
|
||||
wireless: true,
|
||||
endpoint : { "interface": 3, "usage": 0x0001, "usage_page": 0xFF42, "collection": 0x0005 },
|
||||
image: "https://assets.signalrgb.com/devices/brands/corsair/audio/hs80.png"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const CORSAIRdeviceLibrary = new deviceLibrary();
|
||||
const CORSAIR = new CORSAIR_Device_Protocol();
|
||||
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
const colors = [];
|
||||
colors[0] = parseInt(result[1], 16);
|
||||
colors[1] = parseInt(result[2], 16);
|
||||
colors[2] = parseInt(result[3], 16);
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
export function Validate(endpoint) {
|
||||
return endpoint.interface === 0 || endpoint.interface === 3 || endpoint.interface === 4;
|
||||
}
|
||||
|
||||
export function ImageUrl() {
|
||||
return "https://assets.signalrgb.com/devices/default/misc/usb-drive-render.png";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user