770 lines
246 KiB
Plaintext
770 lines
246 KiB
Plaintext
|
export function Name() { return "Logitech Powerplay Dongle"; }
|
||
|
export function VendorId() { return 0x046d; }
|
||
|
export function ProductId() { return 0xC53A; }
|
||
|
export function Publisher() { return "WhirlwindFX"; }
|
||
|
export function Size() { return [3, 3]; }
|
||
|
export function DefaultPosition(){return [240,120]}
|
||
|
export function DefaultScale(){return 8.0}
|
||
|
export function ControllableParameters(){
|
||
|
return [
|
||
|
{"property":"shutdownColor", "label":"Shutdown Color","min":"0","max":"360","type":"color","default":"009bde"},
|
||
|
{"property":"LightingMode", "label":"Lighting Mode", "type":"combobox", "values":["Canvas","Forced"], "default":"Canvas"},
|
||
|
{"property":"forcedColor", "label":"Forced Color","min":"0","max":"360","type":"color","default":"009bde"},
|
||
|
{"property":"DpiControl", "label":"Enable Dpi Control","type":"boolean","default":"false"},
|
||
|
{"property":"dpi1", "label":"DPI","step":"50", "type":"number","min":"200", "max":"25600","default":"800"},
|
||
|
{"property":"DpiLight", "label":"DPI Light Always On","type":"boolean","default":1},
|
||
|
{"property":"pollingrate", "label":"Polling Rate","type":"combobox", "values":[ "1000","500", "250", "100" ], "default":"1000"},
|
||
|
];
|
||
|
}
|
||
|
|
||
|
const LogitechBatteryVoltageDict =
|
||
|
{
|
||
|
4186: 100,
|
||
|
4156: 99,
|
||
|
4143: 98,
|
||
|
4133: 97,
|
||
|
4122: 96,
|
||
|
4113: 95,
|
||
|
4103: 94,
|
||
|
4094: 93,
|
||
|
4086: 92,
|
||
|
4076: 91,
|
||
|
4067: 90,
|
||
|
4060: 89,
|
||
|
4051: 88,
|
||
|
4043: 87,
|
||
|
4036: 86,
|
||
|
4027: 85,
|
||
|
4019: 84,
|
||
|
4012: 83,
|
||
|
4004: 82,
|
||
|
3997: 81,
|
||
|
3989: 80,
|
||
|
3983: 79,
|
||
|
3976: 78,
|
||
|
3969: 77,
|
||
|
3961: 76,
|
||
|
3955: 75,
|
||
|
3949: 74,
|
||
|
3942: 73,
|
||
|
3935: 72,
|
||
|
3929: 71,
|
||
|
3922: 70,
|
||
|
3916: 69,
|
||
|
3909: 68,
|
||
|
3902: 67,
|
||
|
3896: 66,
|
||
|
3890: 65,
|
||
|
3883: 64,
|
||
|
3877: 63,
|
||
|
3870: 62,
|
||
|
3865: 61,
|
||
|
3859: 60,
|
||
|
3853: 59,
|
||
|
3848: 58,
|
||
|
3842: 57,
|
||
|
3837: 56,
|
||
|
3833: 55,
|
||
|
3828: 54,
|
||
|
3824: 53,
|
||
|
3819: 52,
|
||
|
3815: 51,
|
||
|
3811: 50,
|
||
|
3808: 49,
|
||
|
3804: 48,
|
||
|
3800: 47,
|
||
|
3797: 46,
|
||
|
3793: 45,
|
||
|
3790: 44,
|
||
|
3787: 43,
|
||
|
3784: 42,
|
||
|
3781: 41,
|
||
|
3778: 40,
|
||
|
3775: 39,
|
||
|
3772: 38,
|
||
|
3770: 37,
|
||
|
3767: 36,
|
||
|
3764: 35,
|
||
|
3762: 34,
|
||
|
3759: 33,
|
||
|
3757: 32,
|
||
|
3754: 31,
|
||
|
3751: 30,
|
||
|
3748: 29,
|
||
|
3744: 28,
|
||
|
3741: 27,
|
||
|
3737: 26,
|
||
|
3734: 25,
|
||
|
3730: 24,
|
||
|
3726: 23,
|
||
|
3724: 22,
|
||
|
3720: 21,
|
||
|
3717: 20,
|
||
|
3714: 19,
|
||
|
3710: 18,
|
||
|
3706: 17,
|
||
|
3702: 16,
|
||
|
3697: 15,
|
||
|
3693: 14,
|
||
|
3688: 13,
|
||
|
3683: 12,
|
||
|
3677: 11,
|
||
|
3671: 10,
|
||
|
3666: 9,
|
||
|
3662: 8,
|
||
|
3658: 7,
|
||
|
3654: 6,
|
||
|
3646: 5,
|
||
|
3633: 4,
|
||
|
3612: 3,
|
||
|
3579: 2,
|
||
|
3537: 1,
|
||
|
3500: 0
|
||
|
}
|
||
|
const WIRED = 0xFF;
|
||
|
const WIRELESS = 0x01;
|
||
|
var Hero = false;
|
||
|
var savedDpi1;
|
||
|
var DeviceId;
|
||
|
var TransactionId;
|
||
|
var deviceName;
|
||
|
var RGBFeatureID;
|
||
|
var PollingRateID;
|
||
|
var DpiID;
|
||
|
var BattID;
|
||
|
var Sleep = false;
|
||
|
|
||
|
const deviceIdMap =
|
||
|
{
|
||
|
"405d" : "Logitech G403L",
|
||
|
"407f" : "Logitech G502L",
|
||
|
"4070" : "Logitech G703L",
|
||
|
"4086" : "Logitech G703 Hero",
|
||
|
"4053" : "Logitech G900L",
|
||
|
"4067" : "Logitech G903L",
|
||
|
"4087" : "Logitech G903 Hero",
|
||
|
"4079" : "Logitech GPro Wireless",
|
||
|
}
|
||
|
|
||
|
const Powerplay_Mat = {
|
||
|
mapping : [
|
||
|
0
|
||
|
],
|
||
|
positioning : [
|
||
|
[0,0]
|
||
|
],
|
||
|
displayName: "PowerPlay MousePad",
|
||
|
ledCount : 1,
|
||
|
width: 3,
|
||
|
height: 3,
|
||
|
image: Image()
|
||
|
}
|
||
|
|
||
|
var vLedNames = ["Primary Zone", "Logo Zone"];
|
||
|
var vLedPositions = [ [0,1],[0,2] ];
|
||
|
|
||
|
export function LedNames()
|
||
|
{
|
||
|
return vLedNames;
|
||
|
}
|
||
|
|
||
|
export function LedPositions()
|
||
|
{
|
||
|
return vLedPositions;
|
||
|
}
|
||
|
|
||
|
export function Initialize()
|
||
|
{
|
||
|
device.flush()
|
||
|
GrabIds();
|
||
|
|
||
|
let data = [0x80, 0x02, 0x02, 0x00]
|
||
|
|
||
|
let value = Logitech_Short_Set(WIRED, data)
|
||
|
|
||
|
DeviceId = value[3].toString(16) + value[2].toString(16)
|
||
|
TransactionId = value[0];
|
||
|
|
||
|
deviceName = deviceIdMap[DeviceId] || "UNKNOWN"
|
||
|
device.log(`Device Id Found: ${DeviceId}`);
|
||
|
device.log(`Device Name: ${deviceName}`);
|
||
|
|
||
|
device.log("Transaction ID Found: " + TransactionId.toString(16));
|
||
|
|
||
|
if(DeviceId == "00")//make hero mice not angry. They won't run without that extra junk and always give 00.
|
||
|
{
|
||
|
|
||
|
let value = Logitech_Short_Set(WIRED)
|
||
|
|
||
|
let data = [0x80, 0x00, 0x00, 0x01]
|
||
|
Logitech_Short_Set(WIRED, data)
|
||
|
|
||
|
data = [0x80, 0x02, 0x00, 0x00]
|
||
|
value = Logitech_Short_Set(WIRED, data)
|
||
|
|
||
|
data = [0x80, 0x02, 0x02, 0x00]
|
||
|
value = Logitech_Short_Set(WIRED, data)
|
||
|
|
||
|
DeviceId = value[3].toString(16) + value[2].toString(16)
|
||
|
TransactionId = value[0];
|
||
|
|
||
|
deviceName = deviceIdMap[DeviceId] || "UNKNOWN"
|
||
|
device.log(`Device Id Found: ${DeviceId}`);
|
||
|
device.log(`Device Name: ${deviceName}`);
|
||
|
|
||
|
}
|
||
|
|
||
|
if(Hero == true)
|
||
|
{
|
||
|
SetHeroDirectMode();
|
||
|
SetHeroDpiLightAlwaysOn(DpiLight);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetDirectMode();
|
||
|
SetDpiLightAlwaysOn(DpiLight)
|
||
|
}
|
||
|
|
||
|
if(savedDpi1 != dpi1 && DpiControl)
|
||
|
{
|
||
|
setDpi(dpi1);
|
||
|
}
|
||
|
|
||
|
GetBatteryCharge();
|
||
|
|
||
|
//Create Mouse Pad Sub Device
|
||
|
device.createSubdevice("PowerPlayMat");
|
||
|
device.setSubdeviceName("PowerPlayMat",`${Powerplay_Mat.displayName}`);
|
||
|
device.setSubdeviceImage("PowerPlayMat", Powerplay_Mat.image);
|
||
|
device.setSubdeviceSize("PowerPlayMat",Powerplay_Mat.width,Powerplay_Mat.height);
|
||
|
}
|
||
|
|
||
|
export function ondpi1Changed()
|
||
|
{
|
||
|
setDpi(dpi1);
|
||
|
}
|
||
|
|
||
|
var savedPollTimer = Date.now();
|
||
|
var PollModeInternal = 15000;
|
||
|
|
||
|
function PollBattery()
|
||
|
{
|
||
|
|
||
|
if (Date.now() - savedPollTimer < PollModeInternal)
|
||
|
{
|
||
|
return
|
||
|
}
|
||
|
savedPollTimer = Date.now();
|
||
|
GetBatteryCharge();
|
||
|
}
|
||
|
|
||
|
export function Render()
|
||
|
{
|
||
|
CheckForSleep();
|
||
|
CheckForHandoff();
|
||
|
if(Sleep == false)
|
||
|
{
|
||
|
|
||
|
if(Hero == true)
|
||
|
{
|
||
|
sendHeroZone(0);
|
||
|
sendHeroZone(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sendZone(0);
|
||
|
sendZone(1);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
sendMousePad();
|
||
|
PollBattery();
|
||
|
}
|
||
|
|
||
|
|
||
|
export function Shutdown()
|
||
|
{
|
||
|
if(Hero == true)
|
||
|
{
|
||
|
sendHeroZone(0, true);
|
||
|
sendHeroZone(1, true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sendZone(0, true);
|
||
|
sendZone(1, true);
|
||
|
}
|
||
|
sendMousePad(true);
|
||
|
}
|
||
|
|
||
|
export function onDpiLightChanged()
|
||
|
{
|
||
|
if (Hero == true)
|
||
|
{
|
||
|
SetHeroDpiLightAlwaysOn(DpiLight)
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetDpiLightAlwaysOn(DpiLight)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export function onpollingrateChanged()
|
||
|
{
|
||
|
setPollingRate();
|
||
|
}
|
||
|
|
||
|
function GrabIds()
|
||
|
{
|
||
|
const InfoPage = [0x00,0x03]
|
||
|
var InfoID = Logitech_FeatureID_Get(InfoPage)
|
||
|
if(InfoID != 0)
|
||
|
{
|
||
|
device.log("Device Info ID: " + InfoID);
|
||
|
}
|
||
|
|
||
|
const NamePage = [0x00,0x05]
|
||
|
var NameID = Logitech_FeatureID_Get(NamePage)
|
||
|
if(NameID != 0)
|
||
|
{
|
||
|
device.log("Device Name ID: " + NameID);
|
||
|
}
|
||
|
|
||
|
const ResetPage = [0x00,0x20]
|
||
|
var ResetID = Logitech_FeatureID_Get(ResetPage)
|
||
|
if(ResetID != 0)
|
||
|
{
|
||
|
device.log("Device Reset ID: " + ResetID);
|
||
|
}
|
||
|
|
||
|
const BatteryPage = [0x10,0x01]
|
||
|
BattID = Logitech_FeatureID_Get(BatteryPage)
|
||
|
if(BattID != 0)
|
||
|
{
|
||
|
device.log("Battery ID: " + BattID);
|
||
|
}
|
||
|
|
||
|
const UnifiedBatteryPage = [0x10,0x04]
|
||
|
var UnifiedBattID = Logitech_FeatureID_Get(UnifiedBatteryPage)
|
||
|
if(UnifiedBattID != 0)
|
||
|
{
|
||
|
device.log("Unified Battery ID: " + UnifiedBattID);
|
||
|
}
|
||
|
|
||
|
const LEDCtrlPage = [0x13,0x00]
|
||
|
var LEDCtrlID = Logitech_FeatureID_Get(LEDCtrlPage)
|
||
|
if(LEDCtrlID != 0)
|
||
|
{
|
||
|
device.log("Led Control ID: " + LEDCtrlID);
|
||
|
}
|
||
|
|
||
|
const WirelessStatusPage = [0x1D,0x4B]
|
||
|
var WirelessStatusID = Logitech_FeatureID_Get(WirelessStatusPage)
|
||
|
if(WirelessStatusID != 0)
|
||
|
{
|
||
|
device.log("Wireless Status ID: " + WirelessStatusID);
|
||
|
}
|
||
|
|
||
|
const DPIPage = [0x22,0x01]
|
||
|
DpiID = Logitech_FeatureID_Get(DPIPage)
|
||
|
if(DpiID != 0)
|
||
|
{
|
||
|
device.log("DPI ID: " + DpiID);
|
||
|
}
|
||
|
|
||
|
const PollingRatePage = [0x80,0x60]
|
||
|
var PollingRateID = Logitech_FeatureID_Get(PollingRatePage)
|
||
|
if(PollingRateID != 0)
|
||
|
{
|
||
|
device.log("Polling Rate ID: " + PollingRateID);
|
||
|
}
|
||
|
|
||
|
const OnboardProfilePage = [0x00,0x00,0x81,0x00]
|
||
|
var OnboardID = Logitech_FeatureID_Get(OnboardProfilePage)
|
||
|
if(OnboardID != 0)
|
||
|
{
|
||
|
device.log("Onboard Profiles ID: " + OnboardID);
|
||
|
}
|
||
|
|
||
|
const ButtonSpyPage = [0x81,0x10]
|
||
|
var ButtonSpyID = Logitech_FeatureID_Get(ButtonSpyPage)
|
||
|
if(ButtonSpyID != 0)
|
||
|
{
|
||
|
device.log("Button Spy ID: " + ButtonSpyID);
|
||
|
}
|
||
|
|
||
|
const ReportRatePage = [0x80,0x60]
|
||
|
var ReportRateID = Logitech_FeatureID_Get(ReportRatePage)
|
||
|
if(ReportRateID != 0)
|
||
|
{
|
||
|
device.log("ReportRateID: " + ReportRateID);
|
||
|
}
|
||
|
|
||
|
|
||
|
const PerKeyLightingPage = [0x80,0x80]
|
||
|
var PerKeyLightingID = Logitech_FeatureID_Get(PerKeyLightingPage)
|
||
|
if(PerKeyLightingID != 0)
|
||
|
{
|
||
|
device.log("PerKeyLightingID: " + PerKeyLightingID);
|
||
|
}
|
||
|
|
||
|
const PerKeyLightingV2Page = [0x80,0x81]
|
||
|
var PerKeyLightingV2ID = Logitech_FeatureID_Get(PerKeyLightingV2Page)
|
||
|
if(PerKeyLightingV2ID != 0)
|
||
|
{
|
||
|
device.log("PerKeyLightingV2ID: " + PerKeyLightingID);
|
||
|
}
|
||
|
|
||
|
const RGB8070Page = [0x80,0x70]
|
||
|
RGBFeatureID = Logitech_FeatureID_Get(RGB8070Page)
|
||
|
if(RGBFeatureID == 0)
|
||
|
{
|
||
|
const RGB8071Page = [0x80,0x71]
|
||
|
RGBFeatureID = Logitech_FeatureID_Get(RGB8071Page)
|
||
|
if(RGBFeatureID != 0)
|
||
|
{
|
||
|
Hero = true;
|
||
|
device.log("Hero");
|
||
|
}
|
||
|
}
|
||
|
if(RGBFeatureID != 0)
|
||
|
{
|
||
|
device.log("RGB Control ID : " + RGBFeatureID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function clearShortReadBuffer(){
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF
|
||
|
device.read([0x10,0x01],7)
|
||
|
while(device.getLastReadSize() > 0){
|
||
|
device.read([0x10,0xFF],7)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function clearLongReadBuffer(){
|
||
|
device.set_endpoint(2, 0x0002, 0xff00); // Lighting IF
|
||
|
device.read([0x11,0x01],20)
|
||
|
while(device.getLastReadSize() > 0){
|
||
|
device.read([0x10,0x01],20)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function Logitech_Short_Set(Mode, data)
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF
|
||
|
clearShortReadBuffer();
|
||
|
var packet = [0x10,Mode ]
|
||
|
data = data || [ 0x80, 0x00, 0x00, 0x00];
|
||
|
packet = packet.concat(data)
|
||
|
device.write(packet, 7)
|
||
|
packet = device.read(packet,7);
|
||
|
|
||
|
return packet.slice(3,7)
|
||
|
}
|
||
|
|
||
|
function Logitech_Long_Get(Mode, data)
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0002, 0xff00); // Lighting IF
|
||
|
clearLongReadBuffer();
|
||
|
var packet = [0x11,Mode]
|
||
|
data = data || [0x00, 0x00, 0x00];
|
||
|
packet = packet.concat(data)
|
||
|
device.write(packet, 20)
|
||
|
packet = device.read(packet,20);
|
||
|
|
||
|
return packet.slice(4,7)
|
||
|
}
|
||
|
|
||
|
function Logitech_FeatureID_Get(page){
|
||
|
return Logitech_Long_Get(WIRELESS, [0x00,0x00].concat(page))[0]
|
||
|
}
|
||
|
|
||
|
export function GetBatteryCharge(){
|
||
|
let [voltage,state] = LogitechGetBatteryVoltage(BattID)
|
||
|
return GetApproximateBatteryPercentage(voltage)
|
||
|
}
|
||
|
|
||
|
export function GetBatteryStatus(){
|
||
|
let [voltage,state] = LogitechGetBatteryVoltage()
|
||
|
return StatusDict[state]
|
||
|
}
|
||
|
|
||
|
function LogitechGetBatteryVoltage()
|
||
|
{
|
||
|
|
||
|
let data = [BattID, 0x00, 0x1A]
|
||
|
let BatteryArray = Logitech_Long_Get(0x01, data)
|
||
|
device.log(BatteryArray)
|
||
|
let BatteryVoltage = (BatteryArray[0] << 8) + BatteryArray[1]
|
||
|
let BatteryStatus = BatteryArray[2]
|
||
|
|
||
|
device.log("Battery Voltage: " + BatteryVoltage);
|
||
|
device.log("Battery Status: " + StatusDict[BatteryStatus]);
|
||
|
return [BatteryVoltage, BatteryStatus];
|
||
|
}
|
||
|
|
||
|
const StatusDict =
|
||
|
{
|
||
|
0 : "Discharging", //Discharging
|
||
|
128 : "Charging", //Charging
|
||
|
144 : "Wireless Charging" //Wireless Charging
|
||
|
|
||
|
}
|
||
|
const VoltageArray = [ 4186,4156,4143,4133,4122,4113,4103,4094,4086,4076,4067,4060,4051,4043,4036,4027,4019,4012,4004,3997,3989,3983,3976,3969,3961,3955,3949,3942,3935,3929,3922,3916,3909,3902,3896,3890,3883,3877,3870,3865,3859,3853,3848,3842,3837,3833,3828,3824,3819,3815,3811,3808,3804,3800,3797,3793,3790,3787,3784,3781,3778,3775,3772,3770,3767,3764,3762,3759,3757,3754,3751,3748,3744,3741,3737,3734,3730,3726,3724,3720,3717,3714,3710,3706,3702,3697,3693,3688,3683,3677,3671,3666,3662,3658,3654,3646,3633,3612,3579,3537,3500 ];
|
||
|
function GetApproximateBatteryPercentage(BatteryVoltage){
|
||
|
|
||
|
const nearestVoltageBand = VoltageArray.reduce((prev, curr) => {
|
||
|
return (Math.abs(curr - BatteryVoltage) < Math.abs(prev - BatteryVoltage) ? curr : prev);
|
||
|
});
|
||
|
device.log("Battery Percentage Remaining: " + LogitechBatteryVoltageDict[nearestVoltageBand]);
|
||
|
return LogitechBatteryVoltageDict[nearestVoltageBand]
|
||
|
}
|
||
|
|
||
|
function setDpi(dpi)
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF
|
||
|
|
||
|
savedDpi1 = dpi1;
|
||
|
|
||
|
var packet = [];
|
||
|
packet[0] = 0x10;
|
||
|
packet[1] = WIRELESS;
|
||
|
packet[2] = DpiID;
|
||
|
packet[3] = 0x30;
|
||
|
packet[4] = 0x00;//My money is on this being zone
|
||
|
packet[5] = Math.floor(dpi/256);
|
||
|
packet[6] = dpi%256;
|
||
|
|
||
|
device.write(packet, 7);
|
||
|
device.pause(1); //This is here because I was having issues with the device applying the dpi consistenly
|
||
|
}
|
||
|
|
||
|
function setPollingRate()
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF
|
||
|
|
||
|
var packet = [];
|
||
|
packet[0] = 0x10;
|
||
|
packet[1] = WIRELESS;
|
||
|
packet[2] = PollingRateID;
|
||
|
packet[3] = 0x20;
|
||
|
packet[4] = 1000/pollingrate;
|
||
|
|
||
|
device.write(packet, 7);
|
||
|
device.pause(1);
|
||
|
}
|
||
|
|
||
|
function SetDpiLightAlwaysOn(DpiLight){//Fun fact: this is making use of the led control Feature ID
|
||
|
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF
|
||
|
var packet = [0x10, 0x01, 0x08, 0x07E, 0x01, (DpiLight ? 0x02 : 0x04) ,0x00]//0x07 is unknown
|
||
|
device.write(packet, 7);
|
||
|
|
||
|
device.set_endpoint(2, 0x0002, 0xff00); // Lighting IF
|
||
|
packet = [0x11, 0x01, 0x08, 0x05E, 0x01,0x00,0x02, 0x00, 0x02]//0x50 is set led state
|
||
|
device.write(packet, 20);
|
||
|
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF //0x60 should be grabbing config from nvram
|
||
|
packet = [0x10, 0x01, 0x08, 0x06E, 0x01]
|
||
|
device.write(packet, 7);
|
||
|
}
|
||
|
|
||
|
function SetHeroDpiLightAlwaysOn(DpiLight)
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0002, 0xff00);
|
||
|
var packet = [0x11, 0x01, 0x07, 0x03B, 0x01, 0x00 ,0x08, (DpiLight ? 0x04 : 0x02), 0x07]
|
||
|
device.write(packet, 20)
|
||
|
|
||
|
device.set_endpoint(2, 0x0001, 0xff00);
|
||
|
packet = [0x10, 0x01, 0x07, 0x02B, 0x00, 0x03, 0x00 ]
|
||
|
device.write(packet, 7)
|
||
|
|
||
|
device.set_endpoint(2, 0x0001, 0xff00);
|
||
|
packet = [0x10, 0x01, 0x07, 0x03B, 0x00, 0x00, 0x08]
|
||
|
device.write(packet, 7)
|
||
|
}
|
||
|
|
||
|
function sendZone(zone, shutdown = false)
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0002, 0xff00);
|
||
|
var packet = [];
|
||
|
packet[0x00] = 0x11;
|
||
|
packet[0x01] = WIRELESS;
|
||
|
packet[0x02] = RGBFeatureID;
|
||
|
packet[0x03] = 0x3B;
|
||
|
packet[0x04] = zone;
|
||
|
packet[0x05] = 0x01;
|
||
|
|
||
|
var iX = vLedPositions[zone][0];
|
||
|
var iY = vLedPositions[zone][1];
|
||
|
var color;
|
||
|
if(shutdown)
|
||
|
{
|
||
|
color = hexToRgb(shutdownColor);
|
||
|
}else if (LightingMode == "Forced")
|
||
|
{
|
||
|
color = hexToRgb(forcedColor);
|
||
|
}else
|
||
|
{
|
||
|
color = device.color(iX, iY);
|
||
|
}
|
||
|
packet[0x06] = color[0];
|
||
|
packet[0x07] = color[1];
|
||
|
packet[0x08] = color[2];
|
||
|
packet[0x09] = 0x02;
|
||
|
|
||
|
if(DeviceId == "4067" || DeviceId == "4070" || DeviceId == "4087")
|
||
|
{
|
||
|
packet[16] = 0x01;
|
||
|
}
|
||
|
device.write(packet, 20);
|
||
|
device.read(packet, 20)
|
||
|
|
||
|
if(DeviceId == "4079" || DeviceId == "4087" || DeviceId == "405d")
|
||
|
{
|
||
|
Apply();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function sendHeroZone(zone, shutdown = false)
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0002, 0xff00); // Lighting IF
|
||
|
var packet = [];
|
||
|
packet[0x00] = 0x11;
|
||
|
packet[0x01] = WIRELESS;
|
||
|
packet[0x02] = RGBFeatureID;
|
||
|
packet[0x03] = 0x1A;
|
||
|
packet[0x04] = zone;
|
||
|
packet[0x05] = 0x01;
|
||
|
|
||
|
var iX = vLedPositions[zone][0];
|
||
|
var iY = vLedPositions[zone][1];
|
||
|
var color;
|
||
|
if(shutdown)
|
||
|
{
|
||
|
color = hexToRgb(shutdownColor);
|
||
|
}else if (LightingMode == "Forced")
|
||
|
{
|
||
|
color = hexToRgb(forcedColor);
|
||
|
}else
|
||
|
{
|
||
|
color = device.color(iX, iY);
|
||
|
}
|
||
|
packet[0x06] = color[0];
|
||
|
packet[0x07] = color[1];
|
||
|
packet[0x08] = color[2];
|
||
|
packet[0x10] = 0x02;
|
||
|
|
||
|
packet[16] = 0x01;
|
||
|
|
||
|
device.write(packet, 20);
|
||
|
device.read(packet, 20)
|
||
|
}
|
||
|
|
||
|
function sendMousePad(shutdown = false){
|
||
|
|
||
|
device.set_endpoint(2, 0x0002, 0xff00); // Lighting IF
|
||
|
|
||
|
var packet = [];
|
||
|
packet[0x00] = 0x11;
|
||
|
packet[0x01] = 0x07;
|
||
|
packet[0x02] = 0x0b;
|
||
|
packet[0x03] = 0x3E;
|
||
|
packet[0x04] = 0x00;
|
||
|
packet[0x05] = 0x01;
|
||
|
|
||
|
var iX = Powerplay_Mat.positioning[0][0];
|
||
|
var iY = Powerplay_Mat.positioning[0][1];
|
||
|
var color;
|
||
|
if(shutdown){
|
||
|
color = hexToRgb(shutdownColor)
|
||
|
}else if (LightingMode == "Forced") {
|
||
|
color = hexToRgb(forcedColor)
|
||
|
}else{
|
||
|
color = device.subdeviceColor("PowerPlayMat",iX, iY);
|
||
|
}
|
||
|
packet[0x06] = color[0];
|
||
|
packet[0x07] = color[1];
|
||
|
packet[0x08] = color[2];
|
||
|
|
||
|
device.write(packet, 20);
|
||
|
device.pause(1);
|
||
|
}
|
||
|
|
||
|
function Apply()
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00); // System IF
|
||
|
var packet = [];
|
||
|
packet[0] = 0x10;
|
||
|
packet[1] = WIRELESS;
|
||
|
packet[2] = 0x0B;
|
||
|
packet[3] = 0x2F;
|
||
|
packet[4] = 0x01;
|
||
|
device.write(packet, 7);
|
||
|
device.read(packet, 7)
|
||
|
}
|
||
|
|
||
|
function CheckForSleep()
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00);
|
||
|
var packet = [];
|
||
|
packet = device.readTimeout([0x00],64, 5);
|
||
|
|
||
|
if(packet[0] == 0x10 && packet[1] == 0x01 && packet[2] == 0x41 && packet[3] == 0x0C && packet[4] == 0x62 && packet[6] == 0x40)
|
||
|
{
|
||
|
device.log("Mouse Going to Sleep");
|
||
|
return Sleep = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function CheckForHandoff()
|
||
|
{
|
||
|
|
||
|
device.set_endpoint(2, 0x0002, 0xff00);
|
||
|
var packet = [];
|
||
|
packet = device.readTimeout([0x00],64, 5);
|
||
|
|
||
|
if(packet[0] == 0x11 && packet[1] == 0x01 && packet[2] == 0x06 && packet[3] == 0x00 && packet[6] == 0x00)
|
||
|
{
|
||
|
device.log("Waking From Sleep")
|
||
|
device.pause(5000); //Wait five seconds before Handoff. Allows device boot time.
|
||
|
Initialize();
|
||
|
return Sleep = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function SetDirectMode()
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00);
|
||
|
let packet = [0x10, 0x01, RGBFeatureID, 0x80, 0x01, 0x01]//0x80 in this case sets a register
|
||
|
device.write(packet, 7)
|
||
|
device.read(packet, 7)
|
||
|
}
|
||
|
|
||
|
function SetHeroDirectMode()
|
||
|
{
|
||
|
device.set_endpoint(2, 0x0001, 0xff00);
|
||
|
let packet = [0x10, 0x01, 0x07, 0x5A, 0x01, 0x03, 0x05]
|
||
|
device.write(packet, 7)
|
||
|
device.read(packet, 7)
|
||
|
}
|
||
|
|
||
|
export function Validate(endpoint)
|
||
|
{
|
||
|
return endpoint.interface === 2 && endpoint.usage === 0x0002 && endpoint.usage_page === 0xff00
|
||
|
|| endpoint.interface === 2 && endpoint.usage === 0x0001 && endpoint.usage_page === 0xff00;
|
||
|
}
|
||
|
function hexToRgb(hex)
|
||
|
{
|
||
|
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||
|
var colors = [];
|
||
|
colors[0] = parseInt(result[1], 16);
|
||
|
colors[1] = parseInt(result[2], 16);
|
||
|
colors[2] = parseInt(result[3], 16);
|
||
|
|
||
|
return colors;
|
||
|
}
|
||
|
|
||
|
export function Image()
|
||
|
{
|
||
|
return "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
|