* style(privilege): Fix typo 'excusive' -> 'exclusive' * style(privilege): remove unused imports * style(privilege): Fix typo 'initizalized$' -> 'initialized$' * feat(log): Add application wide logger and error handler It is help to debug electron install app on different device * feat(privilege): Add windows USB driver installation * build: I need the windows installer to test the app on windows * fix(privilege): change wdi-simpler installer to zadic * feat(log): change log level to debug in renderer process * chore: Add author in package.json * feat(privilege): Add privilege setter file as extraResource * fix(log): Allowed transport level change only in main process * fix(privilege): Fix app path calculation * fix(privilege): Take the scriptPath between double quote * build: revert the appveyor settings * refactor(privilege): Extract vendor ID, product ID and MAX_PAYLOAD_SIZE into constants file * refactor(privilege): Add both 32 and 64 bit zadics to extraResource of the installer * feat(device): Add HID API communication protocol * build: Fix npm install process * build: Fix npm install process v2 * ci: Add libudev-dev as travis apt dependencies * ci: Merge travis apt packages * ci: remove node-hid from build:usb * ci: try to fix linux build * ci: node-hid use git repo * ci: Add libusb-1.0-0-dev to travis apt dependency * feat(device): Use logging service when communicate with the device * build: create test build * build: PUBLISH_FOR_PULL_REQUEST override * build: revert TEST_BUILD to false * build: node-hid use package version instead of git repo * refactor: remove unused device store files from PR * ci: Manage test build from environment variable * fix(privilege): Set rules files dir base on dev or prod mode * fix(log): Extract nested properties of the logged object * feat(log): use util.inspect in logger service * build: upgrade @types/node-hid -> 0.5.2 * fix(device): Add extra logging when try to open device. * fix(device): log device description and not the device * fix(device): add win specific write * fix(device): add report id as first byte * style(privilege): Reformat else and comment in privilege-checker component * fix(privilege): Comment out windows branch
This commit is contained in:
committed by
László Monda
parent
84b13d3219
commit
2df8f2ea54
142
electron/src/services/uhk-lib-usb-api.service.ts
Normal file
142
electron/src/services/uhk-lib-usb-api.service.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { Inject, Injectable, NgZone, OnDestroy } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subscriber } from 'rxjs/Subscriber';
|
||||
|
||||
import 'rxjs/add/observable/empty';
|
||||
import 'rxjs/add/observable/timer';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/operator/concat';
|
||||
import 'rxjs/add/operator/combineLatest';
|
||||
import 'rxjs/add/operator/concatMap';
|
||||
import 'rxjs/add/operator/first';
|
||||
import 'rxjs/add/operator/publish';
|
||||
import 'rxjs/add/operator/do';
|
||||
|
||||
import { Device, findByIds, InEndpoint, Interface, on, OutEndpoint } from 'usb';
|
||||
|
||||
import { ILogService, LOG_SERVICE } from '../shared/services/logger.service';
|
||||
import { Constants } from '../shared/util';
|
||||
import { UhkDeviceService } from './uhk-device.service';
|
||||
|
||||
@Injectable()
|
||||
export class UhkLibUsbApiService extends UhkDeviceService implements OnDestroy {
|
||||
private device: Device;
|
||||
|
||||
static isUhkDevice(device: Device) {
|
||||
return device.deviceDescriptor.idVendor === Constants.VENDOR_ID &&
|
||||
device.deviceDescriptor.idProduct === Constants.PRODUCT_ID;
|
||||
}
|
||||
|
||||
constructor(zone: NgZone,
|
||||
@Inject(LOG_SERVICE) protected logService: ILogService) {
|
||||
super(logService);
|
||||
|
||||
this.initialize();
|
||||
|
||||
// The change detection doesn't work properly if the callbacks are called outside Angular Zone
|
||||
on('attach', (device: Device) => zone.run(() => this.onDeviceAttach(device)));
|
||||
on('detach', (device: Device) => zone.run(() => this.onDeviceDetach(device)));
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
if (this.initialized$.getValue()) {
|
||||
return;
|
||||
}
|
||||
this.device = findByIds(Constants.VENDOR_ID, Constants.PRODUCT_ID);
|
||||
this.connected$.next(!!this.device);
|
||||
if (!this.device) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.device.open();
|
||||
this.deviceOpened$.next(true);
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
const usbInterface: Interface = this.device.interface(0);
|
||||
// https://github.com/tessel/node-usb/issues/147
|
||||
// The function 'isKernelDriverActive' is not available on Windows and not even needed.
|
||||
if (usbInterface.isKernelDriverActive()) {
|
||||
usbInterface.detachKernelDriver();
|
||||
}
|
||||
|
||||
this.messageIn$ = Observable.create((subscriber: Subscriber<Buffer>) => {
|
||||
const inEndPoint: InEndpoint = <InEndpoint>usbInterface.endpoints[0];
|
||||
this.logService.info('Try to read');
|
||||
inEndPoint.transfer(Constants.MAX_PAYLOAD_SIZE, (error: string, receivedBuffer: Buffer) => {
|
||||
if (error) {
|
||||
this.logService.error('reading error', error);
|
||||
subscriber.error(error);
|
||||
} else {
|
||||
this.logService.info('read data', receivedBuffer);
|
||||
subscriber.next(receivedBuffer);
|
||||
subscriber.complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const outEndPoint: OutEndpoint = <OutEndpoint>usbInterface.endpoints[1];
|
||||
const outSending = this.messageOut$.concatMap(senderPackage => {
|
||||
return (<Observable<void>>Observable.create((subscriber: Subscriber<void>) => {
|
||||
this.logService.info('transfering', senderPackage.buffer);
|
||||
outEndPoint.transfer(senderPackage.buffer, error => {
|
||||
if (error) {
|
||||
this.logService.error('transfering errored', error);
|
||||
subscriber.error(error);
|
||||
} else {
|
||||
this.logService.info('transfering finished');
|
||||
subscriber.complete();
|
||||
}
|
||||
});
|
||||
})).concat(this.messageIn$)
|
||||
.do(buffer => senderPackage.observer.next(buffer) && senderPackage.observer.complete())
|
||||
.catch((error: string) => {
|
||||
senderPackage.observer.error(error);
|
||||
return Observable.empty<void>();
|
||||
});
|
||||
}).publish();
|
||||
this.outSubscription = outSending.connect();
|
||||
|
||||
this.initialized$.next(true);
|
||||
}
|
||||
|
||||
hasPermissions(): Observable<boolean> {
|
||||
return this.isConnected()
|
||||
.combineLatest(this.deviceOpened$)
|
||||
.map((latest: boolean[]) => {
|
||||
const connected = latest[0];
|
||||
const opened = latest[1];
|
||||
if (!connected) {
|
||||
return false;
|
||||
} else if (opened) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
this.device.open();
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
this.device.close();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
onDeviceAttach(device: Device) {
|
||||
if (!UhkLibUsbApiService.isUhkDevice(device)) {
|
||||
return;
|
||||
}
|
||||
// Ugly hack: device is not openable (on Windows) right after the attach
|
||||
Observable.timer(100)
|
||||
.first()
|
||||
.subscribe(() => this.initialize());
|
||||
}
|
||||
|
||||
onDeviceDetach(device: Device) {
|
||||
if (!UhkLibUsbApiService.isUhkDevice(device)) {
|
||||
return;
|
||||
}
|
||||
this.disconnect();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user