• 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';
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