Files
mon_PocketVoltex/Software/WebConfig/js/config.js
T

360 lines
11 KiB
JavaScript

(function(window, document) {
"use strict";
// could be monim, could be pretending
var vids = [0x16D0, 0x1CCF];
var pids = [0x0A6D, 0x1014];
var device;
var SWITCH_COUNT = 8;
var BRIGHTNESS_MAX = 127;
var CONFIG_OUT_EPADDR = 1;
var CONFIG_IN_EPADDR = 2;
var packetSize = 64;
var commands = {
GETCONFIG : 1,
SETCONFIG : 2,
VERSION : 3,
RESET : 42
};
var configDisplay = [
{id: 'controlMode', name: 'Input mode',
options : [{name: 'Keyboard/Mouse', val: 0},
{name: 'Joystick', val: 1},
{name: 'e-AMUSEMENT CLOUD (reconnect after change)', val: 2}]},
{id: 'switches', name: 'Keyboard bindings', labels: ['START','BT-A','BT-B','BT-C','BT-D','FX-L','FX-R']},
{id: 'macroClick', name: 'Macro click'},
{id: 'macroHold', name: 'Macro longpress'},
{id: 'macroPin', name: 'Macro PIN'},
{id: 'lightsOn', name: 'Enable LEDs', children: [
{id: 'hidLights', name: 'HID Lights'},
{id: 'keyLights', name: 'Key lights', children: [
{id: 'btColour', name: 'BT colour'},
{id: 'fxColour', name: 'FX colour'},
]},
{id: 'knobLights', name: 'Knob lights', children: [
{id: 'knobL', name: 'VOL-L colour'},
{id: 'knobR', name: 'VOL-R colour'},
]},
{id: 'lightPattern', name: 'Lights pattern',
options : [{name: 'None', val : 1},
{name: 'Solid', val: 2},
{name: 'Breathe', val: 4},
{name: 'Follower', val: 3}]},
{id: 'breatheColour', name: 'Solid/Breathe colour'},
]},
];
// to match with firmware
var settingOrder = [
'version',
'switches',
'controlMode',
'btColour',
'fxColour',
'breatheColour',
'knobL',
'knobR',
'lightsOn',
'hidLights',
'keyLights',
'knobLights',
'lightPattern',
'macroClick',
'macroHold',
'macroLen',
'macroPin',
];
var defaultConfig = {
switches : [],
ledsOn : true,
//macroClick : KP_PLUS,
macroPin : [0,0,0,0],
}
var visibleLog = function(html) {
console.log(html);
var log = document.getElementById('logview');
log.innerHTML += html + '<br/>';
log.scrollTop = log.scrollHeight;
}
class BinaryBuffer {
constructor(view) {
this.view = view;
this.offset = 0;
}
read(size, forceArray = false) {
let ret;
if(size == 1 && !forceArray) {
ret = this.view.getUint8(this.offset);
} else {
ret = [];
for(var i = 0; i < size; i++) {
ret[i] = this.view.getUint8(this.offset+i);
}
}
this.offset += size;
return ret;
}
write(data) {
if(Array.isArray(data)) {
for(let i = 0; i < data.length; i++) {
this.view[this.offset+i] = data[i];
}
this.offset += data.length;
} else {
this.view[this.offset++] = data;
}
}
rewind() {
this.offset = 0;
}
}
class ConfigValues {
constructor() {
this.version = new SettingPlaceholder(2);
this.switches = new SettingKeys(SWITCH_COUNT, true);
this.controlMode = new SettingRadio();
this.btColour = new SettingRGB(BRIGHTNESS_MAX);
this.fxColour = new SettingRGB(BRIGHTNESS_MAX);
this.breatheColour = new SettingRGB(BRIGHTNESS_MAX);
this.knobL = new SettingRGB(BRIGHTNESS_MAX);
this.knobR = new SettingRGB(BRIGHTNESS_MAX);
this.lightsOn = new SettingBool();
this.hidLights = new SettingBool();
this.keyLights = new SettingBool();
this.knobLights = new SettingBool();
this.lightPattern = new SettingRadio();
this.macroClick = new SettingMacro();
this.macroHold = new SettingMacro();
this.macroLen = new SettingPlaceholder(1);
this.macroPin = new SettingKeys(4);
}
read(view, writeCallback) {
var buffer = new BinaryBuffer(view);
// skip the returned command byte
buffer.read(1);
settingOrder.forEach(setting => {
this[setting].read(buffer);
this[setting].setCallback(writeCallback);
});
}
write(view) {
var buffer = new BinaryBuffer(view);
buffer.write(commands.SETCONFIG);
settingOrder.forEach(setting => {
this[setting].write(buffer);
});
}
getArray(view, offset, size) {
var ret = [];
for(var i = 0; i < size; i++) {
ret[i] = view.getUint8(offset+i);
}
return ret;
};
getColour(view, offset) {
return 'rgb(' + this.getArray(view, offset, 3).join() + ')';
};
getKeys(view, offset, size) {
var keys = [];
for(let i = 0; i < size; i++) {
keys[i] = this.getKey(view, offset++);
}
return keys;
}
getKey(view, offset) {
var key = view.getUint8(offset);
return scancodes.find(code => {return code.value == key});
}
}
class Config {
constructor() {
visibleLog("Welcome to the Pocket Voltex Configurator");
this.optionsDiv = document.getElementById('configOptions');
this.config = new ConfigValues();
// DEBUG
//this.enableUI();
}
connectNew() {
return window.UsbWrapper.connect(vids, pids)
.then(selectedDevice => {
if(!selectedDevice) {
return Promise.reject('No device selected');
}
this.connect(selectedDevice);
})
}
connect(selectedDevice) {
console.log(selectedDevice);
device = selectedDevice;
visibleLog("Opening device...");
return device.open()
.then(() => {
console.log("Opened, selecting configuration...");
return device.selectConfiguration(1)
})
.then(() => {
if(device.deviceVersionSubminor == 2) { // bootloader
return this.loadFirmware();
} else if(device.deviceVersionSubminor == 3) { // main program
return this.loadConfig();
} else {
return Promise.reject("Invalid device found, is this a Tatacon converter?");
}
})
.catch(error => {
//alert(error);
visibleLog(error);
if(device && device.opened)
device.close();
});
}
loadFirmware() {
visibleLog("Downloading fimware...");
return getLatest()
.then(downloadLatest)
.then(firmware => {
visibleLog("Flashing firmware...");
return programLatest(device, firmware);
})
.then(() => {
visibleLog("Done!");
})
}
loadConfig() {
console.log("Selected, claiming interface...");
return device.claimInterface(0)
.then(() => {
visibleLog("Opened!");
return this.readVersion();
})
.then(version => {
this.version = version;
visibleLog("Found Pocket Voltex v" + version/10.0);
return getLatest();
})
.then(latestInfo => {
if(latestInfo.version > this.version) {
alert("Firmware update required. Device will be rebooted. Connect again to update");
visibleLog("Firmware update required. Connect again to update");
this.rebootToBootloader();
return Promise.reject("Rebooted to bootloader, config read aborted");
}
})
.then(() => {
this.enableUI();
return this.readConfig();
});
}
readVersion() {
if(!device || !device.opened)
return Promise.reject("Device not opened");
var data = new Uint8Array(packetSize);
data[0] = commands.VERSION;
return device.transferOut(CONFIG_OUT_EPADDR, data)
.then(() => device.transferIn(CONFIG_IN_EPADDR, packetSize))
.then(result => {
console.log(result);
console.log("Got version response of len", result.data.buffer.byteLength);
// version int exists at offset 1
return result.data.getUint16(1, true);
})
}
readConfig() {
if(!device || !device.opened)
return Promise.reject("Device not opened");
var data = new Uint8Array(packetSize);
data[0] = commands.GETCONFIG;
return device.transferOut(CONFIG_OUT_EPADDR, data)
.then(() => device.transferIn(CONFIG_IN_EPADDR, packetSize))
.then(result => {
console.log("Got config response of len", result.data.buffer.byteLength);
this.config.read(result.data, this.writeConfig.bind(this));
});
}
writeConfig() {
if(!device || !device.opened)
return Promise.reject("Device not opened");
console.log("Writing config");
var data = new Uint8Array(packetSize);
this.config.write(data);
return device.transferOut(CONFIG_OUT_EPADDR, data);
}
close() {
if(!device || !device.opened)
return Promise.reject("Device not opened");
visibleLog("Closing device...");
return device.close();
}
rebootToBootloader() {
if(!device || !device.opened)
return Promise.reject("Device not opened");
var data = new Uint8Array(packetSize);
data[0] = commands.RESET;
return device.transferOut(CONFIG_OUT_EPADDR, data);
};
populateSettings(parent, settings) {
settings.forEach(setting => {
var settingObj = this.config[setting.id];
var container = settingObj.createUI(setting);
settingObj.setCallback(this.writeConfig.bind(this));
if(setting.children) {
var newParent = document.createElement('div');
newParent.className = 'nestedSetting';
this.populateSettings(newParent, setting.children);
container.appendChild(newParent);
}
parent.appendChild(container);
});
}
enableUI() {
//document.getElementById('configBox').classList.remove('hidden', 'disabled');
document.getElementById('connect').classList.add('hidden');
this.populateSettings(this.optionsDiv, configDisplay);
}
disableUI() {
visibleLog('Device disconnected');
document.getElementById('connect').classList.remove('hidden');
this.optionsDiv.innerHTML = '';
}
};
window.Config = Config;
window.visibleLog = visibleLog;
})(window, document);