feat: show udev rules on missing device screen (#842)
* feat: show udev rules on missing device screen * delete MissingDeviceComponent * feat: change privilege and message device screen texts * feat: change message device screen texts * fix: load config from device * fix: load config when hasPermission = true * fix: load app start info after set permission rules * fix: action dispatch * fix: load config from device when UdevRulesInfo.Ok * fix: load config from device when 0 device available * feat: add extra space between the "old udev rule" and permission button
This commit is contained in:
committed by
László Monda
parent
10cd06c70b
commit
1a9bd7de83
@@ -1,5 +1,7 @@
|
||||
import { Device, devices, HID } from 'node-hid';
|
||||
import { CommandLineArgs, DeviceConnectionState, isEqualArray, LogService } from 'uhk-common';
|
||||
import { pathExists } from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { CommandLineArgs, DeviceConnectionState, isEqualArray, LogService, UdevRulesInfo } from 'uhk-common';
|
||||
|
||||
import {
|
||||
ConfigBufferId,
|
||||
@@ -13,7 +15,7 @@ import {
|
||||
UsbCommand,
|
||||
UsbVariables
|
||||
} from './constants';
|
||||
import { bufferToString, getTransferData, isUhkDevice, retry, snooze } from './util';
|
||||
import { bufferToString, getFileContentAsync, getTransferData, isUhkDevice, isUhkZeroInterface, retry, snooze } from './util';
|
||||
|
||||
export const BOOTLOADER_TIMEOUT_MS = 5000;
|
||||
|
||||
@@ -28,9 +30,11 @@ export class UhkHidDevice {
|
||||
private _prevDevices = [];
|
||||
private _device: HID;
|
||||
private _hasPermission = false;
|
||||
private _udevRulesInfo = UdevRulesInfo.Unkonwn;
|
||||
|
||||
constructor(private logService: LogService,
|
||||
private options: CommandLineArgs) {
|
||||
private options: CommandLineArgs,
|
||||
private rootDir: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +58,7 @@ export class UhkHidDevice {
|
||||
const devs = devices();
|
||||
this.logDevices(devs);
|
||||
|
||||
const dev = devs.find((x: Device) => isUhkDevice(x) || x.productId === Constants.BOOTLOADER_ID);
|
||||
const dev = devs.find((x: Device) => isUhkZeroInterface(x) || x.productId === Constants.BOOTLOADER_ID);
|
||||
|
||||
if (!dev) {
|
||||
return true;
|
||||
@@ -74,20 +78,26 @@ export class UhkHidDevice {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with true is an UHK Device is connected to the computer.
|
||||
* @returns {boolean}
|
||||
* Return with the USB device communication sate.
|
||||
* @returns {DeviceConnectionState}
|
||||
*/
|
||||
public getDeviceConnectionState(): DeviceConnectionState {
|
||||
public async getDeviceConnectionStateAsync(): Promise<DeviceConnectionState> {
|
||||
const devs = devices();
|
||||
const result: DeviceConnectionState = {
|
||||
bootloaderActive: false,
|
||||
connected: false,
|
||||
hasPermission: this.hasPermission()
|
||||
zeroInterfaceAvailable: false,
|
||||
hasPermission: this.hasPermission(),
|
||||
udevRulesInfo: await this.getUdevInfoAsync()
|
||||
};
|
||||
|
||||
for (const dev of devs) {
|
||||
if (isUhkDevice(dev)) {
|
||||
result.connected = true;
|
||||
}
|
||||
|
||||
if (isUhkZeroInterface(dev)) {
|
||||
result.zeroInterfaceAvailable = true;
|
||||
} else if (dev.vendorId === Constants.VENDOR_ID &&
|
||||
dev.productId === Constants.BOOTLOADER_ID) {
|
||||
result.bootloaderActive = true;
|
||||
@@ -270,7 +280,7 @@ export class UhkHidDevice {
|
||||
this.logService.debug('[UhkHidDevice] Available devices unchanged');
|
||||
}
|
||||
|
||||
const dev = devs.find(isUhkDevice);
|
||||
const dev = devs.find(isUhkZeroInterface);
|
||||
|
||||
if (!dev) {
|
||||
this.logService.debug('[UhkHidDevice] UHK Device not found:');
|
||||
@@ -279,8 +289,7 @@ export class UhkHidDevice {
|
||||
const device = new HID(dev.path);
|
||||
this.logService.debug('[UhkHidDevice] Used device:', JSON.stringify(dev));
|
||||
return device;
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
this.logService.error('[UhkHidDevice] Can not create device:', err);
|
||||
}
|
||||
|
||||
@@ -292,6 +301,31 @@ export class UhkHidDevice {
|
||||
this.logService.debug(JSON.stringify(logDevice));
|
||||
}
|
||||
}
|
||||
|
||||
private async getUdevInfoAsync(): Promise<UdevRulesInfo> {
|
||||
if (this._udevRulesInfo === UdevRulesInfo.Ok) {
|
||||
return UdevRulesInfo.Ok;
|
||||
}
|
||||
|
||||
if (process.platform === 'win32' || process.platform === 'darwin') {
|
||||
this._udevRulesInfo = UdevRulesInfo.Ok;
|
||||
return UdevRulesInfo.Ok;
|
||||
}
|
||||
|
||||
if (!(await pathExists('/etc/udev/rules.d/50-uhk60.rules'))) {
|
||||
return UdevRulesInfo.NeedToSetup;
|
||||
}
|
||||
|
||||
const expectedUdevSettings = await getFileContentAsync(path.join(this.rootDir, 'rules/50-uhk60.rules'));
|
||||
const currentUdevSettings = await getFileContentAsync('/etc/udev/rules.d/50-uhk60.rules');
|
||||
|
||||
if (isEqualArray(expectedUdevSettings, currentUdevSettings)) {
|
||||
this._udevRulesInfo = UdevRulesInfo.Ok;
|
||||
return UdevRulesInfo.Ok;
|
||||
}
|
||||
|
||||
return UdevRulesInfo.Different;
|
||||
}
|
||||
}
|
||||
|
||||
function kbootCommandName(module: ModuleSlotToI2cAddress): string {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Device } from 'node-hid';
|
||||
import { DeviceConnectionState, LogService } from 'uhk-common';
|
||||
import { readFile } from 'fs-extra';
|
||||
import { EOL } from 'os';
|
||||
import { LogService } from 'uhk-common';
|
||||
|
||||
import { Constants, UsbCommand } from './constants';
|
||||
|
||||
@@ -98,13 +100,7 @@ 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;
|
||||
};
|
||||
|
||||
export const isUhkDevice = (dev: Device): boolean => {
|
||||
export const isUhkZeroInterface = (dev: Device): boolean => {
|
||||
return dev.vendorId === Constants.VENDOR_ID &&
|
||||
dev.productId === Constants.PRODUCT_ID &&
|
||||
// hidapi can not read the interface number on Mac, so check the usage page and usage
|
||||
@@ -112,3 +108,17 @@ export const isUhkDevice = (dev: Device): boolean => {
|
||||
(dev.usagePage === (0xFF00 | 0x00) && dev.usage === 0x01) || // New firmware
|
||||
dev.interface === 0);
|
||||
};
|
||||
|
||||
export const isUhkDevice = (dev: Device): boolean => {
|
||||
return dev.vendorId === Constants.VENDOR_ID &&
|
||||
(dev.productId === Constants.PRODUCT_ID || dev.productId === Constants.BOOTLOADER_ID);
|
||||
};
|
||||
|
||||
export const getFileContentAsync = async (filePath: string): Promise<Array<string>> => {
|
||||
const fileContent = await readFile(filePath, {encoding: 'utf-8'});
|
||||
|
||||
return fileContent
|
||||
.split(EOL)
|
||||
.map(x => x.trim())
|
||||
.filter(x => !x.startsWith('#') && x.length > 0);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user