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