用鸿蒙开发AI应用(七)触摸屏控制LED

开发
文章由鸿蒙社区产出,想要了解更多内容请前往:51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com/#zz

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/#zz

前言

上一篇,我们体验了一下鸿蒙上的界面的开发流程,这一篇我们继续深入一点点,尝试打通从用户态UI到内核态HDF之间的联系。其中涉及到的调用关系比较复杂,建议在“用鸿蒙开发AI应用(五)HDF 驱动补光灯”的基础上阅读本文,HDF的相关细节这里就不在赘述了。

背景知识

用户程序框架子系统包含两个大的模块:Ability子系统和包管理子系统。

1. Ability子系统


1.1 Ability

Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件,一个应用可以包含一个或多个Ability。Ability分为两种类型:Page类型的Ability和Service类型的Ability

Page类型的Ability:带有界面,为用户提供人机交互的能力。

Service类型的Ability:不带界面,为用户提供后台任务机制。

1.2 AbilitySlice

AbilitySlice是单个页面及其控制逻辑的总和,是Page类型Ability特有的组件,一个Page类型的Ability可以包含多个AbilitySlice,此时,这些页面提供的业务能力应当是高度相关的。

1.3 生命周期

生命周期是Ability被调度到启动、激活、隐藏和退出等各个状态的的统称。


Ability生命周期各状态解析:

UNINITIALIZED:未初始状态,为临时状态,Ability被创建后会由UNINITIALIZED状态进入INITIAL状态;

INITIAL:初始化状态,也表示停止状态,表示当前Ability未运行,调用Start后进入INACTIVE,同时回调开发者的OnStart生命周期回调;

INACTIVE:未激活状态,表示当前窗口已显示但是无焦点状态,由于Window暂未支持焦点的概念,当前状态与ACTIVE一致。

ACTIVE:前台激活状态,表示当前窗口已显示,并获取焦点,Ability在退到后台之前先由ACTIVE状态进入INACTIVE状态;

BACKGROUND: 后台状态,表示当前Ability退到后台,Ability在被销毁后由BACKGROUND状态进入INITIAL状态,或者重新被激活后由BACKGROUND状态进入ACTIVE状态。

1.4 AbilityLoader

AbilityLoader负责注册和加载开发者Ability的模块。开发者开发的Ability先要调用AbilityLoader的注册接口注册到框架中,接着Ability启动时会被实例化。

1.5 AbilityManager

AbilityManager负责AbilityKit和Ability管理服务进行IPC的通信。

1.6 EventHandler

EventHandler是AbilityKit提供给开发者的用于在Ability中实现线程间通信的一个模块。

1.7 Ability运行管理服务

Ability运行管理服务是用于协调各Ability运行关系、及生命周期进行调度的系统服务。

其中,服务启动模块负责Ability管理服务的启动、注册等。

服务接口管理模块负责Ability管理服务对外能力的管理。

进程管理模块负责Ability应用所在进程的启动和销毁、及其进程信息维护等功能。Ability栈管理模块负责维护各个Ability之间跳转的先后关系。

生命周期调度模块是Ability管理服务根据系统当前的操作调度Ability进入相应的状态的模块。

连接管理模块是Ability管理服务对Service类型Ability连接管理的模块。

1.8 AppSpawn

AppSpawn是负责创建Ability应用所在进程的系统服务,该服务有较高的权限,为Ability应用设置相应的权限,并预加载一些通用的模块,加速应用的启动。

2. 包管理子系统

包管理子系统,是OpenHarmony为开发者提供的安装包管理框架。

BundleKit:是包管理服务对外提供的接口,有安装/卸载接口、包信息查询接口、包状态变化监听接口。

包扫描器:用来解析本地预制或者安装的安装包,提取里面的各种信息,供管理子模块进行管理,持久化。

包安装子模块:安装,卸载,升级一个包;包安装服务一个单独进程的用于创建删除安装目录,具有较高的权限。

包管理子模块:管理安装包相关的信息,存储持久化包信息。

包安全管理子模块:签名检查、权限授予、权限管理。

HDF驱动LED(可选)

