eAmuse Cloud support

This commit is contained in:
William Toohey
2017-06-17 01:51:50 +10:00
parent bf28be5e4d
commit d3c8435035
11 changed files with 161 additions and 62 deletions
+18 -13
View File
@@ -4,21 +4,22 @@
#include "Config.h"
#include "Macro.h"
uint8_t firstRun EEMEM; // init to 255
sdvx_config_t eeConfig EEMEM;
sdvx_config_t sdvxConfig;
static const PROGMEM sdvx_config_t defaults = {
.configVersion = CONFIG_VERSION,
.switches = {
HID_KEYBOARD_SC_ENTER,
HID_KEYBOARD_SC_Z,
HID_KEYBOARD_SC_X,
HID_KEYBOARD_SC_DOT_AND_GREATER_THAN_SIGN,
HID_KEYBOARD_SC_SLASH_AND_QUESTION_MARK,
HID_KEYBOARD_SC_C,
HID_KEYBOARD_SC_M,
HID_KEYBOARD_SC_ENTER,
HID_KEYBOARD_SC_KEYPAD_PLUS}, // macro
.controlMode = CONTROL_JOYSTICK,
.btColour = {BRIGHTNESS_MAX, BRIGHTNESS_MAX, BRIGHTNESS_MAX}, // white
.fxColour = {BRIGHTNESS_MAX, BRIGHTNESS_MAX/4, 0}, // orange
.breatheColour = {BRIGHTNESS_MAX/2, BRIGHTNESS_MAX/8, 0}, // dim orange
@@ -39,30 +40,34 @@ static const PROGMEM sdvx_config_t defaults = {
.action = PIN_ENTRY,
.keypress = 0
},
.macroLen = 4,
.macroPin = {HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT},
.joystickMode = 1,
};
void InitConfig(void) {
if (eeprom_read_byte(&firstRun) != CONFIG_VERSION) { // store defaults
memcpy_P(&sdvxConfig, &defaults, sizeof(sdvx_config_t));
eeprom_update_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
eeprom_update_byte(&firstRun, CONFIG_VERSION); // defaults set
// TODO: if config version changes, migrate settings
switch(eeprom_read_word(&eeConfig.configVersion)) {
case CONFIG_VERSION: // nothing needs to change
break;
default:
memcpy_P(&sdvxConfig, &defaults, CONFIG_SIZE);
eeprom_update_block(&sdvxConfig, &eeConfig, CONFIG_SIZE);
break;
}
eeprom_read_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
eeprom_read_block(&sdvxConfig, &eeConfig, CONFIG_SIZE);
}
void SetConfig(sdvx_config_t* config) {
memcpy(&sdvxConfig, config, sizeof(sdvx_config_t));
eeprom_update_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
memcpy(&sdvxConfig, config, CONFIG_SIZE);
sdvxConfig.configVersion = CONFIG_VERSION;
eeprom_update_block(&sdvxConfig, &eeConfig, CONFIG_SIZE);
}
void UpdateConfig(void) {
eeprom_update_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
eeprom_update_block(&sdvxConfig, &eeConfig, CONFIG_SIZE);
}
command_response_t HandleConfig(uint8_t* buffer) {
@@ -73,7 +78,7 @@ command_response_t HandleConfig(uint8_t* buffer) {
command->data.version.serial = 0xDEAD; // TODO set properly later
return RESPOND;
case GETCONFIG:
memcpy(&command->data.config, &sdvxConfig, CONFIG_BYTES);
memcpy(&command->data.config, &sdvxConfig, CONFIG_SIZE);
return RESPOND;
case SETCONFIG:
SetConfig(&command->data.config);
+15 -6
View File
@@ -12,16 +12,25 @@
#define JOYSTICK_PPR (24 * 4)
#define MAGIC_RESET_NUMBER 42
// divide by 10 for actual version
#define FIRMWARE_VERSION 12
#define FIRMWARE_VERSION 14
// increment whenever config structure has breaking changes
#define CONFIG_VERSION 1
#define CONFIG_VERSION 2
// not configurable since they're all the same switches
#define SWITCH_DEBOUNCE 30
typedef enum {
CONTROL_KEYBOARD_MOUSE = 0,
CONTROL_JOYSTICK = 1,
CONTROL_EAC = 2
} control_mode_t;
typedef struct {
// SWITCH ORDER: A-D, FXL-R, START
// So we can detect and upgrade without losing settings
uint16_t configVersion;
// SWITCH ORDER: START, A-D, FXL-R
uint8_t switches[SWITCH_COUNT];
uint8_t controlMode;
RGB_t btColour;
RGB_t fxColour;
RGB_t breatheColour;
@@ -34,12 +43,12 @@ typedef struct {
// When tapping or long-pressing the macro key
Macro_t macroClick;
Macro_t macroHold;
// Reused for both
// Reused for both tap or hold, at the end in case I decide to extend
uint8_t macroLen; // placeholder not used yet
uint8_t macroPin[4];
uint8_t joystickMode;
} ATTR_PACKED sdvx_config_t;
#define CONFIG_BYTES sizeof(sdvx_config_t)
#define CONFIG_SIZE sizeof(sdvx_config_t)
typedef struct {
uint16_t version;
@@ -36,7 +36,7 @@ COMMAND_VERSION = 0x03
COMMAND_STARTAPPLICATION = 0x04
COMMAND_PROGRAM = 0x05
BOOTLOADER_VERSION = 65000
BOOTLOADER_VERSION = 11
# Device information table
device_info_map = dict()
@@ -86,10 +86,6 @@ def program_device(hex_data, device_info):
print("No valid device found.")
sys.exit(1)
if get_version(device) != BOOTLOADER_VERSION:
print("Device not in bootloader. TODO: reboot")
sys.exit(1)
try:
print("Connected to bootloader.")
+30 -3
View File
@@ -182,7 +182,7 @@ const uint8_t PROGMEM BOSDescriptor[] =
)
};
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor_Standard =
{
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
@@ -205,6 +205,29 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
};
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor_EAC =
{
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
.USBSpecification = VERSION_BCD(2,1,0),
.Class = USB_CSCP_NoDeviceClass,
.SubClass = USB_CSCP_NoDeviceSubclass,
.Protocol = USB_CSCP_NoDeviceProtocol,
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
// to pretend we are someone else
.VendorID = 0x1CCF,
.ProductID = 0x1014,
// To provide uniqueness
.ReleaseNumber = VERSION_BCD(0,0,3),
.ManufacturerStrIndex = STRING_ID_Manufacturer,
.ProductStrIndex = STRING_ID_Product,
.SerialNumStrIndex = USE_INTERNAL_SERIAL,
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
};
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
.Config =
@@ -433,8 +456,12 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
switch (DescriptorType)
{
case DTYPE_Device:
Address = &DeviceDescriptor;
Size = sizeof(USB_Descriptor_Device_t);
if(sdvxConfig.controlMode == CONTROL_EAC) {
Address = &DeviceDescriptor_EAC;
} else {
Address = &DeviceDescriptor_Standard;
}
Size = sizeof(USB_Descriptor_Device_t);
break;
case DTYPE_Configuration:
Address = &ConfigurationDescriptor;
+14 -14
View File
@@ -105,16 +105,16 @@ uint8_t load_switches(void) {
uint8_t result = 0;
tmp = PINB;
LOAD_SWITCH(tmp, 1, result, 0); // PINB1, A
LOAD_SWITCH(tmp, 0, result, 4); // PINB0, FX L
LOAD_SWITCH(tmp, 1, result, 1); // PINB1, A
LOAD_SWITCH(tmp, 0, result, 5); // PINB0, FX L
tmp = PINC;
LOAD_SWITCH(tmp, 2, result, 6); // PINC2, START
LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START
LOAD_SWITCH(tmp, 1, result, 7); // PINC1, MACRO
tmp = PIND;
LOAD_SWITCH(tmp, 7, result, 1); // PIND7, B
LOAD_SWITCH(tmp, 5, result, 2); // PIND5, C
LOAD_SWITCH(tmp, 4, result, 3); // PIND4, D
LOAD_SWITCH(tmp, 6, result, 5); // PIND6, FX L
LOAD_SWITCH(tmp, 7, result, 2); // PIND7, B
LOAD_SWITCH(tmp, 5, result, 3); // PIND5, C
LOAD_SWITCH(tmp, 4, result, 4); // PIND4, D
LOAD_SWITCH(tmp, 6, result, 6); // PIND6, FX R
return result;
}
@@ -180,15 +180,15 @@ int main(void)
if(sdvxConfig.keyLights) {
// Keep normal lights but override when we get flashes on BT or FX
// BT LEDs
for(uint8_t i = 0; i < 4; i++) {
for(uint8_t i = 1; i < 5; i++) {
if(switches[i].state) {
led_set_rgb(ledMap[i], &sdvxConfig.btColour);
led_set_rgb(ledMap[i-1], &sdvxConfig.btColour);
}
}
// FX LEDs
for(uint8_t i = 4; i < 6; i++) {
for(uint8_t i = 5; i < 7; i++) {
if(switches[i].state) {
led_set_rgb(ledMap[i], &sdvxConfig.fxColour);
led_set_rgb(ledMap[i-1], &sdvxConfig.fxColour);
}
}
}
@@ -263,7 +263,7 @@ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDIn
if(sendKeyboard) {
*ReportID = HID_REPORTID_KeyboardReport;
} else {
if(sdvxConfig.joystickMode) {
if(sdvxConfig.controlMode != CONTROL_KEYBOARD_MOUSE) {
*ReportID = HID_REPORTID_JoystickReport;
} else {
*ReportID = HID_REPORTID_MouseReport;
@@ -277,12 +277,12 @@ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDIn
// Only the first 4 bytes are read by bemanitools, so let's use the first
uint8_t macroUpdated = macro_make_report(&KeyboardReport->KeyCode[0]);
if(!macroUpdated && (sdvxConfig.joystickMode || !switchesChanged)) {
if(!macroUpdated && (sdvxConfig.controlMode != CONTROL_KEYBOARD_MOUSE || !switchesChanged)) {
*ReportSize = 0;
return false;
}
if(!sdvxConfig.joystickMode) {
if(sdvxConfig.controlMode == CONTROL_KEYBOARD_MOUSE) {
// NOTE: using SWITCH_COUNT-1 so we don't write the report for the macro pin
for(uint8_t i = 0; i < SWITCH_COUNT-1; i++) {
// i+1 to take care of the shift from above
+1 -1
View File
@@ -27,7 +27,7 @@ body, html {
}
.connect {
height: 100%;
margin-top: 30px;
display: flex;
align-items: center;
justify-content: center;
+3 -2
View File
@@ -1,4 +1,5 @@
{
"version": 12,
"md5": "6620eb96cde1ecdcc0c5caefac7f9d03"
"version": 14,
"md5": "a07ab17b2ac21c9e0f165eac30f40e99",
"changelog" : "Add support for e-AMUSEMENT CLOUD native input"
}
+17 -3
View File
@@ -17,11 +17,25 @@
document.getElementById("connectBtn").classList.remove("hidden");
config = new Config();
navigator.usb.getDevices()
.then(devices => {
if(devices.length) {
config.connect(devices[0]);
}
});
navigator.usb.addEventListener('connect', event => {
config.connect(event.device);
});
navigator.usb.addEventListener('disconnect', event => {
config.disableUI();
});
}
});
</script>
<!-- Origin Trial Token, feature = WebUSB (For Chrome M57+), origin = https://mon.im, expires = 2017-07-02 -->
<meta http-equiv="origin-trial" data-feature="WebUSB (For Chrome M57+)" data-expires="2017-07-02" content="AhzuiYytgNCrxPIuPxB9c3Eoyr7CbrPzl5hRLm4me+5OpcNSWk+eb6QGaPfktLvGaF/vMFPS531rJ48h7wiDWgwAAABHeyJvcmlnaW4iOiJodHRwczovL21vbi5pbTo0NDMiLCJmZWF0dXJlIjoiV2ViVVNCMiIsImV4cGlyeSI6MTQ5OTA1Njk5OH0=">
<!-- Origin Trial Token, feature = WebUSB (For Chrome M57+), origin = https://mon.im, expires = 2017-07-17 -->
<meta http-equiv="origin-trial" data-feature="WebUSB (For Chrome M57+)" data-expires="2017-07-17" content="AtfCI+37VRHohPe+OASF7EuEDM1ZhH6Dr1W2je8iRI885ETbV5VT/RGnIyg06SGJiGUgNrl20HrAH47shlEyjwsAAABHeyJvcmlnaW4iOiJodHRwczovL21vbi5pbTo0NDMiLCJmZWF0dXJlIjoiV2ViVVNCMiIsImV4cGlyeSI6MTUwMDMwMjYwNn0=">
</head>
<body>
<div class="center">
@@ -33,7 +47,7 @@
<!--<div id="configBox" class="configBox hidden disabled">
</div>-->
<div id="connect" class="connect">
<button id="connectBtn" class="hidden" onclick="config.connect()">Connect</button>
<button id="connectBtn" class="hidden" onclick="config.connectNew()">Connect</button>
</div>
<div id="configOptions" class="configOptions">
</div>
+31 -12
View File
@@ -1,8 +1,9 @@
(function(window, document) {
"use strict";
var vid = 0x16D0;
var pid = 0x0A6D;
// could be monim, could be pretending
var vids = [0x16D0, 0x1CCF];
var pids = [0x0A6D, 0x1014];
var UsbWrapper = window.UsbWrapper;
var device;
@@ -21,9 +22,11 @@ var commands = {
};
var configDisplay = [
{id: 'joystickMode', name: 'Input mode',
options : [{name: 'Keyboard/Mouse', val: 0}, {name: 'Joystick', val: 1}]},
{id: 'switches', name: 'Keyboard bindings', labels: ['BT-A','BT-B','BT-C','BT-D','FX-L','FX-R','START']},
{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'},
@@ -48,7 +51,9 @@ var configDisplay = [
// to match with firmware
var settingOrder = [
'version',
'switches',
'controlMode',
'btColour',
'fxColour',
'breatheColour',
@@ -61,8 +66,8 @@ var settingOrder = [
'lightPattern',
'macroClick',
'macroHold',
'macroLen',
'macroPin',
'joystickMode'
];
var defaultConfig = {
@@ -117,7 +122,9 @@ class BinaryBuffer {
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);
@@ -130,8 +137,8 @@ class ConfigValues {
this.lightPattern = new SettingRadio();
this.macroClick = new SettingMacro();
this.macroHold = new SettingMacro();
this.macroLen = new SettingPlaceholder(1);
this.macroPin = new SettingKeys(4);
this.joystickMode = new SettingRadio();
}
read(view, writeCallback) {
@@ -189,16 +196,21 @@ class Config {
//this.enableUI();
}
connect() {
return UsbWrapper.connect(vid, pid)
connectNew() {
return UsbWrapper.connect(vids, pids)
.then(selectedDevice => {
if(!selectedDevice) {
return Promise.reject('No device selected');
}
device = selectedDevice;
visibleLog("Opening device...");
return device.open();
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)
@@ -248,6 +260,7 @@ class Config {
.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");
}
@@ -334,6 +347,12 @@ class Config {
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;
+20
View File
@@ -14,6 +14,25 @@ class Setting {
// All settings must have createUI, read and write.
// When the UI changes, call fireCallback to update the device config
class SettingPlaceholder extends Setting {
constructor(bytes) {
super();
this.bytes = bytes;
}
read(buffer) {
this.val = buffer.read(this.bytes);
}
write(buffer) {
buffer.write(this.val);
}
createUI(setting) {
return null;
}
}
class SettingBool extends Setting {
read(buffer) {
this.box.checked = !!buffer.read(1);
@@ -341,6 +360,7 @@ var scancodes = [
{name: "NUM .", value: 0x63}
];
window.SettingPlaceholder = SettingPlaceholder;
window.SettingBool = SettingBool;
window.SettingRGB = SettingRGB;
window.SettingRadio = SettingRadio;
+11 -3
View File
@@ -7,15 +7,23 @@
var UsbWrapper = new function() {
this.hasUSB = navigator && navigator.usb;
if(!this.hasUSB)
return;
// returns a promise
this.connect = (vid, pid) => {
return navigator.usb.requestDevice({ filters: [
{ vendorId: vid, productId: pid }] })
this.connect = (vids, pids) => {
var filters = [];
for(let i = 0; i < vids.length; i++) {
filters.push({ vendorId: vids[i], productId: pids[i] });
}
return navigator.usb.requestDevice({filters: filters})
.catch(error => {
console.log(error);
return null;
});
};
this.usb = navigator.usb;
};
window.UsbWrapper = UsbWrapper;