feat(config): Read / write hardware configuration area (#423)

* add write-hca.js

* refactor: Move config serializer into the uhk-common package

* refactor: Move getTransferBuffers into the uhk-usb package

* refactor: delete obsoleted classes

* build: add uhk-usb build command

* refactor: move eeprom transfer to uhk-usb package

* fix: Fix write-hca.js

* feat: load hardware config from the device and

* style: fix ts lint errors

* build: fix rxjs dependency resolve

* test: Add jasmine unit test framework to the tet serializer

* fix(user-config): A "type": "basic", properties to the "keystroke" action types

* feat(usb): set chmod+x on write-hca.js

* feat(usb): Create USB logger

* style: Fix type

* build: Add chalk to dependencies.

Chalk will colorize the output
This commit is contained in:
Róbert Kiss
2017-09-26 18:57:27 +02:00
committed by László Monda
parent 1122784bdb
commit 9294bede50
130 changed files with 9108 additions and 1991 deletions

View File

@@ -1,8 +1,7 @@
import { Action } from '@ngrx/store';
import { type } from 'uhk-common';
import { Notification, CommandLineArgs } from 'uhk-common';
import { AppStartInfo } from '../../../../../uhk-common/src/models/app-start-info';
import { AppStartInfo, HardwareConfiguration, Notification } from 'uhk-common';
const PREFIX = '[app] ';
@@ -15,7 +14,8 @@ export const ActionTypes = {
APP_PROCESS_START_INFO: type(PREFIX + 'process start info'),
UNDO_LAST: type(PREFIX + 'undo last action'),
UNDO_LAST_SUCCESS: type(PREFIX + 'undo last action success'),
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action')
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action'),
LOAD_HARDWARE_CONFIGURATION_SUCCESS: type(PREFIX + 'load hardware configuration success')
};
export class AppBootsrappedAction implements Action {
@@ -58,6 +58,12 @@ export class DismissUndoNotificationAction implements Action {
type = ActionTypes.DISMISS_UNDO_NOTIFICATION;
}
export class LoadHardwareConfigurationSuccessAction implements Action {
type = ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS;
constructor(public payload: HardwareConfiguration) {}
}
export type Actions
= AppStartedAction
| AppBootsrappedAction
@@ -66,4 +72,6 @@ export type Actions
| ProcessAppStartInfoAction
| UndoLastAction
| UndoLastSuccessAction
| DismissUndoNotificationAction;
| DismissUndoNotificationAction
| LoadHardwareConfigurationSuccessAction
;

View File

@@ -1,8 +1,5 @@
import { Action } from '@ngrx/store';
import { KeyAction } from '../../config-serializer/config-items/key-action';
import { Keymap } from '../../config-serializer/config-items/keymap';
import { Macro } from '../../config-serializer/config-items/macro';
import { KeyAction, Keymap, Macro } from 'uhk-common';
export namespace KeymapActions {
export const PREFIX = '[Keymap] ';

View File

@@ -1,7 +1,5 @@
import { Action } from '@ngrx/store';
import { Macro } from '../../config-serializer/config-items/macro';
import { MacroAction } from '../../config-serializer/config-items/macro-action';
import { Macro, MacroAction } from 'uhk-common';
export namespace MacroActions {
export const PREFIX = '[Macro] ';

View File

@@ -1,15 +1,13 @@
import { Action } from '@ngrx/store';
import { type } from 'uhk-common';
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
import { type, UserConfiguration, ConfigurationReply } from 'uhk-common';
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_CONFIG_FROM_DEVICE: type(PREFIX + 'Load User Config from Device'),
LOAD_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')
};
@@ -18,14 +16,14 @@ export class LoadUserConfigAction implements Action {
type = ActionTypes.LOAD_USER_CONFIG;
}
export class LoadUserConfigFromDeviceAction implements Action {
type = ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE;
export class LoadConfigFromDeviceAction implements Action {
type = ActionTypes.LOAD_CONFIG_FROM_DEVICE;
}
export class LoadUserConfigFromDeviceReplyAction implements Action {
type = ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE_REPLY;
export class LoadConfigFromDeviceReplyAction implements Action {
type = ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY;
constructor(public payload: Array<number>) { }
constructor(public payload: ConfigurationReply) { }
}
export class LoadUserConfigSuccessAction implements Action {
@@ -43,4 +41,7 @@ export class SaveUserConfigSuccessAction implements Action {
export type Actions
= LoadUserConfigAction
| LoadUserConfigSuccessAction
| SaveUserConfigSuccessAction;
| SaveUserConfigSuccessAction
| LoadConfigFromDeviceAction
| LoadConfigFromDeviceReplyAction
;

View File

@@ -12,7 +12,7 @@ import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/withLatestFrom';
import { NotificationType, IpcResponse } from 'uhk-common';
import { NotificationType, IpcResponse, UhkBuffer, UserConfiguration } from 'uhk-common';
import {
ActionTypes,
ConnectionStateChangedAction,
@@ -24,9 +24,7 @@ import {
import { DeviceRendererService } from '../../services/device-renderer.service';
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';
import { LoadConfigFromDeviceAction } from '../actions/user-config';
@Injectable()
export class DeviceEffects {
@@ -44,7 +42,7 @@ export class DeviceEffects {
})
.switchMap((connected: boolean) => {
if (connected) {
return Observable.of(new LoadUserConfigFromDeviceAction());
return Observable.of(new LoadConfigFromDeviceAction());
}
return Observable.empty();

View File

@@ -12,11 +12,10 @@ import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/observable/of';
import { Keymap } from 'uhk-common';
import { KeymapActions } from '../actions';
import { AppState } from '../index';
import { Keymap } from '../../config-serializer/config-items/keymap';
@Injectable()
export class KeymapEffects {

View File

@@ -11,7 +11,14 @@ import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/observable/of';
import { LogService, NotificationType } from 'uhk-common';
import {
ConfigurationReply,
HardwareConfiguration,
LogService,
NotificationType,
UhkBuffer,
UserConfiguration
} from 'uhk-common';
import {
ActionTypes,
@@ -20,21 +27,42 @@ import {
SaveUserConfigSuccessAction
} from '../actions/user-config';
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
import { AppState, getPrevUserConfiguration, getUserConfiguration } from '../index';
import { KeymapActions } from '../actions/keymap';
import { MacroActions } from '../actions/macro';
import { UndoUserConfigData } from '../../models/undo-user-config-data';
import { ShowNotificationAction, DismissUndoNotificationAction } from '../actions/app';
import { ShowNotificationAction, DismissUndoNotificationAction, LoadHardwareConfigurationSuccessAction } 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 {
private static getUserConfigFromDeviceResponse(json: string): UserConfiguration {
const data = JSON.parse(json);
const userConfig = new UserConfiguration();
userConfig.fromBinary(UhkBuffer.fromArray(data));
if (userConfig.dataModelVersion > 0) {
return userConfig;
}
return null;
}
private static getHardwareConfigFromDeviceResponse(json: string): HardwareConfiguration {
const data = JSON.parse(json);
const hardwareConfig = new HardwareConfiguration();
hardwareConfig.fromBinary(UhkBuffer.fromArray(data));
if (hardwareConfig.uuid > 0) {
return hardwareConfig;
}
return null;
}
@Effect() loadUserConfig$: Observable<Action> = this.actions$
.ofType(ActionTypes.LOAD_USER_CONFIG)
.startWith(new LoadUserConfigAction())
@@ -88,38 +116,36 @@ 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({dispatch: false}) loadConfigFromDevice$ = this.actions$
.ofType(ActionTypes.LOAD_CONFIG_FROM_DEVICE)
.do(() => this.deviceRendererService.loadConfigurationFromKeyboard());
@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);
@Effect() loadConfigFromDeviceReply$ = this.actions$
.ofType(ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY)
.map(toPayload)
.mergeMap((data: ConfigurationReply): any => {
if (!data.success) {
return [new ShowNotificationAction({
type: NotificationType.Error,
message: data.error
})];
}
return Observable.empty();
try {
const userConfig = UserConfigEffects.getUserConfigFromDeviceResponse(data.userConfiguration);
const hardwareConfig = UserConfigEffects.getHardwareConfigFromDeviceResponse(data.hardwareConfiguration);
return [
new LoadUserConfigSuccessAction(userConfig),
new LoadHardwareConfigurationSuccessAction(hardwareConfig)
];
} catch (err) {
this.logService.error('Eeprom parse error:', err);
return [new ShowNotificationAction({
type: NotificationType.Error,
message: err.message
})];
}
});
constructor(private actions$: Actions,
@@ -147,4 +173,5 @@ export class UserConfigEffects {
return config;
}
}

View File

@@ -3,11 +3,10 @@ import { compose } from '@ngrx/core/compose';
import { ActionReducer, combineReducers } from '@ngrx/store';
import { RouterState, routerReducer } from '@ngrx/router-store';
import { storeFreeze } from 'ngrx-store-freeze';
import { Keymap, UserConfiguration } from 'uhk-common';
import userConfigurationReducer from './reducers/user-configuration';
import presetReducer from './reducers/preset';
import { Keymap } from '../config-serializer/config-items/keymap';
import { UserConfiguration } from '../config-serializer/config-items/user-configuration';
import * as fromAppUpdate from './reducers/app-update.reducer';
import * as autoUpdateSettings from './reducers/auto-update-settings';
import * as fromApp from './reducers/app.reducer';
@@ -53,6 +52,8 @@ export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu);
export const getUndoableNotification = createSelector(appState, fromApp.getUndoableNotification);
export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrevUserConfiguration);
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);
export const getHardwareConfiguration = createSelector(appState, fromApp.getHardwareConfiguration);
export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout);
export const appUpdateState = (state: AppState) => state.appUpdate;
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);

View File

@@ -1,10 +1,10 @@
import { routerActions } from '@ngrx/router-store';
import { Action } from '@ngrx/store';
import { runInElectron, Notification, NotificationType } from 'uhk-common';
import { HardwareConfiguration, runInElectron, Notification, NotificationType, UserConfiguration } from 'uhk-common';
import { ActionTypes, ShowNotificationAction } from '../actions/app';
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum';
export interface State {
started: boolean;
@@ -13,7 +13,8 @@ export interface State {
navigationCountAfterNotification: number;
prevUserConfig?: UserConfiguration;
runningInElectron: boolean;
userConfigLoading: boolean;
configLoading: boolean;
hardwareConfig?: HardwareConfiguration;
}
const initialState: State = {
@@ -21,7 +22,7 @@ const initialState: State = {
showAddonMenu: false,
navigationCountAfterNotification: 0,
runningInElectron: runInElectron(),
userConfigLoading: true
configLoading: true
};
export function reducer(state = initialState, action: Action) {
@@ -56,7 +57,7 @@ export function reducer(state = initialState, action: Action) {
// When deleted a keymap or macro the app automaticaly navigate to other keymap, or macro, so
// so we have to count the navigations and when reach the 2nd then remove the dialog.
case routerActions.UPDATE_LOCATION: {
const newState = { ...state };
const newState = {...state};
newState.navigationCountAfterNotification++;
if (newState.navigationCountAfterNotification > 1) {
@@ -79,18 +80,24 @@ export function reducer(state = initialState, action: Action) {
return {
...state,
prevUserConfig: action.payload,
userConfigLoading: false
configLoading: false
};
}
case UserConfigActionTypes.LOAD_USER_CONFIG_FROM_DEVICE:
case UserConfigActionTypes.LOAD_CONFIG_FROM_DEVICE:
case UserConfigActionTypes.LOAD_USER_CONFIG: {
return {
...state,
userConfigLoading: true
configLoading: true
};
}
case ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS:
return {
...state,
hardwareConfig: action.payload
};
default:
return state;
}
@@ -100,3 +107,11 @@ export const showAddonMenu = (state: State) => state.showAddonMenu;
export const getUndoableNotification = (state: State) => state.undoableNotification;
export const getPrevUserConfiguration = (state: State) => state.prevUserConfig;
export const runningInElectron = (state: State) => state.runningInElectron;
export const getHardwareConfiguration = (state: State) => state.hardwareConfig;
export const getKeyboardLayout = (state: State): KeyboardLayout => {
if (state.hardwareConfig && state.hardwareConfig.isIso) {
return KeyboardLayout.ISO;
}
return KeyboardLayout.ANSI;
};

View File

@@ -1,6 +1,6 @@
import { Action } from '@ngrx/store';
import { Keymap } from 'uhk-common';
import { Keymap } from '../../config-serializer/config-items/keymap';
import { KeymapActions } from '../actions/keymap';
const initialState: Keymap[] = [];

View File

@@ -5,12 +5,7 @@ import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import { Helper as KeyActionHelper } from '../../config-serializer/config-items/key-action';
import { Keymap } from '../../config-serializer/config-items/keymap';
import { Macro } from '../../config-serializer/config-items/macro';
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
import { Layer } from '../../config-serializer/config-items/layer';
import { Module } from '../../config-serializer/config-items/module';
import { Keymap, KeyActionHelper, Layer, Macro, Module, UserConfiguration } from 'uhk-common';
import { KeymapActions, MacroActions } from '../actions';
import { AppState } from '../index';
import { ActionTypes } from '../actions/user-config';