1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { TransmissionInterface } from './TransmissionInterface'; 17import { info } from '../../log/Log'; 18import { HDC_DEVICE_FILTER } from '../common/ConstantType'; 19 20export interface matchingUsbDevice { 21 configurationValue: number; 22 interfaceNumber: number; 23 // @ts-ignore 24 endPoints: USBEndpoint[]; 25} 26 27export class UsbTransmissionChannel implements TransmissionInterface { 28 // @ts-ignore 29 private _device: USBDevice | null; 30 private readonly endpointIn: number; 31 private readonly endpointOut: number; 32 private readonly interfaceNumber: number; 33 34 private constructor( 35 // @ts-ignore 36 device: USBDevice, 37 endpointIn: number, 38 endpointOut: number, 39 interfaceNumber: number 40 ) { 41 this._device = device; 42 this.endpointIn = endpointIn; 43 this.endpointOut = endpointOut; 44 this.interfaceNumber = interfaceNumber; 45 } 46 47 /** 48 * Send data to the device side 49 * 50 * @param writeData writeData 51 */ 52 async writeData(writeData: ArrayBuffer): Promise<void> { 53 await this._device?.transferOut(this.endpointOut, writeData); 54 } 55 56 /** 57 * read data from device via usb 58 * 59 * @param length 60 */ 61 async readData(length: number): Promise<DataView> { 62 const result = await this._device?.transferIn(this.endpointOut, length); 63 if (result?.data) { 64 return result.data; 65 } else { 66 return Promise.resolve(new DataView(new ArrayBuffer(0))); 67 } 68 } 69 70 /** 71 * Close the device connection 72 */ 73 async close(): Promise<void> { 74 try { 75 await this._device?.releaseInterface(this.interfaceNumber); 76 await this._device?.close(); 77 } catch (e) {} 78 this._device = null; 79 } 80 81 /** 82 * 打开设备 83 * 84 * @param usbDevice 85 */ 86 static async openHdcDevice( 87 // @ts-ignore 88 usbDevice: USBDevice 89 ): Promise<UsbTransmissionChannel | null> { 90 try { 91 await usbDevice.open(); 92 const matchDevice = this.filterAndFindDevice(usbDevice, HDC_DEVICE_FILTER); 93 info('matchDevice is', matchDevice); 94 if (!matchDevice) { 95 throw new Error('Could not find hdc device'); 96 } 97 await usbDevice.selectConfiguration(matchDevice.configurationValue); 98 await usbDevice.claimInterface(matchDevice.interfaceNumber); 99 const endpointIn = UsbTransmissionChannel.filterEndpointNumber(matchDevice.endPoints, 'in'); 100 const endpointOut = UsbTransmissionChannel.filterEndpointNumber(matchDevice.endPoints, 'out'); 101 return new UsbTransmissionChannel(usbDevice, endpointIn, endpointOut, matchDevice.interfaceNumber); 102 } catch (e) { 103 return Promise.resolve(null); 104 } 105 } 106 107 /** 108 * Filter out matching devices 109 * 110 * @param device device 111 * @param filter filter 112 */ 113 private static filterAndFindDevice( 114 // @ts-ignore 115 device: USBDevice, 116 // @ts-ignore 117 filter: USBDeviceFilter 118 ): matchingUsbDevice | null { 119 for (const config of device.configurations) { 120 for (const intf of config.interfaces) 121 for (const al of intf.alternates) { 122 if ( 123 filter.classCode === al.interfaceClass && 124 filter.subclassCode === al.interfaceSubclass && 125 filter.protocolCode === al.interfaceProtocol 126 ) { 127 return { 128 configurationValue: config.configurationValue, 129 interfaceNumber: intf.interfaceNumber, 130 endPoints: al.endpoints, 131 }; 132 } 133 } 134 } 135 return null; 136 } 137 138 private static filterEndpointNumber( 139 // @ts-ignore 140 usbEndpoints: USBEndpoint[], 141 dir: 'in' | 'out', 142 type = 'bulk' 143 ): number { 144 let endpoint = usbEndpoints.filter((element) => { 145 return element.direction === dir && element.type === type; 146 }); 147 return endpoint[0].endpointNumber; 148 } 149} 150