想了解更多内容,请访问:
创新互联服务项目包括河源网站建设、河源网站制作、河源网页制作以及河源网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,河源网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到河源省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
和华为官方合作共建的鸿蒙技术社区
https://harmonyos.
HCS(HDF Configuration Source)是 HDF 驱动框架的配置描述源码,内容以 KeyValue 为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。
HC-GEN(HDF Configuration Generator)是 HCS 配置转换工具,可以将 HDF 配置文件转换为软件可读取的文件格式:
以下是使用 HCB 模式的典型应用场景:
图1 配置使用流程图
HCS 经过 HC-GEN 编译生成 HCB 文件,HDF 驱动框架中的 HCS Parser 模块会从 HCB 文件中重建配置树,HDF 驱动模块使用 HCS Parser 提供的配置读取接口获取配置内容。
图2 HCS的架构图
HCS 文本更适合人类阅读,但是并不方便程序直接存取,所以经过 HC-GEN 编译,输出二进制的 HCB 数据。HCB 在编译后打包进内核镜像的.rodata 只读分区,在启动加载时,框架定位到 HCB 数据头,再将二进制数据重新构造为树形数据结构供驱动查询和读取。下面详细分析 HC-GEN 实现。
HCS 的语法介绍如下:
HCS 配置语法保留了以下关键字。
HCS 主要分为属性(Attribute)和节点(Node)两种结构。
属性即最小的配置单元,是一个独立的配置项。语法如下:
- attribute_name = value;
attribute_name 是字母、数字、下划线的组合且必须以字母或下划线开头,字母区分大小写。
value 的可用格式如下:
节点是一组属性的集合,语法如下:
- node_name {
- module = "sample";
- ...
- }
整型长度自动推断,根据实际数据长度给与最小空间占用的类型。
字符串使用双引号(“”)表示。
数组元素支持整型、字符串,不支持混合类型。整型数组中 uint32_t uint64_t 混用会向上转型为 uint64_t 数组。整型数组与字符串数组示例如下:
- attr_foo = [0x01, 0x02, 0x03, 0x04];
- attr_bar = ["hello", "world"];
bool 类型中 true 表示真,false 表示假。
HCS 支持两种注释风格。
单行注释:
- 1. // comment
多行注释:
- /*
- comment
- */
模板的用途在于生成严格一致的 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 保持了完全一致,只是属性的值不同。
引用修改可以实现修改另外任意一个节点的内容,语法为:
- 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 节点,示例如下:
- #include "sample1.hcs"
- root {
- attr_2 = delete;
- foo_2 : delete {
- }
}
为了在解析配置时快速定位到关联的节点,可以把节点作为属性的右值,通过读取属性查找到对应节点。语法为:
- attribute = &node;
HCB 为便于程序读取的 HCS 的二进制数据格式,按照下面的编码表进行数据组织:
以一个示例分析下 HCS 源码和 HCB 的对应关系:
- root {
- module = "sample";
- gpio = [1, 2];
- }
上述 HCS 编译后的 HCB 数据如下:
hc-gen 是 HCS 的编译器,用于在编译时将 HCS 转化为 HCB,也可以将 HCB 反编译为 HCS 以验证配置数据的正确性,这在驱动调试时将很有帮助。
hc-gen v0.7 之前版本作为 prebuilt 文件以二进制下载方式提供。0.7 版本开始,为了更好的支持多环境部署和版本管理,hc-gen 在编译过程中从源码构建。如果调试需要,可以在 OpenHarmony 源码的 drivers/framework/tools/hc-gen 下执行 make 生成,生成产物在该目录的 build 子目录中。
- cd drivers/framework/tools/hc-gen
- make
- ./build/hc-gen –v
- > Hcs compiler 0.7
驱动开发过程中,在 hcs 配置文件修改后,可以手动使用 hc-gen 快速验证配置的正确性,生成 HCB 配置文件方法:
- hcgen o [OutputHcbFileName] b [SourceHcsFileName]
在驱动调试时,可以使用 hc-gen 反编译 HCB 文件获得 HCS 源码,进行配置数据核对。反编译 HCB 文件为 HCS 方法:
- hcgen o [OutputHcsFileName] d [SourceHcbFileName]
在 linux 内核中,HCS 编译基于 KBuild 自定义规则实现自主的编译过程,Makefile 入口在 drivers/adapter/khdf/linux/hcs/Makefile。
- HC_GEN_DIR := $(abspath $(SOURCE_ROOT)/drivers/framework/tools/hc-gen)
- HC_GEN := $(HC_GEN_DIR)/build/hc-gen
- LOCAL_HCS_ROOT := $(abspath $(dir $(realpath $(lastword $(MAKEFILE_LIST)))))
- # LOCAL_HCS_ROOT为根据目标平台和产品拼接出的HCS路径
- HCS_DIR := $(LOCAL_HCS_ROOT)
- HCB_FLAGS := -b -i -a
- HCS_OBJ := hdf_hcs_hex.o
- HCS_OBJ_SRC := $(subst .o,.c,$(notdir $(HCS_OBJ)))
- CONFIG_GEN_HEX_SRC := $(addprefix $(LOCAL_HCS_ROOT)/, $(HCS_OBJ_SRC))
- CONFIG_HCS_SRC := $(subst _hcs_hex.o,.hcs,$(addprefix $(HCS_DIR)/, $(HCS_OBJ)))
- # 使用自定义的.o生成规则覆盖KBbuild默认规则
- $(obj)/$(HCS_OBJ): $(CONFIG_GEN_HEX_SRC)
- $(Q)$(CC) $(c_flags) -c -o $@ $<
- $(Q)rm -f $<
- # 将HCB文件生成后再转换为.c文件中的hex数组,依赖目标为hc-gen工具
- $(CONFIG_GEN_HEX_SRC): $(LOCAL_HCS_ROOT)/%_hcs_hex.c: $(HCS_DIR)/%.hcs | $(HC_GEN)
- $(Q)echo gen hdf built-in config
- $(Q)if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi
- $(Q)$(HC_GEN) $(HCB_FLAGS) -o $(subst _hex.c,,$(@)) $<
- # 生成hc-gen工具
- $(HC_GEN):
- $(Q)make -C $(HC_GEN_DIR)
- obj-$(CONFIG_DRIVERS_HDF) += $(HCS_OBJ)
在 HDF 适配其他平台时,可以复用该 Makefile,核心变化点在正确配置对应平台的 HCS 根路径。
在驱动实现中,可以使用 device_resource_if.h 中定义的接口对配置进行查询和读取。常用 API 介绍如下:
以 UART 控制器驱动为例看 HCS 的使用。UART 在 HCS 中 device_info.hcs 中配置的设备信息为:
- device_uart :: device {
- device0 :: deviceNode {
- policy = 1;
- priority = 40;
- permission = 0644;
- moduleName = "HDF_PLATFORM_UART";
- serviceName = "HDF_PLATFORM_UART_0";
- deviceMatchAttr = "hisilicon_hi35xx_uart_0";
- }
- }
在 hi35xx_uart_config.hcs 中配置如下:
- root {
- platform {
- uart_config {
- device_uart_0x0000 {
- serviceName = "";
- match_attr = "hisilicon_hi35xx_uart_0";
- driver_name = "ttyAMA";
- num = 0;
- }
- }
- }
- }
注意到 UART 使用了 match_attr 特性,这样驱动框架在 device_uart 设备加载时将自动将 device_uart_0x0000 节点关联到该设备。UART 的配置解析代码如下:
- static int32_t HdfUartInit(struct HdfDeviceObject *obj)
- {
- int32_t ret;
- struct DeviceResourceIface *iface = NULL;
- …
- devResourceIface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
- if (devResourceIface == NULL) {
- HDF_LOGE("%s: face is invalid", __func__);
- return HDF_FAILURE;
- }
- devResourceIface->GetUint32(obj->property, "num", &host->num, 0);
- devResourceIface->GetString(obj->property, "driver_name", &drName, "ttyAMA");
- ……
- ret = memcpy_s(g_driverName, UART_NAME_LEN - 1, drName, strlen(drName));
- if (ret != EOK) {
- return HDF_FAILURE;
- }
- host->method = &g_uartHostMethod;
- return HDF_SUCCESS;
- }
device_uart_0x0000 节点被自动关联到了 HdfDeviceObject 的 property 成员。使用 DeviceResourceGetIfaceInstance 接口获取到 HCS 接口实例后调用其成员方法 GetUint32 读取名为"num"的无符号值属性,使用 GetString 接口读取名为"driver_name"的字符串属性。从配置中获取到属性值后,再根据配置值完成相关软硬件的初始化。
本文从全景介绍了 HCS 配置管理方案,重点分析了 HC-GEN 的实现和 HCS 的编译过程,希望对读者理解 HCS 的原理和配置方法能有所帮助。关于 HDF 驱动框架的更多分析,请关注后续文章。
想了解更多内容,请访问:
和华为官方合作共建的鸿蒙技术社区
https://harmonyos.
网页标题:OpenHarmonyHDF配置管理分析及使用
URL标题:http://www.shufengxianlan.com/qtweb/news13/63463.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联