diff --git a/packages/uhk-agent/src/services/device.service.ts b/packages/uhk-agent/src/services/device.service.ts index 5c9d8bb3..9c7cbd4e 100644 --- a/packages/uhk-agent/src/services/device.service.ts +++ b/packages/uhk-agent/src/services/device.service.ts @@ -1,16 +1,6 @@ import { ipcMain } from 'electron'; import { ConfigurationReply, IpcEvents, IpcResponse, LogService } from 'uhk-common'; -import { - Constants, - convertBufferToIntArray, - EepromTransfer, - getTransferBuffers, - snooze, - SystemPropertyIds, - UhkHidDevice, - UhkOperations, - UsbCommand -} from 'uhk-usb'; +import { Constants, snooze, UhkHidDevice, UhkOperations } from 'uhk-usb'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; import { Device, devices } from 'node-hid'; @@ -93,20 +83,11 @@ export class DeviceService { try { await this.device.waitUntilKeyboardBusy(); - const userConfiguration = await this.loadConfiguration( - SystemPropertyIds.MaxUserConfigSize, - UsbCommand.ReadUserConfig, - 'user configuration'); - - const hardwareConfiguration = await this.loadConfiguration( - SystemPropertyIds.HardwareConfigSize, - UsbCommand.ReadHardwareConfig, - 'hardware configuration'); + const result = await this.operations.loadConfigurations(); response = { success: true, - userConfiguration, - hardwareConfiguration + ...result }; event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response)); } catch (error) { @@ -121,51 +102,6 @@ export class DeviceService { event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response)); } - /** - * Return with the actual user / hardware fonfiguration from UHK Device - * @returns {Promise} - */ - public async loadConfiguration(property: SystemPropertyIds, config: UsbCommand, configName: string): Promise { - let response = []; - - try { - this.logService.debug(`[DeviceService] USB[T]: Read ${configName} size from keyboard`); - let configSize = await this.getConfigSizeFromKeyboard(property); - const originalConfigSize = configSize; - this.logService.debug(`[DeviceService] getConfigSize() configSize: ${configSize}`); - const chunkSize = 63; - let offset = 0; - let configBuffer = new Buffer(0); - let firstRead = true; - - this.logService.debug(`[DeviceService] USB[T]: Read ${configName} from keyboard`); - while (offset < configSize) { - const chunkSizeToRead = Math.min(chunkSize, configSize - offset); - const writeBuffer = Buffer.from([config, 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; - - if (firstRead && config === UsbCommand.ReadUserConfig) { - firstRead = false; - configSize = readBuffer[7] + (readBuffer[8] << 8); - this.logService.debug(`[DeviceService] userConfigSize: ${configSize}`); - if (originalConfigSize < configSize) { - this.logService.debug(`[DeviceService] userConfigSize should never be larger than getConfigSize()! ` + - `Overriding configSize with getConfigSize()`); - configSize = originalConfigSize; - } - } - } - response = convertBufferToIntArray(configBuffer); - return Promise.resolve(JSON.stringify(response)); - } catch (error) { - const errMsg = `[DeviceService] ${configName} from eeprom error`; - this.logService.error(errMsg, error); - throw new Error(errMsg); - } - } - public close(): void { this.connected = false; this.stopPollTimer(); @@ -231,27 +167,12 @@ export class DeviceService { .subscribe(); } - /** - * Return the user / hardware configuration size from the UHK Device - * @returns {Promise} - */ - private async getConfigSizeFromKeyboard(property: SystemPropertyIds): Promise { - const buffer = await this.device.write(new Buffer([UsbCommand.GetProperty, property])); - this.device.close(); - const configSize = buffer[1] + (buffer[2] << 8); - this.logService.debug('[DeviceService] User config size:', configSize); - return configSize; - } - private async saveUserConfiguration(event: Electron.Event, args: Array): Promise { const response = new IpcResponse(); const json = args[0]; try { - 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.device.writeConfigToEeprom(EepromTransfer.WriteUserConfig); + await this.operations.saveUserConfiguration(json); response.success = true; } @@ -267,23 +188,6 @@ export class DeviceService { return Promise.resolve(); } - /** - * IpcMain handler. Send the UserConfiguration to the UHK Device and send a response with the result. - * @param {string} json - UserConfiguration in JSON format - * @returns {Promise} - * @private - */ - private async sendUserConfigToKeyboard(json: string): Promise { - const buffer: Buffer = new Buffer(JSON.parse(json).data); - const fragments = getTransferBuffers(UsbCommand.UploadUserConfig, buffer); - 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([UsbCommand.ApplyConfig]); - await this.device.write(applyBuffer); - } - private stopPollTimer(): void { if (!this.pollTimer$) { return; diff --git a/packages/uhk-usb/src/models/load-configurations-result.ts b/packages/uhk-usb/src/models/load-configurations-result.ts new file mode 100644 index 00000000..5dd999fa --- /dev/null +++ b/packages/uhk-usb/src/models/load-configurations-result.ts @@ -0,0 +1,4 @@ +export interface LoadConfigurationsResult { + userConfiguration: string; + hardwareConfiguration: string; +} diff --git a/packages/uhk-usb/src/uhk-operations.ts b/packages/uhk-usb/src/uhk-operations.ts index dbcdab5b..e2b23525 100644 --- a/packages/uhk-usb/src/uhk-operations.ts +++ b/packages/uhk-usb/src/uhk-operations.ts @@ -5,6 +5,8 @@ import * as fs from 'fs'; import { UhkBlhost } from './uhk-blhost'; import { UhkHidDevice } from './uhk-hid-device'; import { snooze } from './util'; +import { convertBufferToIntArray, EepromTransfer, getTransferBuffers, SystemPropertyIds, UsbCommand } from '../index'; +import { LoadConfigurationsResult } from './models/load-configurations-result'; export class UhkOperations { constructor(private logService: LogService, @@ -58,6 +60,121 @@ export class UhkOperations { this.logService.debug('[UhkOperations] End flashing left module firmware'); } + /** + * Return with the actual UserConfiguration from UHK Device + * @returns {Promise} + */ + public async loadConfigurations(): Promise { + try { + await this.device.waitUntilKeyboardBusy(); + const userConfiguration = await this.loadConfiguration( + SystemPropertyIds.MaxUserConfigSize, + UsbCommand.ReadUserConfig, + 'user configuration'); + + const hardwareConfiguration = await this.loadConfiguration( + SystemPropertyIds.HardwareConfigSize, + UsbCommand.ReadHardwareConfig, + 'hardware configuration'); + + return { + userConfiguration, + hardwareConfiguration + }; + } finally { + this.device.close(); + } + } + + /** + * Return with the actual user / hardware fonfiguration from UHK Device + * @returns {Promise} + */ + public async loadConfiguration(property: SystemPropertyIds, config: UsbCommand, configName: string): Promise { + let response = []; + + try { + this.logService.debug(`[DeviceOperation] USB[T]: Read ${configName} size from keyboard`); + let configSize = await this.getConfigSizeFromKeyboard(property); + const originalConfigSize = configSize; + this.logService.debug(`[DeviceOperation] getConfigSize() configSize: ${configSize}`); + const chunkSize = 63; + let offset = 0; + let configBuffer = new Buffer(0); + let firstRead = true; + + this.logService.debug(`[DeviceOperation] USB[T]: Read ${configName} from keyboard`); + while (offset < configSize) { + const chunkSizeToRead = Math.min(chunkSize, configSize - offset); + const writeBuffer = Buffer.from([config, 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; + + if (firstRead && config === UsbCommand.ReadUserConfig) { + firstRead = false; + configSize = readBuffer[7] + (readBuffer[8] << 8); + this.logService.debug(`[DeviceOperation] userConfigSize: ${configSize}`); + if (originalConfigSize < configSize) { + this.logService.debug(`[DeviceOperation] userConfigSize should never be larger than getConfigSize()! ` + + `Overriding configSize with getConfigSize()`); + configSize = originalConfigSize; + } + } + } + response = convertBufferToIntArray(configBuffer); + return Promise.resolve(JSON.stringify(response)); + } catch (error) { + const errMsg = `[DeviceOperation] ${configName} from eeprom error`; + this.logService.error(errMsg, error); + throw new Error(errMsg); + } + } + + /** + * Return the user / hardware configuration size from the UHK Device + * @returns {Promise} + */ + public async getConfigSizeFromKeyboard(property: SystemPropertyIds): Promise { + const buffer = await this.device.write(new Buffer([UsbCommand.GetProperty, property])); + this.device.close(); + const configSize = buffer[1] + (buffer[2] << 8); + this.logService.debug('[DeviceOperation] User config size:', configSize); + return configSize; + } + + public async saveUserConfiguration(json: string): Promise { + try { + this.logService.debug('[DeviceOperation] USB[T]: Write user configuration to keyboard'); + await this.sendUserConfigToKeyboard(json); + this.logService.debug('[DeviceOperation] USB[T]: Write user configuration to EEPROM'); + await this.device.writeConfigToEeprom(EepromTransfer.WriteUserConfig); + } + catch (error) { + this.logService.error('[DeviceOperation] Transferring error', error); + throw error; + } finally { + this.device.close(); + } + } + + /** + * IpcMain handler. Send the UserConfiguration to the UHK Device and send a response with the result. + * @param {string} json - UserConfiguration in JSON format + * @returns {Promise} + * @private + */ + private async sendUserConfigToKeyboard(json: string): Promise { + const buffer: Buffer = new Buffer(JSON.parse(json).data); + const fragments = getTransferBuffers(UsbCommand.UploadUserConfig, buffer); + for (const fragment of fragments) { + await this.device.write(fragment); + } + this.logService.debug('[DeviceOperation] USB[T]: Apply user configuration to keyboard'); + const applyBuffer = new Buffer([UsbCommand.ApplyConfig]); + await this.device.write(applyBuffer); + } + private getFirmwarePath(): string { const firmware = path.join(this.rootDir, 'packages/firmware/devices/uhk60-right/firmware.hex'); diff --git a/packages/usb/write-userconfig.ts b/packages/usb/write-userconfig.ts new file mode 100755 index 00000000..6f186f97 --- /dev/null +++ b/packages/usb/write-userconfig.ts @@ -0,0 +1,31 @@ +#!/usr/bin/env ts-node +/// + +import { UhkBlhost, UhkHidDevice, UhkOperations } from 'uhk-usb'; +import { LogService } from 'uhk-common'; +import * as fs from 'fs'; + +if (process.argv.length < 3) { + console.log(`use: write-userconfig `); + process.exit(1); +} + +const fileContent = fs.readFileSync(process.argv[2]); +const json = JSON.stringify(fileContent); +const logger = new LogService(); +const uhkDevice = new UhkHidDevice(logger); +const uhkBlHost = new UhkBlhost(logger, '.'); +const uhkOperations = new UhkOperations(logger, uhkBlHost, uhkDevice, '.'); + +const init = async (): Promise => { + await uhkOperations.saveUserConfiguration(json); +}; + +init() + .then(() => { + console.log('Success'); + }) + .catch(error => { + console.log(error); + process.exit(-1); + });