之前在内核中已经注册过一个led_driver驱动,并以led_service服务发布,这一节稍微重构一下代码,功能上没有变化,我们快速过一遍,熟悉HDF的可以自行跳过。

1. 业务代码

先新建头文件vendor\huawei\hdf\led\include\led_ctrl.h。

  1. #ifndef _LED_CTRL_H 
  2. #define _LED_CTRL_H 
  3.  
  4. #include "hdf_device_desc.h" 
  5. #include "hdf_log.h" 
  6. #include "device_resource_if.h" 
  7. #include "osal_io.h" 
  8. #include "osal_mem.h" 
  9. #include "gpio_if.h" 
  10. #include "osal_irq.h" 
  11. #include "osal_time.h" 
  12.  
  13. #ifdef __cplusplus 
  14. extern "C" { 
  15. #endif /* __cplusplus */ 
  16.  
  17. extern int32_t CtlLED(int mode); 
  18.  
  19. #ifdef __cplusplus 
  20. #endif /* __cplusplus */ 
  21.  
  22. #endif /* _LED_CTRL_H */ 

 再新建源文件 vendor\huawei\hdf\led\led_ctrl.c 

  1. #include "led_ctrl.h" 
  2.  
  3. #define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 
  4.  
  5. int32_t CtlLED(int mode) 
  6.     int32_t ret; 
  7.     uint16_t valRead; 
  8.     /* LED的GPIO管脚号 */ 
  9.     // uint16_t gpio = 5 * 8 + 1;  // 红外补光灯 
  10.     uint16_t gpio = 2 * 8 + 3;  // 绿色指示灯 
  11.     // uint16_t gpio = 3 * 8 + 4;  // 红色指示灯 
  12.  
  13.     /* 将GPIO管脚配置为输出 */ 
  14.     ret = GpioSetDir(gpio, GPIO_DIR_OUT); 
  15.     if (ret != 0) 
  16.     { 
  17.         HDF_LOGE("GpioSerDir: failed, ret %d\n", ret); 
  18.         return ret; 
  19.     } 
  20.  
  21.     if (mode == -1) 
  22.     { 
  23.         // 翻转输出口 
  24.         (void)GpioRead(gpio, &valRead); 
  25.         ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW); 
  26.     } 
  27.     else 
  28.     { 
  29.         ret = GpioWrite(gpio, mode); 
  30.     } 
  31.  
  32.     if (ret != 0) 
  33.     { 
  34.         HDF_LOGE("GpioWrite: failed, ret %d\n", ret); 
  35.         return ret; 
  36.     } 
  37.     return ret; 

 先完成对绿色指示灯的控制逻辑。

2. 驱动实现

