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


    目录:

    前言
    背景知识
    编译用户程序框架子系统
    基于AbilityKit开发的Ability
    总结

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

    用鸿蒙开发AI应用(七)触摸屏控制LED背景知识
    用户程序框架子系统包含两个大的模块:Ability子系统和包管理子系统。

    1. Ability子系统

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

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

    Page类型的Ability:带有界面,为用户提供人机交互的能力。
    Service类型的Ability:不带界面,为用户提供后台任务机制。
    1.2 AbilitySlice
    AbilitySlice是单个页面及其控制逻辑的总和,是Page类型Ability特有的组件,一个Page类型的Ability可以包含多个AbilitySlice,此时,这些页面提供的业务能力应当是高度相关的。

    用鸿蒙开发AI应用(七)触摸屏控制LED1.3 生命周期
    生命周期是Ability被调度到启动、激活、隐藏和退出等各个状态的的统称。

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

    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为开发者提供的安装包管理框架。

    用鸿蒙开发AI应用(七)触摸屏控制LEDBundleKit:是包管理服务对外提供的接口,有安装/卸载接口、包信息查询接口、包状态变化监听接口。
    包扫描器:用来解析本地预制或者安装的安装包,提取里面的各种信息,供管理子模块进行管理,持久化。
    包安装子模块:安装,卸载,升级一个包;包安装服务一个单独进程的用于创建删除安装目录,具有较高的权限。
    包管理子模块:管理安装包相关的信息,存储持久化包信息。
    包安全管理子模块:签名检查、权限授予、权限管理。

    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 __cplusplus
    extern "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.mk
    
    MODULE_NAME := hdf_led_driver
    LOCAL_SRCS += led_ctrl.c 
    			  led.c 
                  
    LOCAL_INCLUDE := ./include
    LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror
    include $(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.h"
    
    namespace OHOS {
    REGISTER_AA(MainAbility)
    
    void MainAbility::OnStart(const Want &want)
    {
        printf("MainAbility::OnStart
    ");
        SetMainRoute("MainAbilitySlice");
    
        Ability::OnStart(want);
    }

    查看更多章节>>>

    作者:bluishfish

    想了解更多内容,请访问: 51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com

  • 相关阅读:
    运动运行。
    stratMove方法
    抛物线
    表单的小例子吖
    常用的查询DOM的方法
    liuyan
    防止xss攻击。
    ES6
    Map的使用
    ZOJ 3998(线段树)
  • 原文地址:https://www.cnblogs.com/HarmonyOS/p/14371791.html
Copyright © 2020-2023  润新知