7

【系统服务】- OpenHarmony 串口服务访问

 2 years ago
source link: https://www.51cto.com/article/716452.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
b7717e453e004dccd7d40283299f5a586d5b81.png

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

本文档是在eTS项目hap包中实现串口访问的使用说明,通过JS接口开放给上层应用使用。

一、开发环境准备

安装OpenHarmony SDK

1、在DevEco Studio菜单栏选择Tools->SDK Manager

#物联网征文# 【系统服务】- OpenHarmony 串口服务访问-开源基础软件社区

2、OpenHarmony SDK选项中选择配备API版本进行安装

二、创建eTS项目

创建支持Native C++的eTS项目

#物联网征文# 【系统服务】- OpenHarmony 串口服务访问-开源基础软件社区
#物联网征文# 【系统服务】- OpenHarmony 串口服务访问-开源基础软件社区

三、NAPI库相关

生成串口NAPI库

1、添加文件src/main/cpp/types/libserialhelper/serialhelper.d.ts

/*
 * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import {AsyncCallback, Callback} from "basic";
declare namespace serialHelper {
  /**
   * Open serial port.
   * @param dev Indicates the serial port dev.
   */
  function openSerial(dev:string, callback: AsyncCallback<void>): void;
  function openSerial(dev:string): Promise<void>;
  /**
   * Close serial port.
   * @param dev Indicates the serial port dev.
   */
  function closeSerial(dev:string, callback: AsyncCallback<void>): void;
  function closeSerial(dev:string): Promise<void>;
}
export default serialHelper;

2、添加文件src/main/cpp/types/libserialhelper/package.json

{
  "name": "libserialhelper.so",
  "types": "./serialhelper.d.ts"
}

3、根据serialhelper.d.ts文件生成对应的c++源码

方式一:手动编写src/main/cpp/serial_helper.cpp。

struct AsyncCallInfo{
    napi_env env = nullptr;
    napi_ref callbackRef = nullptr;
    napi_deferred deferred = nullptr;
    napi_async_work work = nullptr;
    void *data = nullptr;
};
static void AsyncCallFinish(AsyncCallInfo* asyncCallInfo, int32_t result, napi_value *asyncResult)
{
    if (asyncCallInfo->deferred) {
        if (result == 0) {
            napi_resolve_deferred(asyncCallInfo->env, asyncCallInfo->deferred,
                    asyncResult[1]==nullptr?asyncResult[0]:asyncResult[1]);
        } else {
            napi_reject_deferred(asyncCallInfo->env, asyncCallInfo->deferred, asyncResult[0]);
        }
    } else {
        napi_value callback = nullptr;
        napi_get_reference_value(asyncCallInfo->env, asyncCallInfo->callbackRef, &callback);
        napi_call_function(asyncCallInfo->env, nullptr, callback, CALLBACK_ARGV_CNT, asyncResult, nullptr);
        napi_delete_reference(asyncCallInfo->env, asyncCallInfo->callbackRef);
    }
}
static napi_value Call_OpenSerial(napi_env env, napi_callback_info info)
{
    size_t argc = 0;
    napi_value args[DEFAULT_ARG_COUNT] = {0};
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    ...
    napi_value resourceName = nullptr;
    napi_create_string_utf8(env, "x_napi_tool", NAPI_AUTO_LENGTH, &resourceName);
    napi_create_async_work(env, nullptr, resourceName,
            [](napi_env env, void* data) {
                AsyncCallInfo* asyncCallInfo = (AsyncCallInfo*)data;
                OpenSerialValue* openValue = (OpenSerialValue*)asyncCallInfo->data;
                //openValue->out = SerialClient::GetInstance()->OpenSerial(openValue->dev);
            },
            [](napi_env env, napi_status status, void* data) {
                AsyncCallInfo* asyncCallInfo = (AsyncCallInfo*)data;
                OpenSerialValue* openValue = (OpenSerialValue*)asyncCallInfo->data;
                napi_value asyncResult[CALLBACK_ARGV_CNT]={nullptr, nullptr};
                napi_create_int32(env, openValue->out, &asyncResult[0]);
                AsyncCallFinish(asyncCallInfo, openValue->out,asyncResult);
                napi_delete_async_work(env, asyncCallInfo->work);
                delete openValue;
                delete asyncCallInfo;
            },
            (void*)asyncCallInfo, &asyncCallInfo->work);
    napi_queue_async_work(env, asyncCallInfo->work);
    return retValue;
}

方式二:使用NAPI框架生成工具生成 ​​工具链接​​。

(1)将serialhelper.d.ts、basic.d.ts复制到同一目录中,创建out目录。

(2)执行./napi_generator-linux -f serialhelper.d.ts -o out。

(3)将生成的源码文件复制到src/main/cpp。

4、make文件:src/main/cpp/CMakeList.txt

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(XComponent)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${NATIVERENDER_ROOT_PATH})
add_library(serialhelper SHARED serial_helper.cpp)
target_link_libraries(serialhelper PUBLIC libace_napi.z.so libc++.a)

5、添加项目依赖

entry/package.json:

"devDependencies": {
  "@types/libserialhelper.so": "file:./src/main/cpp/types/libserialhelper"
}

entry/package-lock.json:

"dependencies": {
   "@types/libserialhelper.so": {
      "version": "file:src/main/cpp/types/libserialhelper",
      "dev": true
   }
}

6、编译生成

修改编译项entry/build-profile.json5:

"buildOption": {
  "externalNativeOptions": {
    "path": "./src/main/cpp/CMakeLists.txt",
    "arguments": "-v -DOHOS_STL=c++_shared",
    "abiFilters": [
      "armeabi-v7a",
    ],
    "cppFlags": "",
  }
}

