• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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