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.js'; 17import { error, info, log } from '../../log/Log.js'; 18import { HDC_DEVICE_FILTER } from '../common/ConstantType.js'; 19import { HdcDeviceManager } from '../HdcDeviceManager.js'; 20 21export interface matchingUsbDevice { 22 configurationValue: number; 23 interfaceNumber: number; 24 // @ts-ignore 25 endPoints: USBEndpoint[]; 26} 27 28export class UsbTransmissionChannel implements TransmissionInterface { 29 // @ts-ignore 30 private _device: USBDevice | null; 31 private readonly endpointIn: number; 32 private readonly endpointOut: number; 33 private readonly interfaceNumber: number; 34 35 private constructor( 36 // @ts-ignore 37 device: USBDevice, 38 endpointIn: number, 39 endpointOut: number, 40 interfaceNumber: number 41 ) { 42 this._device = device; 43 this.endpointIn = endpointIn; 44 this.endpointOut = endpointOut; 45 this.interfaceNumber = interfaceNumber; 46 } 47 48 /** 49 * Send data to the device side 50 * 51 * @param writeData writeData 52 */ 53 async writeData(writeData: ArrayBuffer) { 54 await this._device?.transferOut(this.endpointOut, writeData); 55 } 56 57 /** 58 * read data from device via usb 59 * 60 * @param length 61 */ 62 async readData(length: number): Promise<DataView> { 63 const result = await this._device?.transferIn(this.endpointOut, length); 64 if (result?.data) { 65 return result.data; 66 } else { 67 return Promise.resolve(new DataView(new ArrayBuffer(0))); 68 } 69 } 70 71 /** 72 * Close the device connection 73 */ 74 async close(): Promise<void> { 75 await this._device?.releaseInterface(this.interfaceNumber); 76 await this._device?.close(); 77 this._device = null; 78 } 79 80 /** 81 * 打开设备 82 * 83 * @param usbDevice 84 */ 85 static async openHdcDevice( 86 // @ts-ignore 87 usbDevice: USBDevice 88 ): Promise<UsbTransmissionChannel | null> { 89 try { 90 await usbDevice.open(); 91 const matchDevice = this.filterAndFindDevice(usbDevice, HDC_DEVICE_FILTER); 92 info('matchDevice is', matchDevice); 93 if (!matchDevice) { 94 throw new Error('Could not find hdc device'); 95 } 96 await usbDevice.selectConfiguration(matchDevice.configurationValue); 97 await usbDevice.claimInterface(matchDevice.interfaceNumber); 98 const endpointIn = UsbTransmissionChannel.filterEndpointNumber(matchDevice.endPoints, 'in'); 99 const endpointOut = UsbTransmissionChannel.filterEndpointNumber(matchDevice.endPoints, 'out'); 100 return new UsbTransmissionChannel(usbDevice, endpointIn, endpointOut, matchDevice.interfaceNumber); 101 } catch (e) { 102 return Promise.resolve(null); 103 } 104 } 105 106 /** 107 * Filter out matching devices 108 * 109 * @param device device 110 * @param filter filter 111 */ 112 private static filterAndFindDevice( 113 // @ts-ignore 114 device: USBDevice, 115 // @ts-ignore 116 filter: USBDeviceFilter 117 ): matchingUsbDevice | null { 118 for (const config of device.configurations) { 119 for (const intf of config.interfaces) 120 for (const al of intf.alternates) { 121 if ( 122 filter.classCode === al.interfaceClass && 123 filter.subclassCode === al.interfaceSubclass && 124 filter.protocolCode === al.interfaceProtocol 125 ) { 126 return { 127 configurationValue: config.configurationValue, 128 interfaceNumber: intf.interfaceNumber, 129 endPoints: al.endpoints, 130 }; 131 } 132 } 133 } 134 return null; 135 } 136 137 private static filterEndpointNumber( 138 // @ts-ignore 139 usbEndpoints: USBEndpoint[], 140 dir: 'in' | 'out', 141 type = 'bulk' 142 ): number { 143 let endpoint = usbEndpoints.filter((element) => { 144 return element.direction === dir && element.type === type; 145 }); 146 return endpoint[0].endpointNumber; 147 } 148} 149