项目介绍

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

一、开发环境准备

安装OpenHarmony SDK

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

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

二、创建eTS项目

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

三、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;

function openSerial(dev:string): Promise;

/**

* Close serial port.

* @param dev Indicates the serial port dev.

*/

function closeSerial(dev:string, callback: AsyncCallback): void;

function closeSerial(dev:string): Promise;

}

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库,并且实现具体的异步回调功能

将libserialport_service_api.z.so复制到entry/libs/armeabi-a7v目录 将库的头文件复制到entry/src/main/cpp/include目录 继承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(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 pxt = std::make_shared(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标志,表示访问串口服务成功

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

入门必看:https://qr21.cn/FV7h05

应用开发导读(ArkTS)……

HarmonyOS 概念:https://qr21.cn/FV7h05

系统定义技术架构技术特性系统安全

如何快速入门?:https://qr21.cn/FV7h05

基本概念构建第一个ArkTS应用构建第一个JS应用……

开发基础知识:https://qr21.cn/FV7h05

应用基础知识配置文件应用数据管理应用安全管理应用隐私保护三方应用调用管控机制资源分类与访问学习ArkTS语言……

基于ArkTS 开发:https://qr21.cn/FV7h05

1.Ability开发 2.UI开发 3.公共事件与通知 4.窗口管理 5.媒体 6.安全 7.网络与链接 8.电话服务 9.数据管理 10.后台任务(Background Task)管理 11.设备管理 12.设备使用信息统计 13.DFX 14.国际化开发 15.折叠屏系列 16.……

精彩内容

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。