From 653465f0e0512a017fcb74ffc028c9a842fdc101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kiss?= Date: Sat, 19 May 2018 17:22:46 +0200 Subject: [PATCH] feat: device recovery mode (#642) * add new page and ipc processing * refactor: remove unused references from uhk.js * feat: add device recovery route * refactor: device permission * feat: write firmware update log to the screen * fix: xterm height * feat: add reload button to the recovery page * refactor: deviceConnectionState.hasPermission in appStartInfo * refactor: use correct imports * refactor: move .ok-button css class to the main style.scss * feat: add bootload active route guard * style: move RecoveryDeviceAction into new line * feat: delete reload button * feat: start device polling after device recovery --- package-lock.json | 3 +- .../uhk-agent/src/services/app.service.ts | 7 ++- .../uhk-agent/src/services/device.service.ts | 49 ++++++++++++---- .../uhk-common/src/models/app-start-info.ts | 1 + .../src/models/device-connection-state.ts | 1 + packages/uhk-common/src/util/ipcEvents.ts | 1 + packages/uhk-usb/src/constants.ts | 1 + packages/uhk-usb/src/uhk-hid-device.ts | 32 +++++++---- packages/uhk-usb/src/util.ts | 8 ++- packages/uhk-web/src/app/app.routes.ts | 13 ++++- .../app/components/device/device.routes.ts | 5 ++ .../firmware/device-firmware.component.html | 2 +- .../firmware/device-firmware.component.scss | 22 -------- .../src/app/components/device/index.ts | 1 + .../recovery-mode.component.html | 26 +++++++++ .../recovery-mode.component.scss | 10 ++++ .../recovery-mode/recovery-mode.component.ts | 56 +++++++++++++++++++ .../app/services/device-renderer.service.ts | 4 ++ .../uhk-device-bootloader-not-active.guard.ts | 24 ++++++++ packages/uhk-web/src/app/shared.module.ts | 10 +++- .../uhk-web/src/app/store/actions/device.ts | 8 ++- packages/uhk-web/src/app/store/effects/app.ts | 3 +- .../uhk-web/src/app/store/effects/device.ts | 11 +++- packages/uhk-web/src/app/store/index.ts | 1 + .../uhk-web/src/app/store/reducers/device.ts | 13 ++++- packages/uhk-web/src/styles.scss | 22 ++++++++ packages/usb/uhk.js | 4 +- 27 files changed, 274 insertions(+), 64 deletions(-) create mode 100644 packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.html create mode 100644 packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.scss create mode 100644 packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.ts create mode 100644 packages/uhk-web/src/app/services/uhk-device-bootloader-not-active.guard.ts diff --git a/package-lock.json b/package-lock.json index f4cdfce3..e5df44a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5838,7 +5838,8 @@ "jsbn": { "version": "0.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "json-schema": { "version": "0.2.3", diff --git a/packages/uhk-agent/src/services/app.service.ts b/packages/uhk-agent/src/services/app.service.ts index c21ebb44..850df131 100644 --- a/packages/uhk-agent/src/services/app.service.ts +++ b/packages/uhk-agent/src/services/app.service.ts @@ -22,13 +22,14 @@ export class AppService extends MainServiceBase { private async handleAppStartInfo(event: Electron.Event) { this.logService.info('[AppService] getAppStartInfo'); - + const deviceConnectionState = this.uhkHidDeviceService.getDeviceConnectionState(); const response: AppStartInfo = { commandLineArgs: { addons: this.options.addons || false }, - deviceConnected: this.uhkHidDeviceService.deviceConnected(), - hasPermission: this.uhkHidDeviceService.hasPermission() + deviceConnected: deviceConnectionState.connected, + hasPermission: deviceConnectionState.hasPermission, + bootloaderActive: deviceConnectionState.bootloaderActive }; this.logService.info('[AppService] getAppStartInfo response:', response); return event.sender.send(IpcEvents.app.getAppStartInfoReply, response); diff --git a/packages/uhk-agent/src/services/device.service.ts b/packages/uhk-agent/src/services/device.service.ts index 2315e981..a3d3b026 100644 --- a/packages/uhk-agent/src/services/device.service.ts +++ b/packages/uhk-agent/src/services/device.service.ts @@ -10,7 +10,7 @@ import { mapObjectToUserConfigBinaryBuffer, SaveUserConfigurationData } from 'uhk-common'; -import { snooze, UhkHidDevice, UhkOperations } from 'uhk-usb'; +import { deviceConnectionStateComparer, snooze, UhkHidDevice, UhkOperations } from 'uhk-usb'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; import { emptyDir } from 'fs-extra'; @@ -71,6 +71,15 @@ export class DeviceService { ipcMain.on(IpcEvents.device.startConnectionPoller, this.pollUhkDevice.bind(this)); + ipcMain.on(IpcEvents.device.recoveryDevice, (...args: any[]) => { + this.queueManager.add({ + method: this.recoveryDevice, + bind: this, + params: args, + asynchronous: true + }); + }); + logService.debug('[DeviceService] init success'); } @@ -148,6 +157,29 @@ export class DeviceService { event.sender.send(IpcEvents.device.updateFirmwareReply, response); } + public async recoveryDevice(event: Electron.Event): Promise { + const response = new IpcResponse(); + try { + this.stopPollTimer(); + + await this.operations.updateRightFirmware(); + + await snooze(500); + + this.pollUhkDevice(); + + response.success = true; + } catch (error) { + const err = {message: error.message, stack: error.stack}; + this.logService.error('[DeviceService] updateFirmware error', err); + + response.error = err; + } + + await snooze(500); + event.sender.send(IpcEvents.device.updateFirmwareReply, response); + } + /** * HID API not support device attached and detached event. * This method check the keyboard is attached to the computer or not. @@ -161,16 +193,11 @@ export class DeviceService { this.pollTimer$ = Observable.interval(1000) .startWith(0) - .map(() => this.device.deviceConnected()) - .distinctUntilChanged() - .do((connected: boolean) => { - const response: DeviceConnectionState = { - connected, - hasPermission: this.device.hasPermission() - }; - - this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, response); - this.logService.info('[DeviceService] Device connection state changed to:', response); + .map(() => this.device.getDeviceConnectionState()) + .distinctUntilChanged(deviceConnectionStateComparer) + .do((state: DeviceConnectionState) => { + this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, state); + this.logService.info('[DeviceService] Device connection state changed to:', state); }) .subscribe(); } diff --git a/packages/uhk-common/src/models/app-start-info.ts b/packages/uhk-common/src/models/app-start-info.ts index 25d92d11..1c72c088 100644 --- a/packages/uhk-common/src/models/app-start-info.ts +++ b/packages/uhk-common/src/models/app-start-info.ts @@ -4,4 +4,5 @@ export interface AppStartInfo { commandLineArgs: CommandLineArgs; deviceConnected: boolean; hasPermission: boolean; + bootloaderActive: boolean; } diff --git a/packages/uhk-common/src/models/device-connection-state.ts b/packages/uhk-common/src/models/device-connection-state.ts index 538b48cd..0d688bc0 100644 --- a/packages/uhk-common/src/models/device-connection-state.ts +++ b/packages/uhk-common/src/models/device-connection-state.ts @@ -1,4 +1,5 @@ export interface DeviceConnectionState { connected: boolean; hasPermission: boolean; + bootloaderActive: boolean; } diff --git a/packages/uhk-common/src/util/ipcEvents.ts b/packages/uhk-common/src/util/ipcEvents.ts index a4d242f0..e62cc92d 100644 --- a/packages/uhk-common/src/util/ipcEvents.ts +++ b/packages/uhk-common/src/util/ipcEvents.ts @@ -29,6 +29,7 @@ export class Device { public static readonly updateFirmware = 'device-update-firmware'; public static readonly updateFirmwareReply = 'device-update-firmware-reply'; public static readonly startConnectionPoller = 'device-start-connection-poller'; + public static readonly recoveryDevice = 'device-recovery'; } export class IpcEvents { diff --git a/packages/uhk-usb/src/constants.ts b/packages/uhk-usb/src/constants.ts index 71f2a235..a09c0a35 100644 --- a/packages/uhk-usb/src/constants.ts +++ b/packages/uhk-usb/src/constants.ts @@ -1,6 +1,7 @@ export namespace Constants { export const VENDOR_ID = 0x1D50; export const PRODUCT_ID = 0x6122; + export const BOOTLOADER_ID = 0x6120; export const MAX_PAYLOAD_SIZE = 64; } diff --git a/packages/uhk-usb/src/uhk-hid-device.ts b/packages/uhk-usb/src/uhk-hid-device.ts index b9191f48..40e4058a 100644 --- a/packages/uhk-usb/src/uhk-hid-device.ts +++ b/packages/uhk-usb/src/uhk-hid-device.ts @@ -1,6 +1,6 @@ import { cloneDeep, isEqual } from 'lodash'; import { Device, devices, HID } from 'node-hid'; -import { CommandLineArgs, LogService } from 'uhk-common'; +import { CommandLineArgs, DeviceConnectionState, LogService } from 'uhk-common'; import { ConfigBufferId, @@ -50,12 +50,10 @@ export class UhkHidDevice { return true; } - if (!this.deviceConnected()) { - return true; - } + const devs = devices(); - this._hasPermission = this.getDevice() !== null; - this.close(); + this._hasPermission = devs.some((x: Device) => x.vendorId === Constants.VENDOR_ID && + (x.productId === Constants.PRODUCT_ID || x.productId === Constants.BOOTLOADER_ID)); return this._hasPermission; } catch (err) { @@ -69,15 +67,25 @@ export class UhkHidDevice { * Return with true is an UHK Device is connected to the computer. * @returns {boolean} */ - public deviceConnected(): boolean { - const connected = devices().some((dev: Device) => dev.vendorId === Constants.VENDOR_ID && - dev.productId === Constants.PRODUCT_ID); + public getDeviceConnectionState(): DeviceConnectionState { + const devs = devices(); + const result: DeviceConnectionState = { + bootloaderActive: false, + connected: false, + hasPermission: this.hasPermission() + }; - if (!connected) { - this._hasPermission = false; + for (const dev of devs) { + if (dev.vendorId === Constants.VENDOR_ID && + dev.productId === Constants.PRODUCT_ID) { + result.connected = true; + } else if (dev.vendorId === Constants.VENDOR_ID && + dev.productId === Constants.BOOTLOADER_ID) { + result.bootloaderActive = true; + } } - return connected; + return result; } /** diff --git a/packages/uhk-usb/src/util.ts b/packages/uhk-usb/src/util.ts index a897d4c8..c4976cd5 100644 --- a/packages/uhk-usb/src/util.ts +++ b/packages/uhk-usb/src/util.ts @@ -1,5 +1,5 @@ import { Constants, UsbCommand } from './constants'; -import { LogService } from 'uhk-common'; +import { DeviceConnectionState, LogService } from 'uhk-common'; export const snooze = ms => new Promise(resolve => setTimeout(resolve, ms)); @@ -95,3 +95,9 @@ export async function retry(command: Function, maxTry = 3, logService?: LogServi } } } + +export const deviceConnectionStateComparer = (a: DeviceConnectionState, b: DeviceConnectionState): boolean => { + return a.hasPermission === b.hasPermission + && a.connected === b.connected + && a.bootloaderActive === b.bootloaderActive; +}; diff --git a/packages/uhk-web/src/app/app.routes.ts b/packages/uhk-web/src/app/app.routes.ts index 1f6ffc62..b1c48538 100644 --- a/packages/uhk-web/src/app/app.routes.ts +++ b/packages/uhk-web/src/app/app.routes.ts @@ -5,17 +5,19 @@ import { deviceRoutes } from './components/device'; import { addOnRoutes } from './components/add-on'; import { keymapRoutes } from './components/keymap'; import { macroRoutes } from './components/macro'; -import { PrivilegeCheckerComponent } from './components/privilege-checker/privilege-checker.component'; -import { MissingDeviceComponent } from './components/missing-device/missing-device.component'; +import { PrivilegeCheckerComponent } from './components/privilege-checker'; +import { MissingDeviceComponent } from './components/missing-device'; import { UhkDeviceDisconnectedGuard } from './services/uhk-device-disconnected.guard'; import { UhkDeviceConnectedGuard } from './services/uhk-device-connected.guard'; import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard'; import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard'; import { MainPage } from './pages/main-page/main.page'; -import { agentRoutes } from './components/agent/agent.routes'; +import { agentRoutes } from './components/agent'; import { LoadingDevicePageComponent } from './pages/loading-page/loading-device.page'; import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard'; import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard'; +import { RecoveryModeComponent } from './components/device'; +import { UhkDeviceBootloaderNotActiveGuard } from './services/uhk-device-bootloader-not-active.guard'; const appRoutes: Routes = [ { @@ -33,6 +35,11 @@ const appRoutes: Routes = [ component: LoadingDevicePageComponent, canActivate: [UhkDeviceLoadedGuard] }, + { + path: 'recovery-device', + component: RecoveryModeComponent, + canActivate: [UhkDeviceBootloaderNotActiveGuard] + }, { path: '', component: MainPage, diff --git a/packages/uhk-web/src/app/components/device/device.routes.ts b/packages/uhk-web/src/app/components/device/device.routes.ts index 52c6f267..7547de4f 100644 --- a/packages/uhk-web/src/app/components/device/device.routes.ts +++ b/packages/uhk-web/src/app/components/device/device.routes.ts @@ -5,6 +5,7 @@ import { DeviceFirmwareComponent } from './firmware/device-firmware.component'; import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component'; import { LEDBrightnessComponent } from './led-brightness/led-brightness.component'; import { RestoreConfigurationComponent } from './restore-configuration/restore-configuration.component'; +import { RecoveryModeComponent } from './recovery-mode/recovery-mode.component'; export const deviceRoutes: Routes = [ { @@ -34,6 +35,10 @@ export const deviceRoutes: Routes = [ { path: 'restore-user-configuration', component: RestoreConfigurationComponent + }, + { + path: 'recovery-mode', + component: RecoveryModeComponent } ] } diff --git a/packages/uhk-web/src/app/components/device/firmware/device-firmware.component.html b/packages/uhk-web/src/app/components/device/firmware/device-firmware.component.html index c4aa951f..65e84ad4 100644 --- a/packages/uhk-web/src/app/components/device/firmware/device-firmware.component.html +++ b/packages/uhk-web/src/app/components/device/firmware/device-firmware.component.html @@ -42,7 +42,7 @@
- + diff --git a/packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.scss b/packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.scss new file mode 100644 index 00000000..91dde750 --- /dev/null +++ b/packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.scss @@ -0,0 +1,10 @@ +:host { + overflow-y: auto; + display: block; + height: 100%; + width: 100%; + + p { + margin: 1.5rem 0; + } +} diff --git a/packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.ts b/packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.ts new file mode 100644 index 00000000..3ca347c6 --- /dev/null +++ b/packages/uhk-web/src/app/components/device/recovery-mode/recovery-mode.component.ts @@ -0,0 +1,56 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Subscription } from 'rxjs/Subscription'; +import { Observable } from 'rxjs/Observable'; + +import { XtermLog } from '../../../models/xterm-log'; +import { AppState, flashFirmwareButtonDisbabled, xtermLog } from '../../../store'; +import { RecoveryDeviceAction } from '../../../store/actions/device'; + +@Component({ + selector: 'device-recovery-mode', + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: './recovery-mode.component.html', + styleUrls: ['./recovery-mode.component.scss'], + host: { + 'class': 'container-fluid' + } +}) +export class RecoveryModeComponent implements OnInit, OnDestroy { + xtermLogSubscription: Subscription; + flashFirmwareButtonDisbabled$: Observable; + + xtermLog: Array; + + @ViewChild('scrollMe') divElement: ElementRef; + + constructor(private store: Store, + private cdRef: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.flashFirmwareButtonDisbabled$ = this.store.select(flashFirmwareButtonDisbabled); + this.xtermLogSubscription = this.store.select(xtermLog) + .subscribe(data => { + this.xtermLog = data; + + this.cdRef.markForCheck(); + + if (this.divElement && this.divElement.nativeElement) { + setTimeout(() => { + this.divElement.nativeElement.scrollTop = this.divElement.nativeElement.scrollHeight; + }); + } + }); + } + + ngOnDestroy(): void { + if (this.xtermLogSubscription) { + this.xtermLogSubscription.unsubscribe(); + } + } + + onRecoveryDevice(): void { + this.store.dispatch(new RecoveryDeviceAction()); + } +} diff --git a/packages/uhk-web/src/app/services/device-renderer.service.ts b/packages/uhk-web/src/app/services/device-renderer.service.ts index d02389c7..7c191c44 100644 --- a/packages/uhk-web/src/app/services/device-renderer.service.ts +++ b/packages/uhk-web/src/app/services/device-renderer.service.ts @@ -46,6 +46,10 @@ export class DeviceRendererService { this.ipcRenderer.send(IpcEvents.device.startConnectionPoller); } + recoveryDevice(): void { + this.ipcRenderer.send(IpcEvents.device.recoveryDevice); + } + private registerEvents(): void { this.ipcRenderer.on(IpcEvents.device.deviceConnectionStateChanged, (event: string, arg: DeviceConnectionState) => { this.dispachStoreAction(new ConnectionStateChangedAction(arg)); diff --git a/packages/uhk-web/src/app/services/uhk-device-bootloader-not-active.guard.ts b/packages/uhk-web/src/app/services/uhk-device-bootloader-not-active.guard.ts new file mode 100644 index 00000000..b7628f91 --- /dev/null +++ b/packages/uhk-web/src/app/services/uhk-device-bootloader-not-active.guard.ts @@ -0,0 +1,24 @@ +import { CanActivate, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/map'; + +import { AppState, bootloaderActive } from '../store'; + +@Injectable() +export class UhkDeviceBootloaderNotActiveGuard implements CanActivate { + + constructor(private store: Store, private router: Router) { } + + canActivate(): Observable { + return this.store.select(bootloaderActive) + .do(active => { + if (!active) { + this.router.navigate(['/']); + } + }); + } +} diff --git a/packages/uhk-web/src/app/shared.module.ts b/packages/uhk-web/src/app/shared.module.ts index 8ec9ff0c..88b9a716 100644 --- a/packages/uhk-web/src/app/shared.module.ts +++ b/packages/uhk-web/src/app/shared.module.ts @@ -17,7 +17,8 @@ import { DeviceFirmwareComponent, MouseSpeedComponent, LEDBrightnessComponent, - RestoreConfigurationComponent + RestoreConfigurationComponent, + RecoveryModeComponent } from './components/device'; import { KeymapAddComponent, KeymapEditComponent, KeymapHeaderComponent } from './components/keymap'; import { LayersComponent } from './components/layers'; @@ -105,6 +106,7 @@ import { XtermComponent } from './components/xterm/xterm.component'; import { SliderWrapperComponent } from './components/slider-wrapper/slider-wrapper.component'; import { EditableTextComponent } from './components/editable-text/editable-text.component'; import { Autofocus } from './directives/autofocus/autofocus.directive'; +import { UhkDeviceBootloaderNotActiveGuard } from './services/uhk-device-bootloader-not-active.guard'; @NgModule({ declarations: [ @@ -176,7 +178,8 @@ import { Autofocus } from './directives/autofocus/autofocus.directive'; SliderWrapperComponent, EditableTextComponent, Autofocus, - RestoreConfigurationComponent + RestoreConfigurationComponent, + RecoveryModeComponent ], imports: [ CommonModule, @@ -211,7 +214,8 @@ import { Autofocus } from './directives/autofocus/autofocus.directive'; UhkDeviceInitializedGuard, UhkDeviceUninitializedGuard, UhkDeviceLoadingGuard, - UhkDeviceLoadedGuard + UhkDeviceLoadedGuard, + UhkDeviceBootloaderNotActiveGuard ], exports: [ UhkMessageComponent, diff --git a/packages/uhk-web/src/app/store/actions/device.ts b/packages/uhk-web/src/app/store/actions/device.ts index 1512c0ee..445a7b18 100644 --- a/packages/uhk-web/src/app/store/actions/device.ts +++ b/packages/uhk-web/src/app/store/actions/device.ts @@ -26,7 +26,8 @@ export const ActionTypes = { MODULES_INFO_LOADED: type(PREFIX + 'module info loaded'), HAS_BACKUP_USER_CONFIGURATION: type(PREFIX + 'Store backup user configuration'), RESTORE_CONFIGURATION_FROM_BACKUP: type(PREFIX + 'Restore configuration from backup'), - RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS: type(PREFIX + 'Restore configuration from backup success') + RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS: type(PREFIX + 'Restore configuration from backup success'), + RECOVERY_DEVICE: type(PREFIX + 'Recovery device') }; export class SetPrivilegeOnLinuxAction implements Action { @@ -140,6 +141,10 @@ export class RestoreUserConfigurationFromBackupSuccessAction implements Action { type = ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS; } +export class RecoveryDeviceAction implements Action { + type = ActionTypes.RECOVERY_DEVICE; +} + export type Actions = SetPrivilegeOnLinuxAction | SetPrivilegeOnLinuxReplyAction @@ -162,4 +167,5 @@ export type Actions | RestoreUserConfigurationFromBackupAction | HasBackupUserConfigurationAction | RestoreUserConfigurationFromBackupSuccessAction + | RecoveryDeviceAction ; diff --git a/packages/uhk-web/src/app/store/effects/app.ts b/packages/uhk-web/src/app/store/effects/app.ts index 9a25b54c..0a2960c3 100644 --- a/packages/uhk-web/src/app/store/effects/app.ts +++ b/packages/uhk-web/src/app/store/effects/app.ts @@ -68,7 +68,8 @@ export class ApplicationEffects { new ApplyCommandLineArgsAction(appInfo.commandLineArgs), new ConnectionStateChangedAction({ connected: appInfo.deviceConnected, - hasPermission: appInfo.hasPermission + hasPermission: appInfo.hasPermission, + bootloaderActive: appInfo.bootloaderActive }) ]; }); diff --git a/packages/uhk-web/src/app/store/effects/device.ts b/packages/uhk-web/src/app/store/effects/device.ts index e2c55c9e..35a0bd02 100644 --- a/packages/uhk-web/src/app/store/effects/device.ts +++ b/packages/uhk-web/src/app/store/effects/device.ts @@ -24,6 +24,7 @@ import { ActionTypes, ConnectionStateChangedAction, HideSaveToKeyboardButton, + RecoveryDeviceAction, ResetUserConfigurationAction, RestoreUserConfigurationFromBackupSuccessAction, SaveConfigurationAction, @@ -60,6 +61,9 @@ export class DeviceEffects { if (!state.hasPermission) { this.router.navigate(['/privilege']); } + else if (state.bootloaderActive) { + this.router.navigate(['/recovery-device']); + } else if (state.connected) { this.router.navigate(['/']); } @@ -90,7 +94,8 @@ export class DeviceEffects { if (response.success) { return new ConnectionStateChangedAction({ connected: true, - hasPermission: true + hasPermission: true, + bootloaderActive: false }); } @@ -214,6 +219,10 @@ export class DeviceEffects { .ofType(ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP) .map(() => new SaveConfigurationAction()); + @Effect({dispatch: false}) recoveryDevice$ = this.actions$ + .ofType(ActionTypes.RECOVERY_DEVICE) + .do(() => this.deviceRendererService.recoveryDevice()); + constructor(private actions$: Actions, private router: Router, private deviceRendererService: DeviceRendererService, diff --git a/packages/uhk-web/src/app/store/index.ts b/packages/uhk-web/src/app/store/index.ts index 62c31eca..a90a4beb 100644 --- a/packages/uhk-web/src/app/store/index.ts +++ b/packages/uhk-web/src/app/store/index.ts @@ -79,6 +79,7 @@ export const flashFirmwareButtonDisbabled = createSelector(runningInElectron, de export const getHardwareModules = createSelector(deviceState, fromDevice.getHardwareModules); export const getBackupUserConfigurationState = createSelector(deviceState, fromDevice.getBackupUserConfigurationState); export const getRestoreUserConfiguration = createSelector(deviceState, fromDevice.getHasBackupUserConfiguration); +export const bootloaderActive = createSelector(deviceState, fromDevice.bootloaderActive); export const getSideMenuPageState = createSelector( showAddonMenu, diff --git a/packages/uhk-web/src/app/store/reducers/device.ts b/packages/uhk-web/src/app/store/reducers/device.ts index 497135da..98aa25aa 100644 --- a/packages/uhk-web/src/app/store/reducers/device.ts +++ b/packages/uhk-web/src/app/store/reducers/device.ts @@ -17,6 +17,7 @@ import { RestoreConfigurationState } from '../../models/restore-configuration-st export interface State { connected: boolean; hasPermission: boolean; + bootloaderActive: boolean; saveToKeyboard: ProgressButtonState; updatingFirmware: boolean; firmwareUpdateFinished: boolean; @@ -29,6 +30,7 @@ export interface State { export const initialState: State = { connected: true, hasPermission: true, + bootloaderActive: false, saveToKeyboard: initProgressButtonState, updatingFirmware: false, firmwareUpdateFinished: false, @@ -53,7 +55,8 @@ export function reducer(state = initialState, action: Action) { return { ...state, connected: data.connected, - hasPermission: data.hasPermission + hasPermission: data.hasPermission, + bootloaderActive: data.bootloaderActive }; } @@ -193,6 +196,13 @@ export function reducer(state = initialState, action: Action) { hasBackupUserConfiguration: false }; + case ActionTypes.RECOVERY_DEVICE: { + return { + ...state, + updatingFirmware: true, + log: [{message: '', cssClass: XtermCssClass.standard}] + }; + } default: return state; } @@ -212,3 +222,4 @@ export const getBackupUserConfigurationState = (state: State): RestoreConfigurat hasBackupUserConfiguration: state.hasBackupUserConfiguration }; }; +export const bootloaderActive = (state: State) => state.bootloaderActive; diff --git a/packages/uhk-web/src/styles.scss b/packages/uhk-web/src/styles.scss index f4836a8a..81bd8c3e 100644 --- a/packages/uhk-web/src/styles.scss +++ b/packages/uhk-web/src/styles.scss @@ -155,3 +155,25 @@ pre { } } } + +.flex-container { + height: 100%; + max-height: 100%; + display: flex; + flex-direction: column; +} + +.flex-grow { + background-color: black; + overflow: auto; + flex: 1; +} + +.flex-footer { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.ok-button { + min-width: 100px; +} diff --git a/packages/usb/uhk.js b/packages/usb/uhk.js index 227636dc..39455c03 100644 --- a/packages/usb/uhk.js +++ b/packages/usb/uhk.js @@ -1,7 +1,5 @@ -const util = require('util'); const HID = require('node-hid'); const {HardwareConfiguration, UhkBuffer} = require('uhk-common'); -const {getTransferBuffers, ConfigBufferId, UhkHidDevice, UsbCommand} = require('uhk-usb'); const Logger = require('./logger'); const debug = process.env.DEBUG; @@ -18,7 +16,7 @@ const kbootCommandIdToName = { const eepromOperationIdToName = { 0: 'read', 1: 'write', -} +}; function bufferToString(buffer) { let str = '';