OpenHarmony开发实战:HDF驱动开发流程

概述

HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路,让驱动开发和部署更加规范,旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的驱动管理的开发环境,力求做到一次开发,多系统部署。

驱动加载

HDF驱动框架提供把和配置的设备列表匹配成功的驱动程序加载起来的功能。

驱动服务管理

HDF框架可以集中管理驱动服务,开发者可直接通过HDF框架对外提供的能力接口获取驱动相关的服务。

驱动消息机制

HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。

配置管理

HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。

驱动模型

HDF框架将一类设备驱动放在同一个Host(设备容器)里面,用于管理一组设备的启动加载等过程。在划分Host时,驱动程序是部署在一个Host还是部署在不同的Host,主要考虑驱动程序之间是否存在耦合性,如果两个驱动程序之间存在依赖,可以考虑将这部分驱动程序部署在一个Host里面,否则部署到独立的Host中是更好的选择。Device对应一个真实的物理设备。DeviceNode是设备的一个部件,Device至少有一个DeviceNode。每个DeviceNode可以发布一个设备服务。驱动即驱动程序,每个DevicdNode唯一对应一个驱动,实现和硬件的功能交互。HDF驱动模型如下图所示:

图1 HDF驱动模型

点击领取→ 纯血鸿蒙Next全套最新学习资料(安全链接,放心点击希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取~

功能描述

驱动加载

HDF驱动框架提供把和配置的设备列表匹配成功的驱动程序加载起来的功能,支持按需加载和按序加载两种策略,具体设备的加载策略由配置文件中的preload字段来控制,配置值参考如下:

typedef enum {
    DEVICE_PRELOAD_ENABLE = 0,
    DEVICE_PRELOAD_ENABLE_STEP2 = 1,
    DEVICE_PRELOAD_DISABLE = 2,
    DEVICE_PRELOAD_INVALID
} DevicePreload;
按需加载
  • preload字段配置为0(DEVICE_PRELOAD_ENABLE),则系统启动过程中默认加载。
  • preload字段配置为1(DEVICE_PRELOAD_ENABLE_STEP2),当系统支持快速启动的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE_PRELOAD_ENABLE含义相同。
  • preload字段配置为2(DEVICE_PRELOAD_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务消息机制时,如果驱动服务不存在,HDF框架会尝试动态加载该驱动。
按序加载(默认加载策略)

配置文件中的priority(取值范围为整数0到200)是用来表示host(驱动容器)和驱动的优先级的。不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高。

异常恢复(用户态驱动)

当驱动服务异常退出时,恢复策略如下:

  • preload字段配置为0(DEVICE_PRELOAD_ENABLE)或1(DEVICE_PRELOAD_ENABLE_STEP2)的驱动服务,由启动模块拉起host并重新加载服务。
  • preload字段配置为2(DEVICE_PRELOAD_DISABLE)的驱动服务,需业务模块注册HDF的服务状态监听器,当收到服务退出消息时,业务模块调用LoadDevice重新加载服务。

驱动服务管理

驱动服务是HDF驱动设备对外提供能力的对象,由HDF框架统一管理。驱动服务管理主要包含驱动服务的发布和获取。HDF框架定义了驱动对外发布服务的策略,由配置文件中的policy字段来控制,policy字段的取值范围以及含义如下:

typedef enum {
    /* 驱动不提供服务 */
    SERVICE_POLICY_NONE = 0,
    /* 驱动对内核态发布服务 */
    SERVICE_POLICY_PUBLIC = 1,
    /* 驱动对内核态和用户态都发布服务 */
    SERVICE_POLICY_CAPACITY = 2,
    /* 驱动服务不对外发布服务,但可以被订阅 */
    SERVICE_POLICY_FRIENDLY = 3,
    /* 驱动私有服务不对外发布服务,也不能被订阅 */
    SERVICE_POLICY_PRIVATE = 4,
    /* 错误的服务策略 */
    SERVICE_POLICY_INVALID
} ServicePolicy;
使用场景

当驱动需要以接口的形式对外提供能力时,可以使用HDF框架的驱动服务管理能力。

接口说明

针对驱动服务管理功能,HDF框架开放了以下接口供开发者调用,如下表所示:

表1 服务管理接口

方法 描述
int32_t (*Bind)(struct HdfDeviceObject *deviceObject) 需要驱动开发者实现Bind函数,将自己的服务接口绑定到HDF框架中。
const struct HdfObject *DevSvcManagerClntGetService(const char *svcName) 获取驱动的服务。
int HdfDeviceSubscribeService( struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback) 订阅驱动的服务。

驱动消息机制管理

使用场景

当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。

接口说明

消息机制的功能主要有以下两种:

  • 用户态应用发送消息到驱动。
  • 用户态应用接收驱动主动上报事件。

表2 消息机制接口

方法 描述
struct HdfIoService *HdfIoServiceBind(const char *serviceName); 用户态获取驱动的服务,获取该服务之后通过服务中的Dispatch方法向驱动发送消息。
void HdfIoServiceRecycle(struct HdfIoService *service); 释放驱动服务。
int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener); 用户态程序注册接收驱动上报事件的操作方法。
int32_t HdfDeviceSendEvent(const struct HdfDeviceObject *deviceObject, uint32_t id, const struct HdfSBuf *data) 驱动主动上报事件接口。

配置管理

配置概述

HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。HC-GEN(HDF Configuration Generator)是HCS配置转换工具,可以将HDF配置文件转换为软件可读取的文件格式:

  • 在弱性能环境中,转换为配置树源码或配置树宏定义,驱动可直接调用C代码或宏式APIs获取配置。
  • 在高性能环境中,转换为HCB(HDF Configuration Binary)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置。

以下是使用HCB模式的典型应用场景:

图2 配置使用流程图

HCS经过HC-GEN编译生成HCB文件,HDF驱动框架中的HCS Parser模块会从HCB文件中重建配置树,HDF驱动模块使用HCS Parser提供的配置读取接口获取配置内容。

配置语法

HCS的语法介绍如下:

关键字

HCS配置语法保留了以下关键字。

表3 HCS配置语法保留关键字

关键字 用途 说明
root 配置根节点 -
include 引用其他HCS配置文件 -
delete 删除节点或属性 只能用于操作include导入的配置树
template 定义模板节点 -
match_attr 用于标记节点的匹配查找属性 解析配置时可以使用该属性的值查找到对应节点
基本结构

HCS主要分为属性(Attribute)和节点(Node)两种结构。

属性

属性即最小的配置单元,是一个独立的配置项。语法如下:

  attribute_name = value;
  • attribute_name是字母、数字、下划线的组合且必须以字母或下划线开头,字母区分大小写。
  • value的可用格式如下:
    • 数字常量,支持二进制、八进制、十进制、十六进制数,具体数据类型章节。
    • 字符串,内容使用双引号("")引用。
    • 节点引用。
  • attribute必须以分号(;)结束且必须属于一个node。

节点

节点是一组属性的集合,语法如下:

  node_name {
      module = "sample";
      ...
  }
  • node_name是字母、数字、下划线的组合且必须以字母或下划线开头,字母区分大小写。
  • 大括号后无需添加结束符";"。
  • root为保留关键字,用于声明配置表的根节点。每个配置表必须以root节点开始。
  • root节点中必须包含module属性,其值应该为一个字符串,用于表征该配置所属模块。
  • 节点中可以增加match_attr属性,其值为一个全局唯一的字符串。当驱动程序在解析配置时可以以该属性的值为参数调用查找接口查找到包含该属性的节点。
数据类型

在属性定义中使用自动数据类型,不显式指定类型,属性支持的数据类型如下:

整型

整型长度自动推断,根据实际数据长度给与最小空间占用的类型。

  • 二进制,0b前缀,示例:0b1010。
  • 八进制,0前缀,示例:0664。
  • 十进制 ,无前缀,且支持有符号与无符号,示例:1024,+1024均合法。驱动程序在读取负值时注意使用有符号数读取接口。
  • 十六进制,0x前缀,示例:0xff00、0xFF。

字符串

字符串使用双引号("")表示。

数组

数组元素支持整型、字符串,不支持混合类型。整型数组中uint32_t uint64_t混用会向上转型为uint64_t数组。整型数组与字符串数组示例如下:

attr_foo = [0x01, 0x02, 0x03, 0x04];
attr_bar = ["hello", "world"];

bool类型

bool类型中true 表示真,false表示假。

预处理

include

用于导入其他HCS文件。语法示例如下:

#include "foo.hcs"
#include "../bar.hcs"
  • 文件名必须使用双引号(""),不在同一目录使用相对路径引用。被include文件也必须是合法的HCS文件。
  • 多个include,如果存在相同的节点,后者覆盖前者,其余的节点依次展开。
注释

支持两种注释风格。

  • 单行注释。

    // comment
    
  • 多行注释。

    /*
    comment
    */
    

    说明: 多行注释不支持嵌套。

引用修改

引用修改的作用是在当前节点中修改另外任意一个节点的内容,语法为:

 node :& source_node

上述语句表示node中的内容是对source_node节点内容的修改。示例如下:

root {
    module = "sample";
    foo {
        foo_ :& root.bar{
            attr = "foo";
        }
        foo1 :& foo2 {
            attr = 0x2;
        }
        foo2 {
            attr = 0x1;
        }
    }

    bar {
        attr = "bar";
    }
}

最终生成配置树为:

root {
    module = "sample";
    foo {
        foo2 {
            attr = 0x2;
        }
    }
    bar {
        attr = "foo";
    }
}

在以上示例中,可以看到foo.foo_节点通过引用将bar.attr属性的值修改为了"foo",foo.foo1节点通过引用将foo.foo2.attr属性的值修改为了0x2。foo.foo_以及foo.foo1节点表示对目标节点内容的修改,其自身并不会存在最终生成的配置树中。

  • 引用同级node,可以直接使用node名称,否则被引用的节点必须使用绝对路径,节点间使用"."分隔,root表示根节点,格式为root开始的节点路径序列,例如root.foo.bar即为一个合法的绝对路径。
  • 如果出现修改冲突(即多处修改同一个属性),编译器将提示warning,因为这种情况下只会生效某一个修改而导致最终结果不确定。
节点复制

节点复制可以实现在节点定义时从另一个节点先复制内容,用于定义内容相似的节点。语法为:

 node : source_node

上述语句表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。示例如下:

root {
    module = "sample";
    foo {
        attr_0 = 0x0;
    }
    bar:foo {
        attr_1 = 0x1;
    }
}

上述代码的最终生成配置树为:

root {
    module = "sample";
    foo {
        attr_0 = 0x0;
    }
    bar {
        attr_1 = 0x1;
        attr_0 = 0x0;
    }
}

在上述示例中,编译后bar节点既包含attr_0属性又包含attr_1属性,在bar中对attr_0的修改不会影响到foo。

当foo和bar在同级node中时可不指定foo的路径,否则需要使用绝对路径引用,绝对路径的介绍请参考引用修改。

删除

要对include导入的base配置树中不需要的节点或属性进行删除,可以使用delete关键字。下面的举例中sample1.hcs通过include导入了sample2.hcs中的配置内容,并使用delete删除了sample2.hcs中的attribute2属性和foo_2节点,示例如下:

// sample2.hcs
root {
    attr_1 = 0x1;
    attr_2 = 0x2;
    foo_2 {
        t = 0x1;
    }
}

// sample1.hcs
#include "sample2.hcs"
root {
    attr_2 = delete;
    foo_2 : delete {
    }
}

上述代码在生成过程中将会删除root.foo_2节点与attr_2,最终生成配置树为:

root {
    attr_1 = 0x1;
}

说明: 在同一个HCS文件中不允许使用delete,建议直接删除不需要的属性。

属性引用

为了在解析配置时快速定位到关联的节点,可以把节点作为属性的右值,通过读取属性查找到对应节点。语法为:

 attribute = &node;

上述语句表示attribute的值是一个节点node的引用,在解析时可以用这个attribute快速定位到node,便于关联和查询其他node。示例如下:

node1 {
    attributes;
}
node2 {
    attr_1 = &root.node1;
}

node2 {
    node1 {
        attributes;
    }
    attr_1 = &node1;
}
模板

模板的用途在于生成严格一致的node结构,以便对同类型node进行遍历和管理。使用template关键字定义模板node,子node通过双冒号"::"声明继承关系。子节点可以改写或新增但不能删除template中的属性,子节点中没有定义的属性将使用template中的定义作为默认值。示例如下:

root {
    module = "sample";
    template foo {
        attr_1 = 0x1;
        attr_2 = 0x2;
    }

    bar :: foo {
    }

    bar_1 :: foo {
        attr_1 = 0x2;
    }
}

​ 生成配置树如下:

root {
    module = "sample";
    bar {
        attr_1 = 0x1;
        attr_2 = 0x2;
    }
    bar_1 {
        attr_1 = 0x2;
        attr_2 = 0x2;
    }
}

在上述示例中,bar和bar_1节点继承了foo节点,生成配置树节点结构与foo保持了完全一致,只是属性的值不同。

配置生成

​ hc-gen是配置生成的工具,可以对HCS配置语法进行检查并把HCS源文件转化成HCB二进制文件。

hc-gen介绍

​ hc-gen参数说明:

Usage: hc-gen [Options] [File]
options:
  -o <file>   output file name, default same as input
  -a          hcb align with four bytes
  -b          output binary output, default enable
  -t          output config in C language source file style
  -m          output config in macro source file style
  -i          output binary hex dump in C language source file style
  -p <prefix> prefix of generated symbol name
  -d          decompile hcb to hcs
  -V          show verbose info
  -v          show version
  -h          show this help message

生成.c/.h配置文件方法:

hc-gen -o [OutputCFileName] -t [SourceHcsFileName]

生成HCB配置文件方法:

hc-gen -o [OutputHcbFileName] -b [SourceHcsFileName]

生成宏定义配置文件方法:

hc-gen -o [OutputMacroFileName] -m [SourceHcsFileName]

反编译HCB文件为HCS方法:

hc-gen -o [OutputHcsFileName] -d [SourceHcbFileName]

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙**(HarmonyOS NEXT)**学习路径和一些资料的整理供小伙伴学习

点击领取→ 纯血鸿蒙Next全套最新学习资料(安全链接,放心点击

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
**一、**鸿蒙(HarmonyOS NEXT)最新学习路线

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含: (ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)****...等技术 知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

二、HarmonyOS Next 最新全套视频教程

三、《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .......

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ......

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ......

四、大厂面试必问面试题

五、鸿蒙南向开发技术

六、鸿蒙APP开发必备

七、鸿蒙生态应用开发白皮书V2.0PDF

完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料****

总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。

相关推荐
森旺电子1 小时前
无线幅频仪制作(WiFi通信)-含STM32源程序,JAVA上位机与设计报告
java·stm32·单片机·嵌入式硬件
sdszoe49221 小时前
华为BGP路由实验基础1------用物理口建立对等体
网络·华为·bgp对等体
Tony11541 小时前
华为eNSP模拟器安装详细步骤
华为
vickycheung32 小时前
基于IMX8MPlus SMARC核心板的便携式床旁超声诊断仪应用解决方案
嵌入式硬件·arm 嵌入式开发
迷途的小朋友3 小时前
bmob Harmony鸿蒙快速开发搜索功能
华为·harmonyos
HarmonyOS_SDK6 小时前
HiAI Foundation开发平台,加速端侧AI应用的智能革命
harmonyos
-耿瑞-6 小时前
华为手机改变休眠时间 不让手机动不动黑屏
华为
花先锋队长7 小时前
西部智慧健身小程序+华为运动健康服务
华为·小程序·生活
小白在路上~7 小时前
51单片机嵌入式开发:STC89C52操作GPIO口LED灯
c语言·开发语言·单片机·嵌入式硬件·51单片机·dsp开发
FU.l8 小时前
Linux-笔记 全志平台休眠功能初探
linux·驱动开发·笔记