feat(device): Read user config from eeprom (#413)
* feat(device): Read user config from eeprom * read data from eeprom * fix user config serialization * fix device connected detection * not allow override default config is eeprom is empty * add error handling to eeprom parsing * colorize log output * add USB[T] feature * add class name to USB[T] log * remove redundant error log msg * Add USB[T] to Apply user config
This commit is contained in:
committed by
László Monda
parent
d621b1e5e6
commit
96e968729d
@@ -18,9 +18,11 @@ import { UhkHidDeviceService } from './uhk-hid-device.service';
|
||||
* UHK USB Communications command. All communication package should have start with a command code.
|
||||
*/
|
||||
enum Command {
|
||||
GetProperty = 0,
|
||||
UploadConfig = 8,
|
||||
ApplyConfig = 9,
|
||||
LaunchEepromTransfer = 12,
|
||||
ReadUserConfig = 15,
|
||||
GetKeyboardState = 16
|
||||
}
|
||||
|
||||
@@ -31,6 +33,15 @@ enum EepromTransfer {
|
||||
WriteUserConfig = 3
|
||||
}
|
||||
|
||||
enum SystemPropertyIds {
|
||||
UsbProtocolVersion = 0,
|
||||
BridgeProtocolVersion = 1,
|
||||
DataModelVersion = 2,
|
||||
FirmwareVersion = 3,
|
||||
HardwareConfigSize = 4,
|
||||
UserConfigSize = 5
|
||||
}
|
||||
|
||||
const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
/**
|
||||
@@ -38,6 +49,7 @@ const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
* Functionality:
|
||||
* - Detect device is connected or not
|
||||
* - Send UserConfiguration to the UHK Device
|
||||
* - Read UserConfiguration from the UHK Device
|
||||
*/
|
||||
export class DeviceService {
|
||||
private pollTimer$: Subscription;
|
||||
@@ -48,6 +60,7 @@ export class DeviceService {
|
||||
private device: UhkHidDeviceService) {
|
||||
this.pollUhkDevice();
|
||||
ipcMain.on(IpcEvents.device.saveUserConfiguration, this.saveUserConfiguration.bind(this));
|
||||
ipcMain.on(IpcEvents.device.loadUserConfiguration, this.loadUserConfiguration.bind(this));
|
||||
logService.debug('[DeviceService] init success');
|
||||
}
|
||||
|
||||
@@ -59,6 +72,38 @@ export class DeviceService {
|
||||
return this.connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the actual UserConfiguration from UHK Device
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
public async loadUserConfiguration(event: Electron.Event): Promise<void> {
|
||||
let response = [];
|
||||
|
||||
try {
|
||||
this.logService.debug('[DeviceService] USB[T]: Read user configuration size from keyboard');
|
||||
const configSize = await this.getUserConfigSizeFromKeyboard();
|
||||
const chunkSize = 63;
|
||||
let offset = 0;
|
||||
let configBuffer = new Buffer(0);
|
||||
|
||||
this.logService.debug('[DeviceService] USB[T]: Read user configuration from keyboard');
|
||||
while (offset < configSize) {
|
||||
const chunkSizeToRead = Math.min(chunkSize, configSize - offset);
|
||||
const writeBuffer = Buffer.from([Command.ReadUserConfig, chunkSizeToRead, offset & 0xff, offset >> 8]);
|
||||
const readBuffer = await this.device.write(writeBuffer);
|
||||
configBuffer = Buffer.concat([configBuffer, new Buffer(readBuffer.slice(1, chunkSizeToRead + 1))]);
|
||||
offset += chunkSizeToRead;
|
||||
}
|
||||
response = UhkHidDeviceService.convertBufferToIntArray(configBuffer);
|
||||
} catch (error) {
|
||||
this.logService.error('[DeviceService] getUserConfigFromEeprom error', error);
|
||||
} finally {
|
||||
this.device.close();
|
||||
}
|
||||
|
||||
event.sender.send(IpcEvents.device.loadUserConfigurationReply, JSON.stringify(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* HID API not support device attached and detached event.
|
||||
* This method check the keyboard is attached to the computer or not.
|
||||
@@ -76,25 +121,38 @@ export class DeviceService {
|
||||
.do((connected: boolean) => {
|
||||
this.connected = connected;
|
||||
this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, connected);
|
||||
this.logService.info(`Device connection state changed to: ${connected}`);
|
||||
this.logService.info(`[DeviceService] Device connection state changed to: ${connected}`);
|
||||
})
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the UserConfiguration size from the UHK Device
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
private async getUserConfigSizeFromKeyboard(): Promise<number> {
|
||||
const buffer = await this.device.write(new Buffer([Command.GetProperty, SystemPropertyIds.UserConfigSize]));
|
||||
const configSize = buffer[1] + (buffer[2] << 8);
|
||||
this.logService.debug('[DeviceService] User config size:', configSize);
|
||||
return configSize;
|
||||
}
|
||||
|
||||
private async saveUserConfiguration(event: Electron.Event, json: string): Promise<void> {
|
||||
const response = new IpcResponse();
|
||||
|
||||
try {
|
||||
this.sendUserConfigToKeyboard(json);
|
||||
this.logService.debug('[DeviceService] USB[T]: Write user configuration to keyboard');
|
||||
await this.sendUserConfigToKeyboard(json);
|
||||
this.logService.debug('[DeviceService] USB[T]: Write user configuration to EEPROM');
|
||||
await this.writeUserConfigToEeprom();
|
||||
this.device.close();
|
||||
|
||||
response.success = true;
|
||||
this.logService.info('transferring finished');
|
||||
}
|
||||
catch (error) {
|
||||
this.logService.error('[DeviceService] Transferring error', error);
|
||||
response.error = {message: error.message};
|
||||
} finally {
|
||||
this.device.close();
|
||||
}
|
||||
|
||||
event.sender.send(IpcEvents.device.saveUserConfigurationReply, response);
|
||||
@@ -114,19 +172,14 @@ export class DeviceService {
|
||||
for (const fragment of fragments) {
|
||||
await this.device.write(fragment);
|
||||
}
|
||||
|
||||
this.logService.debug('[DeviceService] USB[T]: Apply user configuration to keyboard');
|
||||
const applyBuffer = new Buffer([Command.ApplyConfig]);
|
||||
await this.device.write(applyBuffer);
|
||||
this.logService.info('[DeviceService] Transferring finished');
|
||||
}
|
||||
|
||||
private async writeUserConfigToEeprom(): Promise<void> {
|
||||
this.logService.info('[DeviceService] Start write user configuration to eeprom');
|
||||
|
||||
const buffer = await this.device.write(new Buffer([Command.LaunchEepromTransfer, EepromTransfer.WriteUserConfig]));
|
||||
await this.device.write(new Buffer([Command.LaunchEepromTransfer, EepromTransfer.WriteUserConfig]));
|
||||
await this.waitUntilKeyboardBusy();
|
||||
|
||||
this.logService.info('[DeviceService] End write user configuration to eeprom');
|
||||
}
|
||||
|
||||
private async waitUntilKeyboardBusy(): Promise<void> {
|
||||
|
||||
@@ -6,6 +6,17 @@ import { Constants, LogService } from 'uhk-common';
|
||||
* HID API wrapper to support unified logging and async write
|
||||
*/
|
||||
export class UhkHidDeviceService {
|
||||
/**
|
||||
* Convert the Buffer to number[]
|
||||
* @param {Buffer} buffer
|
||||
* @returns {number[]}
|
||||
* @private
|
||||
* @static
|
||||
*/
|
||||
public static convertBufferToIntArray(buffer: Buffer): number[] {
|
||||
return Array.prototype.slice.call(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the communication package that will send over USB and
|
||||
* - add usb report code as 1st byte
|
||||
@@ -32,17 +43,6 @@ export class UhkHidDeviceService {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Buffer to number[]
|
||||
* @param {Buffer} buffer
|
||||
* @returns {number[]}
|
||||
* @private
|
||||
* @static
|
||||
*/
|
||||
private static convertBufferToIntArray(buffer: Buffer): number[] {
|
||||
return Array.prototype.slice.call(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert buffer to space separated hexadecimal string
|
||||
* @param {Buffer} buffer
|
||||
@@ -109,7 +109,7 @@ export class UhkHidDeviceService {
|
||||
return reject(err);
|
||||
}
|
||||
const logString = UhkHidDeviceService.bufferToString(receivedData);
|
||||
this.logService.debug('[UhkHidDevice] Transfer UHK ===> Agent: ', logString);
|
||||
this.logService.debug('[UhkHidDevice] USB[R]:', logString);
|
||||
|
||||
if (receivedData[0] !== 0) {
|
||||
return reject(new Error(`Communications error with UHK. Response code: ${receivedData[0]}`));
|
||||
@@ -119,7 +119,7 @@ export class UhkHidDeviceService {
|
||||
});
|
||||
|
||||
const sendData = UhkHidDeviceService.getTransferData(buffer);
|
||||
this.logService.debug('[UhkHidDevice] Transfer Agent ===> UHK: ', UhkHidDeviceService.bufferToString(sendData));
|
||||
this.logService.debug('[UhkHidDevice] USB[W]:', UhkHidDeviceService.bufferToString(sendData));
|
||||
device.write(sendData);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user