• 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    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}