四、实现串口异步回调

添加串口IPC客户端libserialport_service_api.z.so库,并且实现具体的异步回调功能

  1. 将libserialport_service_api.z.so复制到entry/libs/armeabi-a7v目录。
  2. 将库的头文件复制到entry/src/main/cpp/include目录。
  3. 继承SerialCallbackBase类,实现串口数据异步回调SerialAsyncCallback。
class SerialAsyncCallback: public SerialCallbackBase {
public:
    SerialAsyncCallback() = default;
    ~SerialAsyncCallback();
    // 通知回调事件
    void OnCallBackEvent() override;
    // 接收到串口数据
    void OnRecvData(const uint8_t *buffer, uint32_t length) override;
    ...
};

修改src/main/cpp/CMakeList.txt文件。

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(XComponent)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include
                    )
link_directories(${NATIVERENDER_ROOT_PATH}/../../../libs/${CMAKE_OHOS_ARCH_ABI})
add_library(serialhelper SHARED serial_helper.cpp x_napi_tool.cpp serial_async_callback.cpp)
target_link_libraries(serialhelper PUBLIC libace_napi.z.so libc++.a libhilog_ndk.z.so libuv.so libserialport_service_api.z.so)

在napi函数中调用api函数,使用NAPI框架生成工具生成OpenSerial代码,如下:

struct OpenSerial_value_struct {
    std::string in0;
    int32_t out;
};
void OpenSerial_execute(XNapiTool *pxt, void *data)
{
    OpenSerial_value_struct *vio = (OpenSerial_value_struct *)data;
    vio->out = get_serial_client()->OpenSerial(vio->in0);
}   
void OpenSerial_complete(XNapiTool *pxt, void *data)
{
    OpenSerial_value_struct *vio = (OpenSerial_value_struct *)data;
    napi_value result = nullptr;
    result = NUMBER_C_2_JS(pxt, Int32, vio->out);
    {
        napi_value args[XNapiTool::ARGV_CNT] = {result, nullptr};
        pxt->FinishAsync(vio->out, args);
    }
    delete vio;
}
napi_value OpenSerial_middle(napi_env env, napi_callback_info info)
{
    XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release();
    if (pxt->IsFailed()) {
        napi_value err = pxt->GetError();
        delete pxt;
        return err;
    }
    struct OpenSerial_value_struct *vio = new OpenSerial_value_struct();
    pxt->SwapJs2CUtf8(pxt->GetArgv(0), vio->in0);
    napi_value result = pxt->StartAsync(OpenSerial_execute, vio, OpenSerial_complete,
        pxt->GetArgc() == 2 ? pxt->GetArgv(1) : nullptr);
    if (pxt->IsFailed()) {
        result = pxt->GetError();
    }
    return result;
}

模块注册。

static napi_value init(napi_env env, napi_value exports)
{
    std::shared_ptr<XNapiTool> pxt = std::make_shared<XNapiTool>(env, exports);
    //js函数与C++函数映射
    pxt->DefineFunction("setOptions", OHOS::SerialPort::SetOptions_middle);
    pxt->DefineFunction("openSerial", OHOS::SerialPort::OpenSerial_middle);
    pxt->DefineFunction("closeSerial", OHOS::SerialPort::CloseSerial_middle);
    pxt->DefineFunction("clearBuffer", OHOS::SerialPort::ClearBuffer_middle);
    pxt->DefineFunction("sendData", OHOS::SerialPort::SendData_middle);
    pxt->DefineFunction("recvData", OHOS::SerialPort::RecvData_middle);
    pxt->DefineFunction("transmit", OHOS::SerialPort::Transmit_middle);
    pxt->DefineFunction("on", OHOS::SerialPort::on_middle);
    pxt->DefineFunction("off", OHOS::SerialPort::off_middle);
    pxt->DefineFunction("setGPIODirection", OHOS::SerialPort::setGPIODirection_middle);
    pxt->DefineFunction("setGPIOValue", OHOS::SerialPort::setGPIOValue_middle);
    pxt->DefineFunction("getGPIOValue", OHOS::SerialPort::getGPIOValue_middle);
    return exports;
}
static napi_module g_serialHelper_Module = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = init,
    .nm_modname = "serialhelper",
    .nm_priv = ((void *)0),
    .reserved = {(void *)0},
};
extern "C" __attribute__((constructor)) void Register_serialHelper_Module(void)
{
    napi_module_register(&g_serialHelper_Module);
}

eTS调用接口验证。

import serialHelper from "libserialhelper.so"
...
//打开串口this.tty /dev/ttyXRUSB0
serialHelper.openSerial(this.tty).then(()=>{
  HiLog.i(TAG, "serial openSerial " + this.tty + " success")
  this.status = '开'
}).catch((error)=> {
  HiLog.i(TAG, "openSerial " + this.tty + " failed:" + error)
});
...
//设置为异步
serialHelper.on("/dev/ttyXRUSB0", (data) => {
  var dataString = "";
  for (var i = 0; i < data.length; i++) {
    dataString += String.fromCharCode(data[i]);
  }
  HiLog.i(TAG, "ttyXRUSB0 len:" + data.length + " data:" + dataString);
})

应用启动后点击"打开/dev/ttyXRUSB0"按钮查看输出日志,出现serialport_client与serial_service_impl标志,表示访问串口服务成功。

#物联网征文# 【系统服务】- OpenHarmony 串口服务访问-开源基础软件社区

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK