天天看點

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

【本文正在參與51CTO HarmonyOS技術社群創作者激勵計劃-星光計劃2.0】

作者:周希元

(目錄)

1. 開發環境

硬體:Hi3516DV300開發闆

軟體:OpenHarmony3.0系統

工具:DevEco Studio 3.0

2. 功能簡介

OpenHarmony3.0采用了方舟開發架構arkUI,支援了基于TS擴充的聲明式開發範式eTS,本文使用ets開發語言,構造一個應用程式,實作通過上層HAP控制底層LED燈的亮與滅。

3. 實作原理

如果在Android上實作,需要通過java調用jni實作對底層的通路。但是在OpenHarmony上,HAP采用ets語言開發,沒有發現嵌入到HAP當中的類JNI語言,但是系統也提供了一個通路底層的機制,叫做NAPI,不過這部分是在系統層實作的,不随HAP一起釋出。我們想要實作控制LED燈的功能,是在NAPI部分通過C語言實作的,然後編譯為xxx.z.so動态庫,它向上層提供了一個控制接口。綠色LED燈對應GPIO2_3,計算出編号:2*8+3=19,是以直接控制gpio19下的value值就可以控制LED燈亮滅了。

4. 具體實作

整個功能的實作分為了上層HAP應用開發和底層.z.so庫的開發兩部分。

4.1 應用的開發

1.在HUAWEI DevEco Studio中,建立一個 [Standard]Empty Ability ,

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

開發語言選擇 “eTS”,可以注意到API Version僅支援7,說明是在OpenHarmony3中新支援的,也僅在OpenHarmony3中支援,這些功能實際上都是測試版本,穩定了之後就會在HarmonyOS中使用了,但目前還沒有釋出。

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

工程建立完畢後,我直接在pages目錄結構下右擊建立了一個ets page,取名led

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

我們頁面的樣式、布局和控制全都在led.ets這個檔案裡了,不再像js分為css、hml和js三個檔案。

Led.ets 檔案内容

import led from '@ohos.led'

@Entry
@Component
struct Led {
  @State private imgpath: string = 'app.media.ledoff'
  @State private isShow: boolean= false

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Text('LED 燈控制')
        .fontSize(25)
        .fontWeight(FontWeight.Bold)
        .margin({bottom: 30})
      Image($r('app.media.ledoff'))
        .objectFit(ImageFit.Contain)
        .width(150)
        .height(150)
        .visibility(this.isShow ? Visibility.None : Visibility.Visible)
      Image($r('app.media.ledon'))
        .objectFit(ImageFit.Contain)
        .width(150)
        .height(150)
        .visibility(this.isShow ? Visibility.Visible : Visibility.None)

      Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) {
        Button('關閉', { type: ButtonType.Capsule, stateEffect: true }).backgroundColor(0x317aff).width(150).height(50).backgroundColor("#aaaaaa")
          .onClick((event: ClickEvent) => {
            this.isShow = false

            led.switchLed(19, 0);

          })
        Button('打開', { type: ButtonType.Capsule, stateEffect: true }).backgroundColor(0x317aff).width(150).height(50)
        .onClick((event: ClickEvent) => {
          this.isShow = true

          led.switchLed(19, 1);

        })

      }.width("100%")
      .margin({ top: 50 })
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }
}
           

放了兩個圖檔,表示LED燈狀态的,放在了代碼的entry\src\main\resources\phone\media目錄,

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

導入的ohos.led 庫,是自己添加的NAPI層的動态庫,後面會繼續介紹。

在config.json檔案中,記得把led.ets放到js部分pages數組的第一位,因為它是要顯示的首頁面。

代碼中使用了兩個Button元件,一個打開,一個關閉,因為在ets中還沒有類似js中的switch的元件,

頁面中有兩個image元件,分别顯示打開和關閉的圖像,通過設定visibility屬性來切換狀态,本來想通過動态設定image的源來改變圖像内容,但沒找到有效的方法,應該是支援的,隻是自己還沒了解怎麼用。

編譯前記得一定要設定簽名,否則編譯出來的程式無法安裝,

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

最後可以編譯程式了,

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

生成的最終HAP在 build\outputs\hap\debug\phone\entry-debug-standard-ark-signed.hap

4.2 動态庫的開發

動态庫需要在OpenHarmony源碼中添加和編譯,本文使用的是OpenHarmony3.0源碼,

在foundation/ace/napi/sample目錄下,複制一份native_module_demo,重命名為native_module_led,裡面的檔案也相應的修改名字,注意檔案裡調用也相應的修改成正确的名字,否則編譯會報錯。

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

主要修改的檔案有,

foundation/ace/napi/sample/native_module_led/BUILD.gn

foundation/ace/napi/sample/native_module_led/native_module_led.cpp

foundation/ace/napi/BUILD.gn

目錄native_module_led下BUILD.gn檔案:

import("//build/ohos.gni")

ohos_shared_library("led") {
  include_dirs = [
    "//third_party/node/src",
    "//foundation/ace/napi/interfaces/kits",
  ]

  sources = [
    "led_javascript_class.cpp",
    "native_module_led.cpp",
  ]

  deps = [ "//foundation/ace/napi:ace_napi" ]

  relative_install_dir = "module"
  
  external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
  
  subsystem_name = "ace"
  part_name = "napi"
}
           

目錄native_module_led下native_module_led.cpp檔案修改部分摘要:

包含的頭檔案和宏定義,

#include <stdlib.h>     // standard library 标準庫函數頭檔案
#include <stdio.h>      // standard input output 标準輸入輸出函數
#include <stdint.h>     // 定義了擴充的整數類型和宏

#include <unistd.h>     // POSIX 系統 API 通路功能的頭檔案
#include <fcntl.h>      // unix标準中通用的頭檔案 define O_WRONLY and O_RDONLY  

// #include <string.h>
#define GPIO_DIR_IN (char*)"in"
#define GPIO_DIR_OUT (char*)"out"
#define GPIO_VAL_LOW 0
#define GPIO_VAL_HIGH 1
           

添加函數SwitchLed的具體實作,

static napi_value SwitchLed(napi_env env, napi_callback_info info)
{
    HILOG_INFO("hey, SwitchLed - 0");
    
    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = { nullptr };
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));

    NAPI_ASSERT(env, argc >= requireArgc, "Wrong number of arguments");

    napi_valuetype valuetype0;
    NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
    napi_valuetype valuetype1;
    NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));

    NAPI_ASSERT(env, valuetype0 == napi_number && valuetype1 == napi_number, "Wrong argument type. Numbers expected.");

    uint32_t gpio;
    NAPI_CALL(env, napi_get_value_uint32(env, args[0], &gpio));

    uint32_t val;
    NAPI_CALL(env, napi_get_value_uint32(env, args[1], &val));


	char direction[100] = {0};
    sprintf(direction,"echo out > /sys/class/gpio/gpio%d/direction", gpio);
    system(direction);

    char value[100] = {0};
    sprintf(value,"echo %d > /sys/class/gpio/gpio%d/value", val, gpio);
    system(value);
	
    napi_value sum;
    NAPI_CALL(env, napi_create_double(env, 1.0f, &sum));
    return sum;
}
           

初始化部分,

EXTERN_C_START
/*
 * function for module exports
 */
static napi_value Init(napi_env env, napi_value exports)
{
    /*
     * Properties define
     */
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_FUNCTION("add", Add),
        DECLARE_NAPI_FUNCTION("minus", Minus),
        DECLARE_NAPI_FUNCTION("switchLed", SwitchLed),
        DECLARE_NAPI_FUNCTION("TestPromise", TestPromise),
        DECLARE_NAPI_FUNCTION("TestPromiseOrAsyncCallback", TestPromiseOrAsyncCallback),
    };
    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));

    DemoJavascriptClassInit(env, exports);

    return exports;
}
EXTERN_C_END
           

子產品定義及注冊,

/*
 * Module define
 */
static napi_module ledModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "led",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};
/*
 * Module register function
 */
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
    napi_module_register(&ledModule);
}
           

目錄napi下BUILD.gn檔案,

group("napi_packages_test") {
  testonly = true

  deps = [
    "sample/native_module_demo:demo",
    "sample/native_module_netserver:netserver",
    "sample/native_module_storage:storage",
"test/unittest:unittest",
"sample/native_module_led:led",
  ]

  if (is_standard_system) {
    deps += [ "sample/native_module_ability:ability" ]
  }
}
           

最後在源碼根目錄下執行編譯指令,

$./build.sh --product-name Hi3516DV300 --build-target make_test

生成的檔案為

out/ohos-arm-release/ace/napi/libled.z.so

5. 系統設定

需要授予應用通路gpio下export檔案的權限,

device/hisilicon/hi3516dv300/build/rootfs/init.Hi3516DV300.cfg

"name" : "boot",
            "cmds" : [
                "write /sys/class/gpio/export 19",
                "chmod 777 /sys/class/gpio/gpio19/direction",
                "chmod 777 /sys/class/gpio/gpio19/value",
           

6. 系統部署

6.1 拷貝動态庫

生成的.z.so動态庫已經拷貝到PC上E:\libled.z.so

PC序列槽控制台:

#mount -o remount,rw /

PC指令視窗cmd:

E:>hdc_std file send E:\libled.z.so /system/lib/module/

PC序列槽控制台:

#chmod 666 /system/lib/module/libled.z.so

6.2 安裝應用

PC指令視窗cmd:

E:>hdc_std install E:\Projects\HarmonyProject\MyLed\build\outputs\hap\debug\phone\entry-debug-standard-ark-signed.hap

7. 應用測試

點選打開按鈕,LED圖示變綠,同時LED燈亮,

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

點選關閉按鈕,LED圖示變灰,同時LED燈滅。

#星光計劃2.0# OpenHarmony3.0上采用ets開發HAP控制LED燈

想了解更多關于鴻蒙的内容,請通路:

繼續閱讀