mirror of
https://github.com/mon/PocketVoltex.git
synced 2026-10-02 11:48:21 +03:00
Better macros, better config, initial updater
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.configBox {
|
||||
@@ -12,12 +18,9 @@
|
||||
}
|
||||
|
||||
.connect {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 285px;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.connect > button {
|
||||
@@ -25,16 +28,9 @@
|
||||
}
|
||||
|
||||
.configOptions {
|
||||
margin-left: 180px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
height: 400px;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.configOptions > div, .configOptions > p {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.colourPicker {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<script type="text/javascript" src="js/usbWrapper.js"></script>
|
||||
<script type="text/javascript" src="js/config.js"></script>
|
||||
<script type="text/javascript" src="js/updater.js"></script>
|
||||
<script type="text/javascript" src="js/jscolor.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("load", function() {
|
||||
|
||||
+111
-60
@@ -21,24 +21,28 @@ var commands = {
|
||||
};
|
||||
|
||||
var configDisplay = [
|
||||
{id: 'joystickMode', name: 'Input mode', display : 'radio',
|
||||
{id: 'joystickMode', name: 'Input mode',
|
||||
options : [{name: 'Keyboard/Mouse', val: 0}, {name: 'Joystick', val: 1}]},
|
||||
{id: 'macroClick', name: 'Macro click', display : 'key'},
|
||||
{id: 'macroHold', name: 'Macro longpress', display : 'bool'},
|
||||
{id: 'macroPin', name: 'Macro PIN', display : 'pin'},
|
||||
{id: 'lightsOn', name: 'Enable LEDs', display : 'bool', children: [
|
||||
{id: 'hidLights', name: 'HID Lights', display : 'bool'},
|
||||
{id: 'keyLights', name: 'Key lights', display : 'bool', children: [
|
||||
{id: 'btColour', name: 'BT colour', display: 'rgb'},
|
||||
{id: 'fxColour', name: 'FX colour', display: 'rgb'},
|
||||
{id: 'switches', name: 'Keyboard bindings'},
|
||||
{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', display : 'bool', children: [
|
||||
{id: 'knobL', name: 'VOL-L colour', display : 'rgb'},
|
||||
{id: 'knobR', name: 'VOL-R colour', display : 'rgb'},
|
||||
{id: 'knobLights', name: 'Knob lights', children: [
|
||||
{id: 'knobL', name: 'VOL-L colour'},
|
||||
{id: 'knobR', name: 'VOL-R colour'},
|
||||
]},
|
||||
{id: 'lightPattern', name: 'Lights pattern', display : 'radio',
|
||||
options : [{name: 'Solid', val: 2}, {name: 'Follower', val: 3}, {name: 'Breathe', val: 4}]},
|
||||
{id: 'breatheColour', name: 'Solid/Breathe colour', display : 'rgb'},
|
||||
{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'},
|
||||
]},
|
||||
];
|
||||
|
||||
@@ -65,7 +69,7 @@ var defaultConfig = {
|
||||
switches : [],
|
||||
ledsOn : true,
|
||||
//macroClick : KP_PLUS,
|
||||
macroPin : [1,2,3,4],
|
||||
macroPin : [0,0,0,0],
|
||||
}
|
||||
|
||||
var visibleLog = function(html) {
|
||||
@@ -123,12 +127,12 @@ class Setting {
|
||||
// All settings must have createUI, read and write.
|
||||
// When the UI changes, call fireCallback to update the device config
|
||||
class SettingBool extends Setting {
|
||||
read(reader) {
|
||||
this.box.checked = !!reader.read(1);
|
||||
read(buffer) {
|
||||
this.box.checked = !!buffer.read(1);
|
||||
}
|
||||
|
||||
write(reader) {
|
||||
reader.write(this.box.checked ? 1 : 0);
|
||||
write(buffer) {
|
||||
buffer.write(this.box.checked ? 1 : 0);
|
||||
}
|
||||
|
||||
createUI(setting) {
|
||||
@@ -150,16 +154,16 @@ class SettingBool extends Setting {
|
||||
}
|
||||
|
||||
class SettingRGB extends Setting {
|
||||
read(reader) {
|
||||
read(buffer) {
|
||||
var rgb = [];
|
||||
for(var i = 0; i < 3; i++)
|
||||
rgb[i] = (reader.read(1) / BRIGHTNESS_MAX) * 255;
|
||||
rgb[i] = (buffer.read(1) / BRIGHTNESS_MAX) * 255;
|
||||
this.picker.fromRGB(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
write(reader) {
|
||||
write(buffer) {
|
||||
for(var i = 0; i < 3; i++)
|
||||
reader.write((this.picker.rgb[i] / 255) * BRIGHTNESS_MAX);
|
||||
buffer.write((this.picker.rgb[i] / 255) * BRIGHTNESS_MAX);
|
||||
}
|
||||
|
||||
createUI(setting) {
|
||||
@@ -237,32 +241,48 @@ class SettingRadio extends Setting {
|
||||
}
|
||||
|
||||
class SettingKeys extends Setting {
|
||||
constructor(switchCount) {
|
||||
constructor(switchCount, ignoreLast = false) {
|
||||
super();
|
||||
this.switchCount = switchCount;
|
||||
this.byteCount = switchCount;
|
||||
// hacks upon hacks, this stuff
|
||||
this.ignoreLast = ignoreLast;
|
||||
this.switchCount = ignoreLast ? switchCount - 1 : switchCount;
|
||||
}
|
||||
|
||||
read(reader) {
|
||||
this.keys = reader.read(this.switchCount);
|
||||
read(buffer) {
|
||||
var keys = buffer.read(this.byteCount);
|
||||
for(var i = 0; i < this.switchCount; i++) {
|
||||
this.selects[i].value = keys[i];
|
||||
}
|
||||
}
|
||||
|
||||
write(reader) {
|
||||
reader.write(this.keys);
|
||||
write(buffer) {
|
||||
for(var i = 0; i < this.selects.length; i++) {
|
||||
buffer.write(this.selects[i].value);
|
||||
}
|
||||
if(this.ignoreLast) {
|
||||
buffer.write(0);
|
||||
}
|
||||
}
|
||||
|
||||
createUI(setting) {
|
||||
var entry = document.createElement('p');
|
||||
entry.textContent = setting.name + ':';
|
||||
|
||||
var select = document.createElement("select");
|
||||
scancodes.forEach(function(code) {
|
||||
var option = document.createElement("option");
|
||||
option.value = code.value;
|
||||
option.textContent = code.name;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
entry.appendChild(select);
|
||||
this.selects = [];
|
||||
for(var i = 0; i < this.switchCount; i++) {
|
||||
var select = document.createElement("select");
|
||||
scancodes.forEach(function(code) {
|
||||
var option = document.createElement("option");
|
||||
option.value = code.value;
|
||||
option.textContent = code.name;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
select.onchange = this.fireCallback.bind(this);
|
||||
entry.appendChild(select);
|
||||
this.selects.push(select);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
@@ -282,9 +302,26 @@ class SettingPin extends Setting {
|
||||
}
|
||||
}
|
||||
|
||||
class SettingMacro extends Setting {
|
||||
createUI(setting) {
|
||||
var entry = document.createElement('p');
|
||||
entry.textContent = setting.name + ':';
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
read(buffer) {
|
||||
this.keys = buffer.read(2);
|
||||
}
|
||||
|
||||
write(buffer) {
|
||||
buffer.write(this.keys);
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigValues {
|
||||
constructor() {
|
||||
this.switches = new SettingKeys(SWITCH_COUNT);
|
||||
this.switches = new SettingKeys(SWITCH_COUNT, true);
|
||||
this.btColour = new SettingRGB();
|
||||
this.fxColour = new SettingRGB();
|
||||
this.breatheColour = new SettingRGB();
|
||||
@@ -295,10 +332,10 @@ class ConfigValues {
|
||||
this.keyLights = new SettingBool();
|
||||
this.knobLights = new SettingBool();
|
||||
this.lightPattern = new SettingRadio();
|
||||
this.macroClick = new SettingKeys(1);
|
||||
this.macroHold = new SettingBool();
|
||||
this.macroClick = new SettingMacro();
|
||||
this.macroHold = new SettingMacro();
|
||||
this.macroPin = new SettingKeys(4);
|
||||
this.joystickMode = new SettingBool();
|
||||
this.joystickMode = new SettingRadio();
|
||||
}
|
||||
|
||||
read(view, writeCallback) {
|
||||
@@ -367,9 +404,38 @@ class Config {
|
||||
return device.selectConfiguration(1)
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Selected, claiming interface...");
|
||||
return device.claimInterface(0);
|
||||
if(device.productName == 'Voltex Boot') {
|
||||
return this.loadFirmware();
|
||||
} else {
|
||||
return this.loadConfig();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
//alert(error);
|
||||
visibleLog(error);
|
||||
if(device && device.opened)
|
||||
device.close();
|
||||
});
|
||||
}
|
||||
|
||||
loadFirmware() {
|
||||
visibleLog("Downloading fimware...");
|
||||
return getLatest()
|
||||
.then(info => {
|
||||
return downloadLatest(info.version);
|
||||
})
|
||||
.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();
|
||||
@@ -379,12 +445,6 @@ class Config {
|
||||
this.enableUI();
|
||||
return this.readConfig();
|
||||
})
|
||||
.catch(error => {
|
||||
//alert(error);
|
||||
visibleLog(error);
|
||||
if(device && device.opened)
|
||||
device.close();
|
||||
});
|
||||
}
|
||||
|
||||
readVersion() {
|
||||
@@ -463,15 +523,6 @@ class Config {
|
||||
document.getElementById('connect').classList.add('hidden');
|
||||
this.populateSettings(this.optionsDiv, configDisplay);
|
||||
}
|
||||
|
||||
createSetting(parent, setting) {
|
||||
var func = this.settingsMap[setting.display];
|
||||
if(func) {
|
||||
func(parent, setting);
|
||||
} else {
|
||||
console.log('Unknown setting type', setting.display);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.Config = Config;
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
(function(window, document) {
|
||||
"use strict";
|
||||
|
||||
var pageSize = 128;
|
||||
// full size - bootloader
|
||||
var flashSize = (16 * 1024) - (2 * 1024);
|
||||
|
||||
var COMMAND_VERSION = 0x03;
|
||||
var COMMAND_STARTAPPLICATION = 0x04;
|
||||
var COMMAND_PROGRAM = 0x05;
|
||||
|
||||
var WEBUSB_ID = 0x01;
|
||||
var MS_OS_ID = 0x02;
|
||||
var CONFIG_ID = 0x03;
|
||||
|
||||
function getLatest() {
|
||||
return new Promise ((resolve, reject) => {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", "firmwares/latest.json", true);
|
||||
req.responseType = "json";
|
||||
|
||||
req.onload = function (oEvent) {
|
||||
if (req.response) {
|
||||
resolve(req.response);
|
||||
} else {
|
||||
reject(Error(req.status + ": Could not fetch latest firmware information"));
|
||||
}
|
||||
};
|
||||
|
||||
req.send();
|
||||
});
|
||||
};
|
||||
|
||||
function downloadLatest(version) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", "firmwares/PocketVoltex_" + version + ".bin", true);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
req.onload = function (oEvent) {
|
||||
var arrayBuffer = req.response;
|
||||
if (arrayBuffer) {
|
||||
var view = new Uint8Array(arrayBuffer);
|
||||
if(view.length <= flashSize) {
|
||||
resolve(view);
|
||||
} else {
|
||||
reject(Error("Firmware too big! Must be under " +flashSize + ", got " + arrayBuffer.length));
|
||||
}
|
||||
} else {
|
||||
reject(Error(req.status + ": Could not fetch firmware version " + version));
|
||||
}
|
||||
};
|
||||
|
||||
req.send();
|
||||
})
|
||||
};
|
||||
|
||||
function programLatest(device, hex) {
|
||||
var p = Promise.resolve();
|
||||
for(let addr = 0; addr < hex.length; addr += pageSize) {
|
||||
let page = hex.subarray(addr, addr+pageSize);
|
||||
p = p.then(() => {
|
||||
// pad to 0s when size smaller
|
||||
let packet = new Uint8Array(new ArrayBuffer(pageSize));
|
||||
packet.set(page);
|
||||
console.log(Math.round(addr / hex.length * 100) + '%');
|
||||
return device.controlTransferOut({
|
||||
requestType: 'vendor',
|
||||
recipient: 'device',
|
||||
request: CONFIG_ID,
|
||||
value: addr,
|
||||
index: COMMAND_PROGRAM}, packet);
|
||||
});
|
||||
}
|
||||
p = p.then(() => {
|
||||
console.log("Rebooting...");
|
||||
return device.controlTransferOut({
|
||||
requestType: 'vendor',
|
||||
recipient: 'device',
|
||||
request: CONFIG_ID,
|
||||
value: 0,
|
||||
index: COMMAND_STARTAPPLICATION}, []);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
window.downloadLatest = downloadLatest;
|
||||
window.getLatest = getLatest;
|
||||
window.programLatest = programLatest;
|
||||
|
||||
})(window, document);
|
||||
Reference in New Issue
Block a user