在 huawei/hdf 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led.c。

  1. #include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件 
  2. #include "hdf_log.h"         // HDF 框架提供的日志接口头文件 
  3. #include "led_ctrl.h" 
  4.  
  5. // #define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 
  6. #define LED_WRITE_READ 1       // 读写操作码1 
  7.  
  8. // Dispatch是用来处理用户态发下来的消息 
  9. int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) 
  10.     int32_t result = HDF_FAILURE; 
  11.     HDF_LOGE("Led driver dispatch"); 
  12.     if (client == NULL || client->device == NULL
  13.     { 
  14.         HDF_LOGE("Led driver device is NULL"); 
  15.         return HDF_ERR_INVALID_OBJECT; 
  16.     } 
  17.  
  18.     switch (cmdCode) 
  19.     { 
  20.     case LED_WRITE_READ: 
  21.         const char *recv = HdfSbufReadString(data); 
  22.         if (recv != NULL
  23.         { 
  24.             HDF_LOGI("recv: %s", recv); 
  25.             result = CtlLED(-1); 
  26.             // result = CtlLED(GPIO_VAL_HIGH); 
  27.             if (!HdfSbufWriteInt32(reply, result)) 
  28.             { 
  29.                 HDF_LOGE("replay is fail"); 
  30.             } 
  31.             return HdfDeviceSendEvent(client->device, cmdCode, data); 
  32.         } 
  33.         break; 
  34.  
  35.     default
  36.         break; 
  37.     } 
  38.     return result; 
  39.  
  40. //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架 
  41. int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject) 
  42.     if (deviceObject == NULL
  43.     { 
  44.         HDF_LOGE("Led driver bind failed!"); 
  45.         return HDF_ERR_INVALID_OBJECT; 
  46.     } 
  47.     static struct IDeviceIoService ledDriver = { 
  48.         .Dispatch = LedDriverDispatch, 
  49.     }; 
  50.  
  51.     deviceObject->service = (struct IDeviceIoService *)(&ledDriver); 
  52.     HDF_LOGD("Led driver bind success"); 
  53.     return HDF_SUCCESS; 
  54.  
  55.  
  56. // 驱动自身业务初始的接口 
  57. int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject) 
  58.     if (deviceObject == NULL
  59.     { 
  60.         HDF_LOGE("Led driver Init failed!"); 
  61.         return HDF_ERR_INVALID_OBJECT; 
  62.     } 
  63.     HDF_LOGD("Led driver Init success"); 
  64.     return HDF_SUCCESS; 
  65.  
  66. // 驱动资源释放的接口 
  67. void HdfLedDriverRelease(struct HdfDeviceObject *deviceObject) 
  68.     if (deviceObject == NULL
  69.     { 
  70.         HDF_LOGE("Led driver release failed!"); 
  71.         return
  72.     } 
  73.  
  74.     HDF_LOGD("Led driver release success"); 
  75.     return
  76.  
  77. // 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量 
  78. struct HdfDriverEntry g_ledDriverEntry = { 
  79.     .moduleVersion = 1, 
  80.     .moduleName = "led_driver"
  81.     .Bind = HdfLedDriverBind, 
  82.     .Init = HdfLedDriverInit, 
  83.     .Release = HdfLedDriverRelease, 
  84. }; 
  85.  
  86. // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 
  87. HDF_INIT(g_ledDriverEntry); 

 3. 驱动编译

在 huawei/hdf/led 目录下新建编译文件 Makefile。

  1. include $(LITEOSTOPDIR)/../../drivers/hdf/lite/lite.mk 
  2.  
  3. MODULE_NAME := hdf_led_driver 
  4. LOCAL_SRCS += led_ctrl.c \ 
  5.               led.c \ 
  6.                
  7. LOCAL_INCLUDE := ./include 
  8. LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror 
  9. include $(HDF_DRIVER) 

 4. 编译结果链接到内核镜像

修改 huawei/hdf/hdf_vendor.mk 文件,添加以下代码

  1. LITEOS_BASELIB += -lhdf_led_driver  #链接生成的静态库 
  2. LIB_SUBDIRS    += $(VENDOR_HDF_DRIVERS_ROOT)/led  #驱动代码Makefile的目录 

 5. 驱动配置

修改 vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs配置文件,添加驱动的设备描述。

  1. platform :: host { 
  2.     hostName = "platform_host";  // host名称,host节点是用来存放某一类驱动的容器 
  3.     priority = 50;  // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 
  4.  
  5.     device_led :: device {                  // led设备节点 
  6.         device0 :: deviceNode {             // led驱动的DeviceNode节点 
  7.             policy = 2;                     // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍 
  8.             priority = 100;                 // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 
  9.             preload = 0;                    // 驱动按需加载字段 
  10.             permission = 0666;              // 驱动创建设备节点权限 
  11.             moduleName = "led_driver";      // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 
  12.             serviceName = "led_service";    // 驱动对外发布服务的名称,必须唯一 
  13.             deviceMatchAttr = "led_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 
  14.         } 
  15.     }  

 编译用户程序框架子系统

1. 添加配置文件

在 build/lite/platform/hi3516dv300_liteos_a/platform.json中的subsystems字段下面添加appexecfwk和aafwk。

  1.   "subsystem""aafwk"
  2.   "components": [ 
  3.     { 
  4.       "component""ability"
  5.       "optional""true"
  6.       "dirs": [ 
  7.         "foundation/aafwk" 
  8.       ], 
  9.       "targets": [ 
  10.         "//foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite"
  11.         "//foundation/aafwk/frameworks/ability_lite:aafwk_abilityMain_lite"
  12.         "//foundation/aafwk/frameworks/abilitymgr_lite:aafwk_abilityManager_lite"
  13.         "//foundation/aafwk/services/abilitymgr_lite:aafwk_services_lite" 
  14.       ], 
  15.       "features": [ 
  16.         {"enable_ohos_appexecfwk_feature_ability""true"
  17.       ], 
  18.       "deps": { 
  19.         "components": [ 
  20.           "hilog_a"
  21.           "bundle_mgr"
  22.           "system_ability_manager"
  23.           "distributed_schedule"
  24.           "graphic"
  25.           "utils"
  26.           "ipc" 
  27.         ], 
  28.         "third_party": [ 
  29.           "cjson"
  30.           "bounds_checking_function" 
  31.         ] 
  32.       } 
  33.     } 
  34.   ] 
  35. }, 
  36.  
  37.   "subsystem""appexecfwk"
  38.   "components": [ 
  39.     { 
  40.       "component""bundle_mgr"
  41.       "optional""true"
  42.       "dirs": [ 
  43.         "foundation/appexecfwk" 
  44.       ], 
  45.       "targets": [ 
  46.         "//foundation/appexecfwk/services/bundlemgr_lite:appexecfwk_services_lite"
  47.         "//foundation/appexecfwk/frameworks/bundle_lite:appexecfwk_kits_lite" 
  48.       ], 
  49.       "features": [], 
  50.       "deps": { 
  51.         "components": [ 
  52.           "iam"
  53.           "app_verify"
  54.           "hilog_a"
  55.           "system_ability_manager"
  56.           "global_resource_manager"
  57.           "graphic"
  58.           "utils" 
  59.         ], 
  60.         "third_party": [ 
  61.           "cjson"
  62.           "zlib" 
  63.         ] 
  64.       } 
  65.     } 
  66.   ] 
  67. }, 

 2. 添加编译文件

新建build\lite\config\subsystem\aafwk\BUILD.gn文件,

  1. import("//build/lite/config/subsystem/lite_subsystem.gni"
  2.  
  3. lite_subsystem("aafwk") { 
  4.     subsystem_components = [ 
  5.         "//foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite"
  6.         "//foundation/aafwk/frameworks/abilitymgr_lite:aafwk_abilityManager_lite"
  7.         "//foundation/aafwk/services/abilitymgr_lite:aafwk_services_lite"
  8.     ] 

 新建/build/lite/config/subsystem/appexecfwk/BUILD.gn文件,

  1. import("//build/lite/config/subsystem/lite_subsystem.gni"
  2.  
  3. lite_subsystem("appexecfwk") { 
  4.     subsystem_components = [ 
  5.         "//foundation/appexecfwk/kits/appkit_lite:appexecfwk_kit_lite"
  6.         "//foundation/appexecfwk/services/bundlemgr_lite:appexecfwk_services_lite"
  7.     ] 

 3. 运行管理服务

用户程序框架有两个系统服务ability管理服务(abilityms)和(bundlems),两系统服务运行于foundation进程中。

abilityms和bundlems注册到sa_manager中,sa_manager运行于foundation进程中,sa_manager为abilityms和bundlems创建线程运行环境。

在foundation/distributedschedule/services/safwk_lite/BUILD.gn中添加对abilityms和bundlems

  1. deps = [ 
  2.     "..."
  3. if (ohos_kernel_type == "liteos_a") { 
  4.     deps += [ 
  5.         "..."
  6.         "//foundation/aafwk/services/abilitymgr_lite:abilityms"
  7.         "//foundation/appexecfwk/services/bundlemgr_lite:bundlems"
  8.         "..."
  9.     ] 

 基于AbilityKit开发的Ability

1. 主页面实现

新建源文件applications\sample\camera\myLedApp\src\main_ability.cpp

  1. #include "main_ability.h" 
  2.  
  3. namespace OHOS { 
  4. REGISTER_AA(MainAbility) 
  5.  
  6. void MainAbility::OnStart(const Want &want) 
  7.     printf("MainAbility::OnStart\n"); 
  8.     SetMainRoute("MainAbilitySlice"); 
  9.  
  10.     Ability::OnStart(want); 

 2. 分片页面

2.1 定义控件常量

新建源文件main_ability_slice.cpp, 屏幕大小为960x480

  1. #include "main_ability_slice.h" 
  2.  
  3. #include "ability_manager.h" 
  4. #include "components/ui_label.h" 
  5. #include "components/ui_label_button.h" 
  6. namespace OHOS 
  7. REGISTER_AS(MainAbilitySlice) 
  8.  
  9. constexpr static int BUTTON1_POSITION_X = 380; 
  10. constexpr static int BUTTON1_POSITION_Y = 200; 
  11. constexpr static int BUTTON_WIDTH = 200; 
  12. constexpr static int BUTTON_HEIGHT = 80; 
  13. constexpr static int ROOT_VIEW_POSITION_X = 0; 
  14. constexpr static int ROOT_VIEW_POSITION_Y = 0; 
  15. constexpr static int ROOT_VIEW_WIDTH = 960; 
  16. constexpr static int ROOT_VIEW_HEIGHT = 480; 
  17. constexpr static uint8_t ROOT_VIEW_OPACITY = 255; 
  18. constexpr static uint8_t FONT_ID = 10; 
  19.  
  20. constexpr static int BUTTON1_POSITION_X = 380; 
  21. constexpr static int BUTTON1_POSITION_Y = 200; 
  22. constexpr static int BUTTON_WIDTH = 200; 
  23. constexpr static int BUTTON_HEIGHT = 80; 
  24. constexpr static int ROOT_VIEW_POSITION_X = 0; 
  25. constexpr static int ROOT_VIEW_POSITION_Y = 0; 
  26. constexpr static int ROOT_VIEW_WIDTH = 960; 
  27. constexpr static int ROOT_VIEW_HEIGHT = 480; 
  28. constexpr static uint8_t ROOT_VIEW_OPACITY = 255; 
  29. constexpr static uint8_t FONT_ID = 10; 
  30. } // namespace OHOS 

 2.2 创建按钮和布局

在生命周期函数OnStart中,全屏放置一个rootView_,居中位置放置一个按钮button1。

  1. void MainAbilitySlice::OnStart(const Want &want) 
  2.     printf("MainAbilitySlice::OnStart\n"); 
  3.     AbilitySlice::OnStart(want); 
  4.      
  5.     auto button1 = new UILabelButton(); 
  6.     button1->SetPosition(BUTTON1_POSITION_X, BUTTON1_POSITION_Y); 
  7.     button1->SetText("翻转 LED"); 
  8.     button1->Resize(BUTTON_WIDTH, BUTTON_HEIGHT); 
  9.     button1->SetFontId(FONT_ID); 
  10.     button1->SetStyle(STYLE_TEXT_COLOR, Color::Black().full); 
  11.     button1->SetStyle(STYLE_TEXT_OPA, ROOT_VIEW_OPACITY); 
  12.     button1->SetStyle(STYLE_BACKGROUND_OPA, ROOT_VIEW_OPACITY); 
  13.  
  14.     rootView_ = RootView::GetWindowRootView(); 
  15.     rootView_->SetPosition(ROOT_VIEW_POSITION_X, ROOT_VIEW_POSITION_Y); 
  16.     rootView_->Resize(ROOT_VIEW_WIDTH, ROOT_VIEW_HEIGHT); 
  17.  
  18.     rootView_->Add(button1); 
  19.     SetUIContent(rootView_); 

 2.3 实现驱动消息机制

这里顺便提一下,文档中DevSvcManagerClntGetService接口仅在内核态有效,可以方便的获取服务并直接调用。鸿蒙作为微内核的OS,想从用户态调用内核态函数,要么用框架的消息机制,要么自己用中断服务实现。

  1. #define LED_WRITE_READ 1 
  2. #define LED_SERVICE "led_service" 
  3.  
  4. static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data) 
  5.     const char *string = HdfSbufReadString(data); 
  6.     if (string == NULL
  7.     { 
  8.         printf("fail to read string in event data\n"); 
  9.         return HDF_FAILURE; 
  10.     } 
  11.     printf("%s: dev event received: %u %s\n", (char *)priv, id, string); 
  12.  
  13.     return HDF_SUCCESS; 
  14.  
  15. static int SendEvent(struct HdfIoService *serv, const char *eventData) 
  16.     int ret = 0; 
  17.     struct HdfSBuf *data = HdfSBufObtainDefaultSize(); 
  18.     if (data == NULL
  19.     { 
  20.         printf("fail to obtain sbuf data\n"); 
  21.         return 1; 
  22.     } 
  23.  
  24.     struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); 
  25.     if (reply == NULL
  26.     { 
  27.         printf("fail to obtain sbuf reply\n"); 
  28.         ret = HDF_DEV_ERR_NO_MEMORY; 
  29.         HdfSBufRecycle(data); 
  30.         return ret; 
  31.     } 
  32.  
  33.     if (!HdfSbufWriteString(data, eventData)) 
  34.     { 
  35.         printf("fail to write sbuf\n"); 
  36.         ret = HDF_FAILURE; 
  37.         HdfSBufRecycle(data); 
  38.         HdfSBufRecycle(reply); 
  39.         return ret; 
  40.     } 
  41.  
  42.     ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply); 
  43.     if (ret != HDF_SUCCESS) 
  44.     { 
  45.         printf("fail to send service call\n"); 
  46.         HdfSBufRecycle(data); 
  47.         HdfSBufRecycle(reply); 
  48.         return ret; 
  49.     } 
  50.  
  51.     int replyData = 0; 
  52.     if (!HdfSbufReadInt32(reply, &replyData)) 
  53.     { 
  54.         printf("fail to get service call reply\n"); 
  55.         ret = HDF_ERR_INVALID_OBJECT; 
  56.         HdfSBufRecycle(data); 
  57.         HdfSBufRecycle(reply); 
  58.         return ret; 
  59.     } 
  60.     printf("Get reply is: %d\n", replyData); 
  61.  
  62.     HdfSBufRecycle(data); 
  63.     HdfSBufRecycle(reply); 
  64.     return ret; 

 2.4 加入点击事件

每次点击按钮,向内核态发送一次消息。

  1. auto onClick = [this](UIView &view, const Event &event) -> bool { 
  2.     printf("led button pressed\n"); 
  3.  
  4.     struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE, 0); 
  5.     if (serv == NULL
  6.     { 
  7.         printf("fail to get service %s\n", LED_SERVICE); 
  8.         return false
  9.     } 
  10.  
  11.     static struct HdfDevEventlistener listener = { 
  12.         .callBack = OnDevEventReceived, 
  13.         .priv = (void *)"Service0"}; 
  14.  
  15.     if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) 
  16.     { 
  17.         printf("fail to register event listener\n"); 
  18.         return false
  19.     } 
  20.  
  21.     const char *send_cmd = "toggle LED"
  22.  
  23.     if (SendEvent(serv, send_cmd)) 
  24.     { 
  25.         printf("fail to send event\n"); 
  26.         return false
  27.     } 
  28.  
  29.     if (HdfDeviceUnregisterEventListener(serv, &listener)) 
  30.     { 
  31.         printf("fail to  unregister listener\n"); 
  32.         return false
  33.     } 
  34.  
  35.     HdfIoServiceRecycle(serv); 
  36.  
  37.     return true
  38. }; 

 2.5 注销页面

在生命周期函数OnStop中,删除所有节点,回收系统资源。

  1. void DeleteViewChildren(UIView *view
  2.     if (view == nullptr) { 
  3.         return
  4.     } 
  5.     while (view != nullptr) { 
  6.         UIView *tempView = view
  7.         view = view->GetNextSibling(); 
  8.         if (tempView->IsViewGroup()) { 
  9.             DeleteViewChildren(dynamic_cast<UIViewGroup *>(tempView)->GetChildrenHead()); 
  10.         } 
  11.         if (tempView->GetParent()) { 
  12.             dynamic_cast<UIViewGroup *>(tempView->GetParent())->Remove(tempView); 
  13.         } 
  14.         delete tempView; 
  15.     } 
  16.  
  17. void MainAbilitySlice::OnStop() 
  18.     printf("MainAbilitySlice::OnStop\n"); 
  19.     AbilitySlice::OnStop(); 
  20.     DeleteViewChildren(rootView_); 

 3. 编译配置

新增 applications\sample\camera\myLedApp\BUILD.gn文件

  1. import("//build/lite/config/component/lite_component.gni"
  2. import("//build/lite/config/subsystem/aafwk/config.gni"
  3.  
  4. HDF_FRAMEWORKS = "//drivers/hdf/frameworks" 
  5. src_path = "//applications/sample/camera/myLedApp/src" 
  6.  
  7. lite_library("ledability") { 
  8.     target_type = "shared_library" 
  9.     ldflags = [ 
  10.         "-shared"
  11.     ] 
  12.     sources = [ 
  13.         "${src_path}/main_ability.cpp"
  14.         "${src_path}/main_ability_slice.cpp"
  15.     ] 
  16.  
  17.     include_dirs = [ 
  18.         "."
  19.         "//foundation/aafwk/frameworks/ability_lite/example/entry/src/main/cpp"
  20.         "//foundation/aafwk/interfaces/innerkits/abilitymgr_lite"
  21.         "//foundation/aafwk/interfaces/kits/ability_lite"
  22.         "//foundation/aafwk/interfaces/kits/want_lite"
  23.         "//foundation/appexecfwk/interfaces/kits/bundle_lite"
  24.         "//foundation/appexecfwk/utils/bundle_lite"
  25.         "//foundation/communication/interfaces/kits/ipc_lite"
  26.         "//foundation/graphic/lite/interfaces/kits/config"
  27.         "//foundation/graphic/lite/interfaces/kits/ui"
  28.         "//foundation/graphic/lite/interfaces/kits/utils"
  29.         "//kernel/liteos_a/kernel/common"
  30.         "//kernel/liteos_a/kernel/include"
  31.         "//drivers/hdf/lite/include/host"
  32.         "$HDF_FRAMEWORKS/ability/sbuf/include",         
  33.         "$HDF_FRAMEWORKS/core/shared/include"
  34.         "$HDF_FRAMEWORKS/core/host/include"
  35.         "$HDF_FRAMEWORKS/core/master/include"
  36.         "$HDF_FRAMEWORKS/include/core"
  37.         "$HDF_FRAMEWORKS/include/utils"
  38.         "$HDF_FRAMEWORKS/utils/include"
  39.         "$HDF_FRAMEWORKS/include/osal"
  40.         "//kernel/liteos_a/platform/include"
  41.         "$HDF_FRAMEWORKS/adapter/syscall/include"
  42.         "$HDF_FRAMEWORKS/adapter/vnode/include"
  43.     ] 
  44.  
  45.     deps = [ 
  46.         "//foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite"
  47.         "//drivers/hdf/lite/manager:hdf_core"
  48.         "//drivers/hdf/lite/adapter/osal/posix:hdf_posix_osal"
  49.     ] 
  50.  
  51.     defines = [ 
  52.         "OHOS_APPEXECFWK_BMS_BUNDLEMANAGER"
  53.     ] 
  54.  
  55.     if (enable_ohos_appexecfwk_feature_ability == true) { 
  56.         deps += [ 
  57.             "//foundation/graphic/lite/frameworks/ui:ui"
  58.         ] 
  59.         defines += [ 
  60.             "ENABLE_WINDOW=1"
  61.             "ABILITY_WINDOW_SUPPORT" 
  62.         ] 
  63.     } 
  64.     output_dir = "$root_out_dir/dev_tools/led" 

 4. 应用配置文件

新建 applications\sample\camera\myLedApp\config.json

  1.     "app": { 
  2.         "bundleName""com.bluishfish.ledability"
  3.         "vendor""huawei"
  4.         "version": { 
  5.             "code": 1, 
  6.             "name""1.0" 
  7.         }, 
  8.        "apiVersion": { 
  9.           "compatible": 3, 
  10.           "target": 3 
  11.        } 
  12.     }, 
  13.     "deviceConfig": { 
  14.         "default": { 
  15.             "keepAlive"false 
  16.         } 
  17.     }, 
  18.     "module": { 
  19.         "deviceType": [ 
  20.             "smartVision" 
  21.         ], 
  22.         "distro": { 
  23.             "deliveryWithInstall"true
  24.             "moduleName""ledability"
  25.             "moduleType""entry" 
  26.         }, 
  27.         "abilities": [{ 
  28.             "name""MainAbility"
  29.             "icon""assets/entry/resources/base/media/icon.png"
  30.             "label""Led Ability"
  31.             "launchType""standard"
  32.             "type""page"
  33.             "visible"true 
  34.         } 
  35.         ] 
  36.     } 

 

5. 板级编译配置

复制 build/lite/product/ipcamera_hi3516dv300.json,改名为my_hi3516dv300在子系统里加入

  1.   "ohos_version""OpenHarmony 1.0"
  2.   "board""hi3516dv300"
  3.   "kernel""liteos_a"
  4.   "compiler""clang"
  5.   "subsystem": [ 
  6.     { 
  7.       "name""aafwk"
  8.       "component": [ 
  9.             "......"
  10.             { "name""ability_led""dir""//applications/sample/camera/myLedApp:ledability""features": []} 
  11.         ] 
  12. "......" 

 6. 编译应用

  1. python build.py my_hi3516dv300 -b debug 

 

将系统烧录到开发板上。

7. 打包应用

在 assets\entry\resources\base\media\目录下放置一个icon.png作为启动图标。

将applications\sample\camera\myLedApp\config.json和 Z:\openharmony\out\my_hi3516dv300\dev_tools\led\libledability.so打包压缩成zip包


改名为ledability.hap ,复制到NFS共享目录

8. 安装Hap

  1. mkdir nfs 
  2. mount 192.168.1.57:/nfs /nfs nfs 
  3. ./nfs/dev_tools/bin/bm set -s disable 
  4. ./nfs/dev_tools/bin/bm install -p ./nfs/ledability.hap 

 

9. 运行程序

  1. ./nfs/dev_tools/bin/aa start -p com.bluishfish.ledability -n MainAbility 

 


完美!

总结

整理一下思路,

我们先用AbilityKit绘制Ability页面,在其button1上绑定一个按钮事件;

触发后,由用户子系统寻找到led_server服务,向HDF框架发送消息;

内核驱动led_driver接收到消息后,调用底层GPIO控制LED翻转,并将操作状态以reply消息的形式传回用户侧;

后续可以接着根据返回状态更新下界面。

好了,在此基础上美化下界面,接个继电器做个智能家居的App应该不是难事了。

源码下载


PS:最近收到了社区之星的礼物,还有前沿新书《鸿蒙应用开发实战》,感谢一下小编的辛苦工作。


下一篇预告

用C++来写UI开发效率总是不如java和js高的,

何况还没法用上DevEco Studio辅助设计,

下一篇我们尝试实现更多的设备能力,

并用JS框架来访问内核层,

敬请期待...


想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/#zz

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2009-07-01 09:27:36

触摸屏驱动WinCE

2009-12-10 10:25:12

Linux触摸屏驱动

2013-11-27 15:59:21

微软Kinect触摸屏

2020-05-22 09:45:24

谷歌AI耳机线

2019-04-02 16:44:22

2010-09-02 08:46:16

苹果触摸屏

2012-02-28 14:07:17

Android触摸屏手势识别

2012-05-14 15:11:23

戴尔一体机

2013-01-11 10:08:43

PC操作系统

2012-04-10 09:09:21

2012-07-19 09:04:29

Windows 8Office 2013

2011-10-19 15:34:13

惠普一体机

2011-06-17 09:34:02

Qt 4.5.1 Sqlite 移植

2021-01-19 12:46:45

鸿蒙HarmonyOSHelloworld

2011-06-17 09:19:03

Qt 4.5.1 Sqlite 移植

2009-09-03 16:17:45

2011-11-15 11:04:14

黑莓BBX

2013-07-09 13:38:13

触摸屏用户体验UI设计

2011-07-12 10:10:58

2011-11-01 10:11:52

后PC微软
点赞
收藏

51CTO技术栈公众号