基于鸿蒙开发的触摸屏控制LED

这一篇我们继续深入一点点,尝试打通从用户态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. 业务代码
先新建头文件vendorhuaweihdfledincludeled_ctrl.h。
#ifndef _led_ctrl_h#define _led_ctrl_h#include hdf_device_desc.h#include hdf_log.h#include device_resource_if.h#include osal_io.h#include osal_mem.h#include gpio_if.h#include osal_irq.h#include osal_time.h#ifdef __cplusplusextern c {#endif /* __cplusplus */extern int32_t ctlled(int mode);#ifdef __cplusplus}#endif /* __cplusplus */#endif /* _led_ctrl_h */ 再新建源文件 vendorhuaweihdfledled_ctrl.c
#include led_ctrl.h#define hdf_log_tag led_driver // 打印日志所包含的标签,如果不定义则用默认定义的hdf_tag标签int32_t ctlled(int mode){ int32_t ret; uint16_t valread; /* led的gpio管脚号 */ // uint16_t gpio = 5 * 8 + 1; // 红外补光灯 uint16_t gpio = 2 * 8 + 3; // 绿色指示灯 // uint16_t gpio = 3 * 8 + 4; // 红色指示灯 /* 将gpio管脚配置为输出 */ ret = gpiosetdir(gpio, gpio_dir_out); if (ret != 0) { hdf_loge(gpioserdir: failed, ret %d, ret); return ret; } if (mode == -1) { // 翻转输出口 (void)gpioread(gpio, &valread); ret = gpiowrite(gpio, (valread == gpio_val_low) ? gpio_val_high : gpio_val_low); } else { ret = gpiowrite(gpio, mode); } if (ret != 0) { hdf_loge(gpiowrite: failed, ret %d, ret); return ret; } return ret;} 先完成对绿色指示灯的控制逻辑。
2. 驱动实现 在 huawei/hdf 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led.c。
#include hdf_device_desc.h // hdf框架对驱动开放相关能力接口的头文件#include hdf_log.h // hdf 框架提供的日志接口头文件#include led_ctrl.h// #define hdf_log_tag led_driver // 打印日志所包含的标签,如果不定义则用默认定义的hdf_tag标签#define led_write_read 1 // 读写操作码1// dispatch是用来处理用户态发下来的消息int32_t leddriverdispatch(struct hdfdeviceioclient *client, int cmdcode, struct hdfsbuf *data, struct hdfsbuf *reply){ int32_t result = hdf_failure; hdf_loge(led driver dispatch); if (client == null || client->device == null) { hdf_loge(led driver device is null); return hdf_err_invalid_object; } switch (cmdcode) { case led_write_read: const char *recv = hdfsbufreadstring(data); if (recv != null) { hdf_logi(recv: %s, recv); result = ctlled(-1); // result = ctlled(gpio_val_high); if (!hdfsbufwriteint32(reply, result)) { hdf_loge(replay is fail); } return hdfdevicesendevent(client->device, cmdcode, data); } break; default: break; } return result;}//驱动对外提供的服务能力,将相关的服务接口绑定到hdf框架int32_t hdfleddriverbind(struct hdfdeviceobject *deviceobject){ if (deviceobject == null) { hdf_loge(led driver bind failed!); return hdf_err_invalid_object; } static struct ideviceioservice leddriver = { .dispatch = leddriverdispatch, }; deviceobject->service = (struct ideviceioservice *)(&leddriver); hdf_logd(led driver bind success); return hdf_success;}// 驱动自身业务初始的接口int32_t hdfleddriverinit(struct hdfdeviceobject *deviceobject){ if (deviceobject == null) { hdf_loge(led driver init failed!); return hdf_err_invalid_object; } hdf_logd(led driver init success); return hdf_success;}// 驱动资源释放的接口void hdfleddriverrelease(struct hdfdeviceobject *deviceobject){ if (deviceobject == null) { hdf_loge(led driver release failed!); return; } hdf_logd(led driver release success); return;}// 定义驱动入口的对象,必须为hdfdriverentry(在hdf_device_desc.h中定义)类型的全局变量struct hdfdriverentry g_leddriverentry = { .moduleversion = 1, .modulename = led_driver, .bind = hdfleddriverbind, .init = hdfleddriverinit, .release = hdfleddriverrelease,};// 调用hdf_init将驱动入口注册到hdf框架中,在加载驱动时hdf框架会先调用bind函数,再调用init函数加载该驱动,当init调用异常时,hdf框架会调用release释放驱动资源并退出。hdf_init(g_leddriverentry); 3. 驱动编译 在 huawei/hdf/led 目录下新建编译文件 makefile。
include $(liteostopdir)/../../drivers/hdf/lite/lite.mkmodule_name := hdf_led_driverlocal_srcs += led_ctrl.c led.c local_include := ./includelocal_cflags += -fstack-protector-strong -wextra -wall -werrorinclude $(hdf_driver) 4. 编译结果链接到内核镜像 修改 huawei/hdf/hdf_vendor.mk 文件,添加以下代码
liteos_baselib += -lhdf_led_driver #链接生成的静态库lib_subdirs += $(vendor_hdf_drivers_root)/led #驱动代码makefile的目录 5. 驱动配置 修改 vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs配置文件,添加驱动的设备描述。
platform :: host { hostname = platform_host; // host名称,host节点是用来存放某一类驱动的容器 priority = 50; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 device_led :: device { // led设备节点 device0 :: devicenode { // led驱动的devicenode节点 policy = 2; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍 priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 preload = 0; // 驱动按需加载字段 permission = 0666; // 驱动创建设备节点权限 modulename = led_driver; // 驱动名称,该字段的值必须和驱动入口结构的modulename值一致 servicename = led_service; // 驱动对外发布服务的名称,必须唯一 devicematchattr = led_config; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 } } 编译用户程序框架子系统 1. 添加配置文件 在 build/lite/platform/hi3516dv300_liteos_a/platform.json中的subsystems字段下面添加appexecfwk和aafwk。
{ subsystem: aafwk, components: [ { component: ability, optional: true, dirs: [ foundation/aafwk ], targets: [ //foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite, //foundation/aafwk/frameworks/ability_lite:aafwk_abilitymain_lite, //foundation/aafwk/frameworks/abilitymgr_lite:aafwk_abilitymanager_lite, //foundation/aafwk/services/abilitymgr_lite:aafwk_services_lite ], features: [ {enable_ohos_appexecfwk_feature_ability: true} ], deps: { components: [ hilog_a, bundle_mgr, system_ability_manager, distributed_schedule, graphic, utils, ipc ], third_party: [ cjson, bounds_checking_function ] } } ]},{ subsystem: appexecfwk, components: [ { component: bundle_mgr, optional: true, dirs: [ foundation/appexecfwk ], targets: [ //foundation/appexecfwk/services/bundlemgr_lite:appexecfwk_services_lite, //foundation/appexecfwk/frameworks/bundle_lite:appexecfwk_kits_lite ], features: [], deps: { components: [ iam, app_verify, hilog_a, system_ability_manager, global_resource_manager, graphic, utils ], third_party: [ cjson, zlib ] } } ]}, 2. 添加编译文件 新建buildliteconfigsubsystemaafwkbuild.gn文件,
import(//build/lite/config/subsystem/lite_subsystem.gni)lite_subsystem(aafwk) { subsystem_components = [ //foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite, //foundation/aafwk/frameworks/abilitymgr_lite:aafwk_abilitymanager_lite, //foundation/aafwk/services/abilitymgr_lite:aafwk_services_lite, ]} 新建/build/lite/config/subsystem/appexecfwk/build.gn文件,
import(//build/lite/config/subsystem/lite_subsystem.gni)lite_subsystem(appexecfwk) { subsystem_components = [ //foundation/appexecfwk/kits/appkit_lite:appexecfwk_kit_lite, //foundation/appexecfwk/services/bundlemgr_lite:appexecfwk_services_lite, ]} 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
deps = [ ...,]if (ohos_kernel_type == liteos_a) { deps += [ ..., //foundation/aafwk/services/abilitymgr_lite:abilityms, //foundation/appexecfwk/services/bundlemgr_lite:bundlems, ..., ]} 基于abilitykit开发的ability 1. 主页面实现 新建源文件applicationssamplecameramyledappsrcmain_ability.cpp
#include main_ability.hnamespace ohos {register_aa(mainability)void mainability::onstart(const want &want){ printf(mainability::onstart); setmainroute(mainabilityslice); ability::onstart(want);} 2. 分片页面 2.1 定义控件常量 新建源文件main_ability_slice.cpp, 屏幕大小为960x480
#include main_ability_slice.h#include ability_manager.h#include components/ui_label.h#include components/ui_label_button.hnamespace ohos{register_as(mainabilityslice)constexpr static int button1_position_x = 380;constexpr static int button1_position_y = 200;constexpr static int button_width = 200;constexpr static int button_height = 80;constexpr static int root_view_position_x = 0;constexpr static int root_view_position_y = 0;constexpr static int root_view_width = 960;constexpr static int root_view_height = 480;constexpr static uint8_t root_view_opacity = 255;constexpr static uint8_t font_id = 10;constexpr static int button1_position_x = 380;constexpr static int button1_position_y = 200;constexpr static int button_width = 200;constexpr static int button_height = 80;constexpr static int root_view_position_x = 0;constexpr static int root_view_position_y = 0;constexpr static int root_view_width = 960;constexpr static int root_view_height = 480;constexpr static uint8_t root_view_opacity = 255;constexpr static uint8_t font_id = 10;} // namespace ohos 2.2 创建按钮和布局 在生命周期函数onstart中,全屏放置一个rootview_,居中位置放置一个按钮button1。
void mainabilityslice::onstart(const want &want){ printf(mainabilityslice::onstart); abilityslice::onstart(want); auto button1 = new uilabelbutton(); button1->setposition(button1_position_x, button1_position_y); button1->settext(翻转 led); button1->resize(button_width, button_height); button1->setfontid(font_id); button1->setstyle(style_text_color, color::black().full); button1->setstyle(style_text_opa, root_view_opacity); button1->setstyle(style_background_opa, root_view_opacity); rootview_ = rootview::getwindowrootview(); rootview_->setposition(root_view_position_x, root_view_position_y); rootview_->resize(root_view_width, root_view_height); rootview_->add(button1); setuicontent(rootview_);} 2.3 实现驱动消息机制 这里顺便提一下,文档中devsvcmanagerclntgetservice接口仅在内核态有效,可以方便的获取服务并直接调用。鸿蒙作为微内核的os,想从用户态调用内核态函数,要么用框架的消息机制,要么自己用中断服务实现。
#define led_write_read 1#define led_service led_servicestatic int ondeveventreceived(void *priv, uint32_t id, struct hdfsbuf *data){ const char *string = hdfsbufreadstring(data); if (string == null) { printf(fail to read string in event data); return hdf_failure; } printf(%s: dev event received: %u %s, (char *)priv, id, string); return hdf_success;}static int sendevent(struct hdfioservice *serv, const char *eventdata){ int ret = 0; struct hdfsbuf *data = hdfsbufobtaindefaultsize(); if (data == null) { printf(fail to obtain sbuf data); return 1; } struct hdfsbuf *reply = hdfsbufobtaindefaultsize(); if (reply == null) { printf(fail to obtain sbuf reply); ret = hdf_dev_err_no_memory; hdfsbufrecycle(data); return ret; } if (!hdfsbufwritestring(data, eventdata)) { printf(fail to write sbuf); ret = hdf_failure; hdfsbufrecycle(data); hdfsbufrecycle(reply); return ret; } ret = serv->dispatcher->dispatch(&serv->object, led_write_read, data, reply); if (ret != hdf_success) { printf(fail to send service call); hdfsbufrecycle(data); hdfsbufrecycle(reply); return ret; } int replydata = 0; if (!hdfsbufreadint32(reply, &replydata)) { printf(fail to get service call reply); ret = hdf_err_invalid_object; hdfsbufrecycle(data); hdfsbufrecycle(reply); return ret; } printf(get reply is: %d, replydata); hdfsbufrecycle(data); hdfsbufrecycle(reply); return ret;} 2.4 加入点击事件 每次点击按钮,向内核态发送一次消息。
auto onclick = [this](uiview &view, const event &event) -> bool { printf(led button pressed); struct hdfioservice *serv = hdfioservicebind(led_service, 0); if (serv == null) { printf(fail to get service %s, led_service); return false; } static struct hdfdeveventlistener listener = { .callback = ondeveventreceived, .priv = (void *)service0}; if (hdfdeviceregistereventlistener(serv, &listener) != hdf_success) { printf(fail to register event listener); return false; } const char *send_cmd = toggle led; if (sendevent(serv, send_cmd)) { printf(fail to send event); return false; } if (hdfdeviceunregistereventlistener(serv, &listener)) { printf(fail to unregister listener); return false; } hdfioservicerecycle(serv); return true;}; 2.5 注销页面 在生命周期函数onstop中,删除所有节点,回收系统资源。
void deleteviewchildren(uiview *view){ if (view == nullptr) { return; } while (view != nullptr) { uiview *tempview = view; view = view->getnextsibling(); if (tempview->isviewgroup()) { deleteviewchildren(dynamic_cast(tempview)->getchildrenhead()); } if (tempview->getparent()) { dynamic_cast(tempview->getparent())->remove(tempview); } delete tempview; }}void mainabilityslice::onstop(){ printf(mainabilityslice::onstop); abilityslice::onstop(); deleteviewchildren(rootview_);} 3. 编译配置 新增 applicationssamplecameramyledappbuild.gn文件
import(//build/lite/config/component/lite_component.gni)import(//build/lite/config/subsystem/aafwk/config.gni)hdf_frameworks = //drivers/hdf/frameworkssrc_path = //applications/sample/camera/myledapp/srclite_library(ledability) { target_type = shared_library ldflags = [ -shared, ] sources = [ ${src_path}/main_ability.cpp, ${src_path}/main_ability_slice.cpp, ] include_dirs = [ ., //foundation/aafwk/frameworks/ability_lite/example/entry/src/main/cpp, //foundation/aafwk/interfaces/innerkits/abilitymgr_lite, //foundation/aafwk/interfaces/kits/ability_lite, //foundation/aafwk/interfaces/kits/want_lite, //foundation/appexecfwk/interfaces/kits/bundle_lite, //foundation/appexecfwk/utils/bundle_lite, //foundation/communication/interfaces/kits/ipc_lite, //foundation/graphic/lite/interfaces/kits/config, //foundation/graphic/lite/interfaces/kits/ui, //foundation/graphic/lite/interfaces/kits/utils, //kernel/liteos_a/kernel/common, //kernel/liteos_a/kernel/include, //drivers/hdf/lite/include/host, $hdf_frameworks/ability/sbuf/include, $hdf_frameworks/core/shared/include, $hdf_frameworks/core/host/include, $hdf_frameworks/core/master/include, $hdf_frameworks/include/core, $hdf_frameworks/include/utils, $hdf_frameworks/utils/include, $hdf_frameworks/include/osal, //kernel/liteos_a/platform/include, $hdf_frameworks/adapter/syscall/include, $hdf_frameworks/adapter/vnode/include, ] deps = [ //foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite, //drivers/hdf/lite/manager:hdf_core, //drivers/hdf/lite/adapter/osal/posix:hdf_posix_osal, ] defines = [ ohos_appexecfwk_bms_bundlemanager, ] if (enable_ohos_appexecfwk_feature_ability == true) { deps += [ //foundation/graphic/lite/frameworks/ui:ui, ] defines += [ enable_window=1, ability_window_support ] } output_dir = $root_out_dir/dev_tools/led} 4. 应用配置文件 新建 applicationssamplecameramyledappconfig.json
{ app: { bundlename: com.bluishfish.ledability, vendor: huawei, version: { code: 1, name: 1.0 }, apiversion: { compatible: 3, target: 3 } }, deviceconfig: { default: { keepalive: false } }, module: { devicetype: [ smartvision ], distro: { deliverywithinstall: true, modulename: ledability, moduletype: entry }, abilities: [{ name: mainability, icon: assets/entry/resources/base/media/icon.png, label: led ability, launchtype: standard, type: page, visible: true } ] }}
5. 板级编译配置 复制 build/lite/product/ipcamera_hi3516dv300.json,改名为my_hi3516dv300在子系统里加入
{ ohos_version: openharmony 1.0, board: hi3516dv300, kernel: liteos_a, compiler: clang, subsystem: [ { name: aafwk, component: [ ......, { name: ability_led, dir: //applications/sample/camera/myledapp:ledability, features: []} ]...... 6. 编译应用
python build.py my_hi3516dv300 -b debug
将系统烧录到开发板上。
7. 打包应用 在 assetsentry esourcesasemedia目录下放置一个icon.png作为启动图标。
将applicationssamplecameramyledappconfig.json和 z:openharmonyoutmy_hi3516dv300dev_toolsledlibledability.so打包压缩成zip包
改名为ledability.hap ,复制到nfs共享目录
8. 安装hap
mkdir nfsmount 192.168.1.57:/nfs /nfs nfs./nfs/dev_tools/bin/bm set -s disable./nfs/dev_tools/bin/bm install -p ./nfs/ledability.hap
9. 运行程序
./nfs/dev_tools/bin/aa start -p com.bluishfish.ledability -n mainability
完美!

集微连线:板级封装潜力无穷 RDL工艺勇挑大梁
石墨烯/氮化硼异质结构在集成电路热管理中的应用
一个新的、大型的机器人指南网站,了解世界上最酷的机器人
HP MSA存储vxfs文件系统数据恢复案例
碳化硅太阳能电池的湿式化学处理
基于鸿蒙开发的触摸屏控制LED
简述可穿戴设备在无线充电市场的发展情况
经纬恒润入选北京市第一批“隐形冠军”企业
骁龙888与骁龙865性能对比,哪款更好?
工业互联网使各行业数字化转型进程加速
昂视2021华南工博会圆满落幕
浅谈接地和屏蔽技术应用
怎么检测霍尔开关的好坏?
新型多功能柔性可穿戴式传感器守护健康
消费电子FPC国内外使用量分析
2019智能可穿戴市场份额出炉 苹果远远领先其他品牌
相对介电常数越大代表什么
监测供电的电能质量监测装置应用分析
电子芯闻早报:三星正研发VR无线一体机
无线投屏技术可帮助我们在家学习和工作