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
@@ -9,6 +9,7 @@ import {
|
||||
SaveConfigurationReplyAction,
|
||||
SetPrivilegeOnLinuxReplyAction
|
||||
} from '../store/actions/device';
|
||||
import { LoadUserConfigFromDeviceReplyAction } from '../store/actions/user-config';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceRendererService {
|
||||
@@ -28,6 +29,10 @@ export class DeviceRendererService {
|
||||
this.ipcRenderer.send(IpcEvents.device.saveUserConfiguration, JSON.stringify(buffer));
|
||||
}
|
||||
|
||||
loadUserConfiguration(): void {
|
||||
this.ipcRenderer.send(IpcEvents.device.loadUserConfiguration);
|
||||
}
|
||||
|
||||
private registerEvents(): void {
|
||||
this.ipcRenderer.on(IpcEvents.device.deviceConnectionStateChanged, (event: string, arg: boolean) => {
|
||||
this.dispachStoreAction(new ConnectionStateChangedAction(arg));
|
||||
@@ -40,6 +45,10 @@ export class DeviceRendererService {
|
||||
this.ipcRenderer.on(IpcEvents.device.saveUserConfigurationReply, (event: string, response: IpcResponse) => {
|
||||
this.dispachStoreAction(new SaveConfigurationReplyAction(response));
|
||||
});
|
||||
|
||||
this.ipcRenderer.on(IpcEvents.device.loadUserConfigurationReply, (event: string, response: string) => {
|
||||
this.dispachStoreAction(new LoadUserConfigFromDeviceReplyAction(JSON.parse(response)));
|
||||
});
|
||||
}
|
||||
|
||||
private dispachStoreAction(action: Action): void {
|
||||
|
||||
@@ -8,6 +8,8 @@ const PREFIX = '[user-config] ';
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
LOAD_USER_CONFIG: type(PREFIX + 'Load User Config'),
|
||||
LOAD_USER_CONFIG_FROM_DEVICE: type(PREFIX + 'Load User Config from Device'),
|
||||
LOAD_USER_CONFIG_FROM_DEVICE_REPLY: type(PREFIX + 'Load User Config from Device reply'),
|
||||
LOAD_USER_CONFIG_SUCCESS: type(PREFIX + 'Load User Config Success'),
|
||||
SAVE_USER_CONFIG_SUCCESS: type(PREFIX + 'Save User Config Success')
|
||||
};
|
||||
@@ -16,6 +18,16 @@ export class LoadUserConfigAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG;
|
||||
}
|
||||
|
||||
export class LoadUserConfigFromDeviceAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE;
|
||||
}
|
||||
|
||||
export class LoadUserConfigFromDeviceReplyAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE_REPLY;
|
||||
|
||||
constructor(public payload: Array<number>) { }
|
||||
}
|
||||
|
||||
export class LoadUserConfigSuccessAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG_SUCCESS;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class ApplicationEffects {
|
||||
this.logService.info('Renderer appStart effect end');
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
@Effect({dispatch: false})
|
||||
showNotification$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.APP_SHOW_NOTIFICATION)
|
||||
.map(toPayload)
|
||||
|
||||
@@ -15,7 +15,8 @@ import 'rxjs/add/operator/withLatestFrom';
|
||||
import { NotificationType, IpcResponse } from 'uhk-common';
|
||||
import {
|
||||
ActionTypes,
|
||||
ConnectionStateChangedAction, HideSaveToKeyboardButton,
|
||||
ConnectionStateChangedAction,
|
||||
HideSaveToKeyboardButton,
|
||||
PermissionStateChangedAction,
|
||||
SaveToKeyboardSuccessAction,
|
||||
SaveToKeyboardSuccessFailed
|
||||
@@ -25,10 +26,11 @@ import { ShowNotificationAction } from '../actions/app';
|
||||
import { AppState } from '../index';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { UhkBuffer } from '../../config-serializer/uhk-buffer';
|
||||
import { LoadUserConfigFromDeviceAction } from '../actions/user-config';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceEffects {
|
||||
@Effect({dispatch: false})
|
||||
@Effect()
|
||||
deviceConnectionStateChange$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.CONNECTION_STATE_CHANGED)
|
||||
.map(toPayload)
|
||||
@@ -39,6 +41,13 @@ export class DeviceEffects {
|
||||
else {
|
||||
this.router.navigate(['/detection']);
|
||||
}
|
||||
})
|
||||
.switchMap((connected: boolean) => {
|
||||
if (connected) {
|
||||
return Observable.of(new LoadUserConfigFromDeviceAction());
|
||||
}
|
||||
|
||||
return Observable.empty();
|
||||
});
|
||||
|
||||
@Effect({dispatch: false})
|
||||
|
||||
@@ -11,7 +11,7 @@ import 'rxjs/add/operator/withLatestFrom';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { NotificationType } from 'uhk-common';
|
||||
import { LogService, NotificationType } from 'uhk-common';
|
||||
|
||||
import {
|
||||
ActionTypes,
|
||||
@@ -29,6 +29,8 @@ import { MacroActions } from '../actions/macro';
|
||||
import { UndoUserConfigData } from '../../models/undo-user-config-data';
|
||||
import { ShowNotificationAction, DismissUndoNotificationAction } from '../actions/app';
|
||||
import { ShowSaveToKeyboardButtonAction } from '../actions/device';
|
||||
import { DeviceRendererService } from '../../services/device-renderer.service';
|
||||
import { UhkBuffer } from '../../config-serializer/uhk-buffer';
|
||||
|
||||
@Injectable()
|
||||
export class UserConfigEffects {
|
||||
@@ -86,10 +88,46 @@ export class UserConfigEffects {
|
||||
return [new LoadUserConfigSuccessAction(config), go(payload.path)];
|
||||
});
|
||||
|
||||
@Effect({dispatch: false}) loadUserConfigFromDevice$ = this.actions$
|
||||
.ofType(ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE)
|
||||
.do(() => this.deviceRendererService.loadUserConfiguration());
|
||||
|
||||
@Effect() loadUserConfigFromDeviceReply$ = this.actions$
|
||||
.ofType(ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE_REPLY)
|
||||
.map(action => action.payload)
|
||||
.switchMap((data: Array<number>) => {
|
||||
try {
|
||||
let userConfig;
|
||||
if (data.length > 0) {
|
||||
const uhkBuffer = new UhkBuffer();
|
||||
let hasNonZeroValue = false;
|
||||
for (const num of data) {
|
||||
if (num > 0) {
|
||||
hasNonZeroValue = true;
|
||||
}
|
||||
uhkBuffer.writeUInt8(num);
|
||||
}
|
||||
uhkBuffer.offset = 0;
|
||||
userConfig = new UserConfiguration();
|
||||
userConfig.fromBinary(uhkBuffer);
|
||||
|
||||
if (hasNonZeroValue) {
|
||||
return Observable.of(new LoadUserConfigSuccessAction(userConfig));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
this.logService.error('Eeprom parse error:', err);
|
||||
}
|
||||
|
||||
return Observable.empty();
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
private dataStorageRepository: DataStorageRepositoryService,
|
||||
private store: Store<AppState>,
|
||||
private defaultUserConfigurationService: DefaultUserConfigurationService) {
|
||||
private defaultUserConfigurationService: DefaultUserConfigurationService,
|
||||
private deviceRendererService: DeviceRendererService,
|
||||
private logService: LogService) {
|
||||
}
|
||||
|
||||
private getUserConfiguration() {
|
||||
|
||||
@@ -13,13 +13,15 @@ export interface State {
|
||||
navigationCountAfterNotification: number;
|
||||
prevUserConfig?: UserConfiguration;
|
||||
runningInElectron: boolean;
|
||||
userConfigLoading: boolean;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
started: false,
|
||||
showAddonMenu: false,
|
||||
navigationCountAfterNotification: 0,
|
||||
runningInElectron: runInElectron()
|
||||
runningInElectron: runInElectron(),
|
||||
userConfigLoading: true
|
||||
};
|
||||
|
||||
export function reducer(state = initialState, action: Action) {
|
||||
@@ -76,7 +78,16 @@ export function reducer(state = initialState, action: Action) {
|
||||
case UserConfigActionTypes.SAVE_USER_CONFIG_SUCCESS: {
|
||||
return {
|
||||
...state,
|
||||
prevUserConfig: action.payload
|
||||
prevUserConfig: action.payload,
|
||||
userConfigLoading: false
|
||||
};
|
||||
}
|
||||
|
||||
case UserConfigActionTypes.LOAD_USER_CONFIG_FROM_DEVICE:
|
||||
case UserConfigActionTypes.LOAD_USER_CONFIG: {
|
||||
return {
|
||||
...state,
|
||||
userConfigLoading: true
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,27 @@ import * as util from 'util';
|
||||
|
||||
import { LogService } from 'uhk-common';
|
||||
|
||||
const transferRegExp = /USB\[T]:/;
|
||||
const writeRegExp = /USB\[W]:/;
|
||||
const readRegExp = /USB\[R]: 00/;
|
||||
const errorRegExp = /(?:(USB\[R]: ([^0]|0[^0])))/;
|
||||
|
||||
// https://github.com/megahertz/electron-log/issues/44
|
||||
// console.debug starting with Chromium 58 this method is a no-op on Chromium browsers.
|
||||
if (console.debug) {
|
||||
console.debug = console.log;
|
||||
console.debug = (...args: any[]): void => {
|
||||
if (writeRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:blue');
|
||||
} else if (readRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:green');
|
||||
} else if (errorRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:red');
|
||||
}else if (transferRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:orange');
|
||||
} else {
|
||||
console.log(...args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,7 +38,7 @@ if (console.debug) {
|
||||
*/
|
||||
@Injectable()
|
||||
export class ElectronLogService implements LogService {
|
||||
private static getErrorText(args: any) {
|
||||
public static getErrorText(args: any) {
|
||||
return util.inspect(args);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user