HarmonyOS USB与HID设备通讯

一、项目背景:

因信创国产替代需求,公司准备慢慢向国产化转型,开始国产化的技术积累,需要一款国产移动终端设备替代原先的安卓终端,产品形态是安卓终端+STM32单片机结合的一款产品,选型国替代方案首先考虑到鸿蒙和星光麒麟,后面选择了鸿蒙,鸿蒙生态丰富,可跨端,不过OpenHarmony距离真正成熟商用还需要时间。

二、项目方案:

前期用华为P40 Pro harmony 4.2+STM32,通过USB Type-C的方式进行连接,手机做为Host,单片机做为Devices,通过OTG的转接进行连接。

三、开发过程中问题点:

(1)开发过程发现用ArkTS+ArkUi开发的鸿蒙应用,跑在P40上面界面卡顿、黑屏,用官网给出的例程也存在同样问题,在DevEco编译器中模拟器运行鸿蒙应用比较流畅,华为官网论坛开发者也有遇到这个问题,原因分析是跟低版本手机CPU兼容问题导致屏幕没刷新,目前还未完全适配低版本机型,可以用meta50或60系列手机调试进行规避。

(2)向公司申请meta60手机进行开发调试,应用运行卡顿、黑屏问题得到解决,但在开发USB的过程,可获取接入主设备的USB设备列表并打开USB设备,也可访问USB权限,但USBInterface获取不到,USBInterface包含USB输入和输出端点,通过端点才能读写数据进行传输,后面提交工单华为客服工程师建议升级next版本,然后升级next版本得到解决。
在这里插入图片描述

(3)HarmonyOS 的API版本管理策略存在不强制向下兼容的特点,不同设备搭载的 HarmonyOS 版本可能差异较大(如P30 pro用手机API 7,P40 pro用 API 9),且官网开发文档更新迭代较快,需自行根据实际开发调试的设备进行版本兼容适配。

建议开发者在开发前尽量用HarmonyOS next版本的终端进行开发工作,初次接触遇到的主要问题就是以上3点,后面项目是基于mate 60 HarmonyOS next 5.0.0进行开发,可以规避用4.2及以下双架构安卓和HarmonyOS系统的很多坑。

四、代码部分

参照官方文档https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/usb-guidelines-V5进行开发,代码如下:

import { BusinessError, systemDateTime, usbManager } from '@kit.BasicServicesKit';
import { Logger } from '@nzy/logger';
import { BasePacket } from '../parse/BasePacket';
import { McException } from '../rsu/McException';
import StringUtils from '../utils/StringUtils';
import UsbHostConfig from './UsbHostConfig';

/**
 * usb管理类
 */
class UsbDeviceManger {
  getUsbDevicesList() {
    // 获取设备列表。
    let deviceList: Array<usbManager.USBDevice> = usbManager.getDevices();
    if (deviceList.length === 0) {
      Logger.error("usb deviceList:" + deviceList);
      throw new McException(UsbHostConfig.MY_USB_LIST_NULL, undefined, undefined);
    }
    Logger.error("usb deviceList length:" + deviceList.length);
    let deviceName: string = deviceList[1].name;
    Logger.error("usb deviceName:" + deviceName);
    // 申请操作指定的device的操作权限。
    usbManager.requestRight(deviceName).then((hasRight: boolean) => {
      Logger.info("usb device request right result: " + hasRight);
      this.openUsbDevice(deviceList);
    }).catch((error: BusinessError) => {
      Logger.error("usb device request right failed : " + error);
      throw new McException(UsbHostConfig.MY_USB_REQ_RIGHT_FAILED, undefined, undefined);
    });
  }

  private pipe?: usbManager.USBDevicePipe;
  private interface1?: usbManager.USBInterface;

  openUsbDevice(deviceList: Array<usbManager.USBDevice>) {
    // 打开设备,获取数据传输通道。
    this.pipe = usbManager.connectDevice(deviceList[1]);
    this.interface1 = deviceList[1].configs[0].interfaces[0];
    /*
     打开对应接口,在设备信息(deviceList)中选取对应的interface。
    interface1为设备配置中的一个接口。
    */
    usbManager.claimInterface(this.pipe, this.interface1, true);
  }

  async sendData(cmd: Uint8Array): Promise<number> {
    let sendState: number = 1;
    if (this.interface1 === undefined) {
      sendState = 1;
      throw new McException(UsbHostConfig.MY_USB_DEV_NO_INTERFACE, undefined, undefined);
    }
    Logger.info("usb data send:" + StringUtils.uint8ArrayToHexString(cmd))
    let outEndpoint: usbManager.USBEndpoint = this.interface1.endpoints[1];
    // Logger.info("usb deviceList:" + this.interface1.endpoints[1].number)
    // 发送数据,在device信息中选取对应数据发送的endpoint来做数据传输。(endpoint.direction == 0)
    let result: Promise<number> = usbManager.bulkTransfer(this.pipe, outEndpoint, cmd, 1000);
    await result.then((dataLength: number) => {
      if (dataLength >= 0) {
        Logger.info("usb writeData result write length : " + dataLength);
        sendState = 0;
      } else {
        Logger.error("usb writeData failed");
        sendState = 1;
        throw new McException(UsbHostConfig.MY_USB_SEND_DATA_FAILED, undefined, undefined);
      }
    }).catch((error: BusinessError) => {
      Logger.error("usb writeData error : " + JSON.stringify(error));
      throw new McException(UsbHostConfig.MY_USB_SEND_DATA_ERROR, undefined, undefined);
    });
    return sendState;
  }

  revDataArray: Uint8Array = new Uint8Array(1024);

  async receiveData(): Promise<BasePacket> {
    /**************读取数据 START****************/
    if (this.interface1 != undefined) {
      let inEndpoint: usbManager.USBEndpoint = this.interface1.endpoints[0];
      /*
       读取数据,在device信息中选取对应数据接收的endpoint来做数据传输
     (endpoint.direction == 0x80);dataUint8Array是要读取的数据,类型为Uint8Array。
     */
      let currentTime = systemDateTime.getTime(false);
      while (currentTime + 2000 > systemDateTime.getTime(false)) {
        let dataLength: number = await usbManager.bulkTransfer(this.pipe, inEndpoint, this.revDataArray, 200);
        if (dataLength > 0) {
          let relDataArr: Uint8Array = this.revDataArray.slice(0, dataLength)
          Logger.info("usb readData result Length : " + dataLength + ",data:" +
          StringUtils.uint8ArrayToHexString(relDataArr));
          //此处可自行根据业务进行解析
        } else {
          Logger.error("usb readData failed : " + dataLength);
        }
      }
      throw new McException(UsbHostConfig.MY_USB_REV_DATA_FAILED, undefined, undefined);
    }
    throw new McException(UsbHostConfig.MY_USB_REV_DATA_ERROR, undefined, undefined);
  }

  releaseUsbDevice() {
    if (this.pipe !== undefined || this.interface1 !== undefined) {
      //释放注册过的通信接口
      usbManager.releaseInterface(this.pipe, this.interface1);
      //关闭设备消息控制通道
      usbManager.closePipe(this.pipe);
    }
  }
}

export default new UsbDeviceManger

五、HarmonyOS适配OpenHarmony

修改app icon图标(harmonyos 图标显示规则和OpenHarmony不一致,可能不显示,不要用前景背景合成)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0b95ef96cc8246e4876b4376bb47e2df.png

兼容OpenHarmony设备上运行,签名不用华为签名,用OpenHarmony签名;修改SDK版本和runtimeOS。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值