概述
HDF(Hardware Driver Foundation)驅(qū)動(dòng)框架,為驅(qū)動(dòng)開(kāi)發(fā)者提供驅(qū)動(dòng)框架能力,包括驅(qū)動(dòng)加載、驅(qū)動(dòng)服務(wù)管理、驅(qū)動(dòng)消息機(jī)制和配置管理。并以組件化驅(qū)動(dòng)模型作為核心設(shè)計(jì)思路,讓驅(qū)動(dòng)開(kāi)發(fā)和部署更加規(guī)范,旨在構(gòu)建統(tǒng)一的驅(qū)動(dòng)架構(gòu)平臺(tái),為驅(qū)動(dòng)開(kāi)發(fā)者提供更精準(zhǔn)、更高效的驅(qū)動(dòng)管理的開(kāi)發(fā)環(huán)境,力求做到一次開(kāi)發(fā),多系統(tǒng)部署。
驅(qū)動(dòng)加載
HDF驅(qū)動(dòng)框架提供把和配置的設(shè)備列表匹配成功的驅(qū)動(dòng)程序加載起來(lái)的功能。
驅(qū)動(dòng)服務(wù)管理
HDF框架可以集中管理驅(qū)動(dòng)服務(wù),開(kāi)發(fā)者可直接通過(guò)HDF框架對(duì)外提供的能力接口獲取驅(qū)動(dòng)相關(guān)的服務(wù)。
驅(qū)動(dòng)消息機(jī)制
HDF框架提供統(tǒng)一的驅(qū)動(dòng)消息機(jī)制,支持用戶態(tài)應(yīng)用向內(nèi)核態(tài)驅(qū)動(dòng)發(fā)送消息,也支持內(nèi)核態(tài)驅(qū)動(dòng)向用戶態(tài)應(yīng)用發(fā)送消息。
配置管理
HCS(HDF Configuration Source)是HDF驅(qū)動(dòng)框架的配置描述源碼,內(nèi)容以Key-Value為主要形式。它實(shí)現(xiàn)了配置代碼與驅(qū)動(dòng)代碼解耦,便于開(kāi)發(fā)者進(jìn)行配置管理。
驅(qū)動(dòng)模型
HDF框架將一類設(shè)備驅(qū)動(dòng)放在同一個(gè)Host(設(shè)備容器)里面,用于管理一組設(shè)備的啟動(dòng)加載等過(guò)程。在劃分Host時(shí),驅(qū)動(dòng)程序是部署在一個(gè)Host還是部署在不同的Host,主要考慮驅(qū)動(dòng)程序之間是否存在耦合性,如果兩個(gè)驅(qū)動(dòng)程序之間存在依賴,可以考慮將這部分驅(qū)動(dòng)程序部署在一個(gè)Host里面,否則部署到獨(dú)立的Host中是更好的選擇。Device對(duì)應(yīng)一個(gè)真實(shí)的物理設(shè)備。DeviceNode是設(shè)備的一個(gè)部件,Device至少有一個(gè)DeviceNode。每個(gè)DeviceNode可以發(fā)布一個(gè)設(shè)備服務(wù)。驅(qū)動(dòng)即驅(qū)動(dòng)程序,每個(gè)DevicdNode唯一對(duì)應(yīng)一個(gè)驅(qū)動(dòng),實(shí)現(xiàn)和硬件的功能交互。HDF驅(qū)動(dòng)模型如下圖所示:
圖1?HDF驅(qū)動(dòng)模型
功能描述
驅(qū)動(dòng)加載
HDF驅(qū)動(dòng)框架提供把和配置的設(shè)備列表匹配成功的驅(qū)動(dòng)程序加載起來(lái)的功能,支持按需加載和按序加載兩種策略,具體設(shè)備的加載策略由配置文件中的preload字段來(lái)控制,配置值參考如下:
typedef enum {
DEVICE_PRELOAD_ENABLE = 0,
DEVICE_PRELOAD_ENABLE_STEP2 = 1,
DEVICE_PRELOAD_DISABLE = 2,
DEVICE_PRELOAD_INVALID
} DevicePreload;
按需加載
- preload字段配置為0(DEVICE_PRELOAD_ENABLE),則系統(tǒng)啟動(dòng)過(guò)程中默認(rèn)加載。
- preload字段配置為1(DEVICE_PRELOAD_ENABLE_STEP2),當(dāng)系統(tǒng)支持快速啟動(dòng)的時(shí)候,則在系統(tǒng)完成之后再加載這一類驅(qū)動(dòng),否則和DEVICE_PRELOAD_ENABLE含義相同。
- preload字段配置為2(DEVICE_PRELOAD_DISABLE),則系統(tǒng)啟動(dòng)過(guò)程中默認(rèn)不加載,支持后續(xù)動(dòng)態(tài)加載,當(dāng)用戶態(tài)獲取驅(qū)動(dòng)服務(wù)消息機(jī)制時(shí),如果驅(qū)動(dòng)服務(wù)不存在,HDF框架會(huì)嘗試動(dòng)態(tài)加載該驅(qū)動(dòng)。
按序加載(默認(rèn)加載策略)
配置文件中的priority(取值范圍為整數(shù)0到200)是用來(lái)表示host(驅(qū)動(dòng)容器)和驅(qū)動(dòng)的優(yōu)先級(jí)的。不同的host內(nèi)的驅(qū)動(dòng),host的priority值越小,驅(qū)動(dòng)加載優(yōu)先級(jí)越高;同一個(gè)host內(nèi)驅(qū)動(dòng)的priority值越小,加載優(yōu)先級(jí)越高。
異?;謴?fù)(用戶態(tài)驅(qū)動(dòng))
當(dāng)驅(qū)動(dòng)服務(wù)異常退出時(shí),恢復(fù)策略如下:
- preload字段配置為0(DEVICE_PRELOAD_ENABLE)或1(DEVICE_PRELOAD_ENABLE_STEP2)的驅(qū)動(dòng)服務(wù),由啟動(dòng)模塊拉起host并重新加載服務(wù)。
- preload字段配置為2(DEVICE_PRELOAD_DISABLE)的驅(qū)動(dòng)服務(wù),需業(yè)務(wù)模塊注冊(cè)HDF的服務(wù)狀態(tài)監(jiān)聽(tīng)器,當(dāng)收到服務(wù)退出消息時(shí),業(yè)務(wù)模塊調(diào)用LoadDevice重新加載服務(wù)。
驅(qū)動(dòng)服務(wù)管理
驅(qū)動(dòng)服務(wù)是HDF驅(qū)動(dòng)設(shè)備對(duì)外提供能力的對(duì)象,由HDF框架統(tǒng)一管理。驅(qū)動(dòng)服務(wù)管理主要包含驅(qū)動(dòng)服務(wù)的發(fā)布和獲取。HDF框架定義了驅(qū)動(dòng)對(duì)外發(fā)布服務(wù)的策略,由配置文件中的policy字段來(lái)控制,policy字段的取值范圍以及含義如下:
typedef enum {
/* 驅(qū)動(dòng)不提供服務(wù) */
SERVICE_POLICY_NONE = 0,
/* 驅(qū)動(dòng)對(duì)內(nèi)核態(tài)發(fā)布服務(wù) */
SERVICE_POLICY_PUBLIC = 1,
/* 驅(qū)動(dòng)對(duì)內(nèi)核態(tài)和用戶態(tài)都發(fā)布服務(wù) */
SERVICE_POLICY_CAPACITY = 2,
/* 驅(qū)動(dòng)服務(wù)不對(duì)外發(fā)布服務(wù),但可以被訂閱 */
SERVICE_POLICY_FRIENDLY = 3,
/* 驅(qū)動(dòng)私有服務(wù)不對(duì)外發(fā)布服務(wù),也不能被訂閱 */
SERVICE_POLICY_PRIVATE = 4,
/* 錯(cuò)誤的服務(wù)策略 */
SERVICE_POLICY_INVALID
} ServicePolicy;
使用場(chǎng)景
當(dāng)驅(qū)動(dòng)需要以接口的形式對(duì)外提供能力時(shí),可以使用HDF框架的驅(qū)動(dòng)服務(wù)管理能力。
接口說(shuō)明
針對(duì)驅(qū)動(dòng)服務(wù)管理功能,HDF框架開(kāi)放了以下接口供開(kāi)發(fā)者調(diào)用,如下表所示:
表1?服務(wù)管理接口
方法 | 描述 |
---|---|
int32_t (*Bind)(struct HdfDeviceObject *deviceObject) | 需要驅(qū)動(dòng)開(kāi)發(fā)者實(shí)現(xiàn)Bind函數(shù),將自己的服務(wù)接口綁定到HDF框架中。 |
const struct HdfObject *DevSvcManagerClntGetService(const char *svcName) | 獲取驅(qū)動(dòng)的服務(wù)。 |
int HdfDeviceSubscribeService( struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback) | 訂閱驅(qū)動(dòng)的服務(wù)。 |
驅(qū)動(dòng)消息機(jī)制管理
使用場(chǎng)景
當(dāng)用戶態(tài)應(yīng)用和內(nèi)核態(tài)驅(qū)動(dòng)需要交互時(shí),可以使用HDF框架的消息機(jī)制來(lái)實(shí)現(xiàn)。
接口說(shuō)明
消息機(jī)制的功能主要有以下兩種:
- 用戶態(tài)應(yīng)用發(fā)送消息到驅(qū)動(dòng)。
- 用戶態(tài)應(yīng)用接收驅(qū)動(dòng)主動(dòng)上報(bào)事件。
表2?消息機(jī)制接口
方法 | 描述 |
---|---|
struct HdfIoService *HdfIoServiceBind(const char *serviceName); | 用戶態(tài)獲取驅(qū)動(dòng)的服務(wù),獲取該服務(wù)之后通過(guò)服務(wù)中的Dispatch方法向驅(qū)動(dòng)發(fā)送消息。 |
void HdfIoServiceRecycle(struct HdfIoService *service); | 釋放驅(qū)動(dòng)服務(wù)。 |
int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener); | 用戶態(tài)程序注冊(cè)接收驅(qū)動(dòng)上報(bào)事件的操作方法。 |
int32_t HdfDeviceSendEvent(const struct HdfDeviceObject *deviceObject, uint32_t id, const struct HdfSBuf *data) | 驅(qū)動(dòng)主動(dòng)上報(bào)事件接口。 |
配置管理
配置概述
HCS(HDF Configuration Source)是HDF驅(qū)動(dòng)框架的配置描述源碼,內(nèi)容以Key-Value為主要形式。它實(shí)現(xiàn)了配置代碼與驅(qū)動(dòng)代碼解耦,便于開(kāi)發(fā)者進(jìn)行配置管理。HC-GEN(HDF Configuration Generator)是HCS配置轉(zhuǎn)換工具,可以將HDF配置文件轉(zhuǎn)換為軟件可讀取的文件格式:
- 在弱性能環(huán)境中,轉(zhuǎn)換為配置樹(shù)源碼或配置樹(shù)宏定義,驅(qū)動(dòng)可直接調(diào)用C代碼或宏式APIs獲取配置。
- 在高性能環(huán)境中,轉(zhuǎn)換為HCB(HDF Configuration Binary)二進(jìn)制文件,驅(qū)動(dòng)可使用HDF框架提供的配置解析接口獲取配置。
以下是使用HCB模式的典型應(yīng)用場(chǎng)景:
圖2?配置使用流程圖
HCS經(jīng)過(guò)HC-GEN編譯生成HCB文件,HDF驅(qū)動(dòng)框架中的HCS Parser模塊會(huì)從HCB文件中重建配置樹(shù),HDF驅(qū)動(dòng)模塊使用HCS Parser提供的配置讀取接口獲取配置內(nèi)容。
配置語(yǔ)法
HCS的語(yǔ)法介紹如下:
關(guān)鍵字
HCS配置語(yǔ)法保留了以下關(guān)鍵字。
表3?HCS配置語(yǔ)法保留關(guān)鍵字
關(guān)鍵字 | 用途 | 說(shuō)明 |
---|---|---|
root | 配置根節(jié)點(diǎn) | - |
include | 引用其他HCS配置文件 | - |
delete | 刪除節(jié)點(diǎn)或?qū)傩?/td> | 只能用于操作include導(dǎo)入的配置樹(shù) |
template | 定義模板節(jié)點(diǎn) | - |
match_attr | 用于標(biāo)記節(jié)點(diǎn)的匹配查找屬性 | 解析配置時(shí)可以使用該屬性的值查找到對(duì)應(yīng)節(jié)點(diǎn) |
基本結(jié)構(gòu)
HCS主要分為屬性(Attribute)和節(jié)點(diǎn)(Node)兩種結(jié)構(gòu)。
屬性
屬性即最小的配置單元,是一個(gè)獨(dú)立的配置項(xiàng)。語(yǔ)法如下:
attribute_name = value;
- attribute_name是字母、數(shù)字、下劃線的組合且必須以字母或下劃線開(kāi)頭,字母區(qū)分大小寫。
- value的可用格式如下:
- 數(shù)字常量,支持二進(jìn)制、八進(jìn)制、十進(jìn)制、十六進(jìn)制數(shù),具體數(shù)據(jù)類型章節(jié)。
- 字符串,內(nèi)容使用雙引號(hào)("")引用。
- 節(jié)點(diǎn)引用。
- attribute必須以分號(hào)(;)結(jié)束且必須屬于一個(gè)node。
節(jié)點(diǎn)
節(jié)點(diǎn)是一組屬性的集合,語(yǔ)法如下:
node_name {
module = "sample";
...
}
- node_name是字母、數(shù)字、下劃線的組合且必須以字母或下劃線開(kāi)頭,字母區(qū)分大小寫。
- 大括號(hào)后無(wú)需添加結(jié)束符“;”。
- root為保留關(guān)鍵字,用于聲明配置表的根節(jié)點(diǎn)。每個(gè)配置表必須以root節(jié)點(diǎn)開(kāi)始。
- root節(jié)點(diǎn)中必須包含module屬性,其值應(yīng)該為一個(gè)字符串,用于表征該配置所屬模塊。
- 節(jié)點(diǎn)中可以增加match_attr屬性,其值為一個(gè)全局唯一的字符串。當(dāng)驅(qū)動(dòng)程序在解析配置時(shí)可以以該屬性的值為參數(shù)調(diào)用查找接口查找到包含該屬性的節(jié)點(diǎn)。
數(shù)據(jù)類型
在屬性定義中使用自動(dòng)數(shù)據(jù)類型,不顯式指定類型,屬性支持的數(shù)據(jù)類型如下:
整型
整型長(zhǎng)度自動(dòng)推斷,根據(jù)實(shí)際數(shù)據(jù)長(zhǎng)度給與最小空間占用的類型。
- 二進(jìn)制,0b前綴,示例:0b1010。
- 八進(jìn)制,0前綴,示例:0664。
- 十進(jìn)制 ,無(wú)前綴,且支持有符號(hào)與無(wú)符號(hào),示例:1024,+1024均合法。驅(qū)動(dòng)程序在讀取負(fù)值時(shí)注意使用有符號(hào)數(shù)讀取接口。
- 十六進(jìn)制,0x前綴,示例:0xff00、0xFF。
字符串
字符串使用雙引號(hào)("")表示。
數(shù)組
數(shù)組元素支持整型、字符串,不支持混合類型。整型數(shù)組中uint32_t uint64_t混用會(huì)向上轉(zhuǎn)型為uint64_t數(shù)組。整型數(shù)組與字符串?dāng)?shù)組示例如下:
attr_foo = [0x01, 0x02, 0x03, 0x04];
attr_bar = ["hello", "world"];
bool類型
bool類型中true表示真,false表示假。
預(yù)處理
include
用于導(dǎo)入其他HCS文件。語(yǔ)法示例如下:
#include "foo.hcs"
#include "../bar.hcs"
- 文件名必須使用雙引號(hào)(""),不在同一目錄使用相對(duì)路徑引用。被include文件也必須是合法的HCS文件。
- 多個(gè)include,如果存在相同的節(jié)點(diǎn),后者覆蓋前者,其余的節(jié)點(diǎn)依次展開(kāi)。
注釋
支持兩種注釋風(fēng)格。
-
單行注釋。
// comment
-
多行注釋。
/* comment */
說(shuō)明:?多行注釋不支持嵌套。
引用修改
引用修改的作用是在當(dāng)前節(jié)點(diǎn)中修改另外任意一個(gè)節(jié)點(diǎn)的內(nèi)容,語(yǔ)法為:
node :& source_node
上述語(yǔ)句表示node中的內(nèi)容是對(duì)source_node節(jié)點(diǎn)內(nèi)容的修改。示例如下:
root {
module = "sample";
foo {
foo_ :& root.bar{
attr = "foo";
}
foo1 :& foo2 {
attr = 0x2;
}
foo2 {
attr = 0x1;
}
}
bar {
attr = "bar";
}
}
最終生成配置樹(shù)為:
root {
module = "sample";
foo {
foo2 {
attr = 0x2;
}
}
bar {
attr = "foo";
}
}
在以上示例中,可以看到foo.foo_節(jié)點(diǎn)通過(guò)引用將bar.attr屬性的值修改為了"foo",foo.foo1節(jié)點(diǎn)通過(guò)引用將foo.foo2.attr屬性的值修改為了0x2。foo.foo_以及foo.foo1節(jié)點(diǎn)表示對(duì)目標(biāo)節(jié)點(diǎn)內(nèi)容的修改,其自身并不會(huì)存在最終生成的配置樹(shù)中。
- 引用同級(jí)node,可以直接使用node名稱,否則被引用的節(jié)點(diǎn)必須使用絕對(duì)路徑,節(jié)點(diǎn)間使用“.”分隔,root表示根節(jié)點(diǎn),格式為root開(kāi)始的節(jié)點(diǎn)路徑序列,例如root.foo.bar即為一個(gè)合法的絕對(duì)路徑。
- 如果出現(xiàn)修改沖突(即多處修改同一個(gè)屬性),編譯器將提示warning,因?yàn)檫@種情況下只會(huì)生效某一個(gè)修改而導(dǎo)致最終結(jié)果不確定。
節(jié)點(diǎn)復(fù)制
節(jié)點(diǎn)復(fù)制可以實(shí)現(xiàn)在節(jié)點(diǎn)定義時(shí)從另一個(gè)節(jié)點(diǎn)先復(fù)制內(nèi)容,用于定義內(nèi)容相似的節(jié)點(diǎn)。語(yǔ)法為:
node : source_node
上述語(yǔ)句表示在定義"node"節(jié)點(diǎn)時(shí)將另一個(gè)節(jié)點(diǎn)"source_node"的屬性復(fù)制過(guò)來(lái)。示例如下:
root {
module = "sample";
foo {
attr_0 = 0x0;
}
bar:foo {
attr_1 = 0x1;
}
}
上述代碼的最終生成配置樹(shù)為:
root {
module = "sample";
foo {
attr_0 = 0x0;
}
bar {
attr_1 = 0x1;
attr_0 = 0x0;
}
}
在上述示例中,編譯后bar節(jié)點(diǎn)既包含attr_0屬性又包含attr_1屬性,在bar中對(duì)attr_0的修改不會(huì)影響到foo。
當(dāng)foo和bar在同級(jí)node中時(shí)可不指定foo的路徑,否則需要使用絕對(duì)路徑引用,絕對(duì)路徑的介紹請(qǐng)參考引用修改。
刪除
要對(duì)include導(dǎo)入的base配置樹(shù)中不需要的節(jié)點(diǎn)或?qū)傩赃M(jìn)行刪除,可以使用delete關(guān)鍵字。下面的舉例中sample1.hcs通過(guò)include導(dǎo)入了sample2.hcs中的配置內(nèi)容,并使用delete刪除了sample2.hcs中的attribute2屬性和foo_2節(jié)點(diǎn),示例如下:
// 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 {
}
}
上述代碼在生成過(guò)程中將會(huì)刪除root.foo_2節(jié)點(diǎn)與attr_2,最終生成配置樹(shù)為:
root {
attr_1 = 0x1;
}
說(shuō)明:?在同一個(gè)HCS文件中不允許使用delete,建議直接刪除不需要的屬性。
屬性引用
為了在解析配置時(shí)快速定位到關(guān)聯(lián)的節(jié)點(diǎn),可以把節(jié)點(diǎn)作為屬性的右值,通過(guò)讀取屬性查找到對(duì)應(yīng)節(jié)點(diǎn)。語(yǔ)法為:
attribute = &node;
上述語(yǔ)句表示attribute的值是一個(gè)節(jié)點(diǎn)node的引用,在解析時(shí)可以用這個(gè)attribute快速定位到node,便于關(guān)聯(lián)和查詢其他node。示例如下:
node1 {
attributes;
}
node2 {
attr_1 = &root.node1;
}
或
node2 {
node1 {
attributes;
}
attr_1 = &node1;
}
模板
模板的用途在于生成嚴(yán)格一致的node結(jié)構(gòu),以便對(duì)同類型node進(jìn)行遍歷和管理。使用template關(guān)鍵字定義模板node,子node通過(guò)雙冒號(hào)“::”聲明繼承關(guān)系。子節(jié)點(diǎn)可以改寫或新增但不能刪除template中的屬性,子節(jié)點(diǎn)中沒(méi)有定義的屬性將使用template中的定義作為默認(rèn)值。示例如下:
root {
module = "sample";
template foo {
attr_1 = 0x1;
attr_2 = 0x2;
}
bar :: foo {
}
bar_1 :: foo {
attr_1 = 0x2;
}
}
? 生成配置樹(shù)如下:
root {
module = "sample";
bar {
attr_1 = 0x1;
attr_2 = 0x2;
}
bar_1 {
attr_1 = 0x2;
attr_2 = 0x2;
}
}
在上述示例中,bar和bar_1節(jié)點(diǎn)繼承了foo節(jié)點(diǎn),生成配置樹(shù)節(jié)點(diǎn)結(jié)構(gòu)與foo保持了完全一致,只是屬性的值不同。
配置生成
? hc-gen是配置生成的工具,可以對(duì)HCS配置語(yǔ)法進(jìn)行檢查并把HCS源文件轉(zhuǎn)化成HCB二進(jìn)制文件。
hc-gen介紹
? hc-gen參數(shù)說(shuō)明:
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]
開(kāi)發(fā)指導(dǎo)
場(chǎng)景介紹
關(guān)于驅(qū)動(dòng)的開(kāi)發(fā)我們主要目的是實(shí)現(xiàn)驅(qū)動(dòng)代碼的編寫,但是驅(qū)動(dòng)開(kāi)發(fā)過(guò)程中需要服務(wù)管理、消息機(jī)制管理,才能使驅(qū)動(dòng)在代碼編譯過(guò)程中進(jìn)行加載。以下開(kāi)發(fā)步驟中介紹了驅(qū)動(dòng)開(kāi)發(fā)、驅(qū)動(dòng)消息機(jī)制管理開(kāi)發(fā)、驅(qū)動(dòng)服務(wù)管理開(kāi)發(fā)的步驟。
驅(qū)動(dòng)開(kāi)發(fā)實(shí)例
基于HDF框架的驅(qū)動(dòng)開(kāi)發(fā)主要分為三個(gè)部分:驅(qū)動(dòng)實(shí)現(xiàn)、驅(qū)動(dòng)編譯腳本編寫和驅(qū)動(dòng)配置。詳細(xì)開(kāi)發(fā)流程如下所示:
驅(qū)動(dòng)實(shí)現(xiàn)
驅(qū)動(dòng)實(shí)現(xiàn)包含驅(qū)動(dòng)業(yè)務(wù)代碼實(shí)現(xiàn)和驅(qū)動(dòng)入口注冊(cè),具體寫法如下:
-
驅(qū)動(dòng)業(yè)務(wù)代碼
#include "hdf_device_desc.h" // HDF框架對(duì)驅(qū)動(dòng)開(kāi)發(fā)相關(guān)能力接口的頭文件 #include "hdf_log.h" // HDF框架提供的日志接口頭文件 #define HDF_LOG_TAG sample_driver // 打印日志所包含的標(biāo)簽,如果不定義則用默認(rèn)定義的HDF_TAG標(biāo)簽。 // 將驅(qū)動(dòng)對(duì)外提供的服務(wù)能力接口綁定到HDF框架。 int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject) { HDF_LOGD("Sample driver bind success"); return HDF_SUCCESS; } // 驅(qū)動(dòng)自身業(yè)務(wù)初始化的接口 int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject) { HDF_LOGD("Sample driver Init success"); return HDF_SUCCESS; } // 驅(qū)動(dòng)資源釋放的接口 void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject) { HDF_LOGD("Sample driver release success"); return; }
-
驅(qū)動(dòng)入口注冊(cè)到HDF框架
// 定義驅(qū)動(dòng)入口的對(duì)象,必須為HdfDriverEntry(在hdf_device_desc.h中定義)類型的全局變量。 struct HdfDriverEntry g_sampleDriverEntry = { .moduleVersion = 1, .moduleName = "sample_driver", .Bind = HdfSampleDriverBind, .Init = HdfSampleDriverInit, .Release = HdfSampleDriverRelease, }; // 調(diào)用HDF_INIT將驅(qū)動(dòng)入口注冊(cè)到HDF框架中。在加載驅(qū)動(dòng)時(shí)HDF框架會(huì)先調(diào)用Bind函數(shù),再調(diào)用Init函數(shù)加載該驅(qū)動(dòng);當(dāng)Init調(diào)用異常時(shí),HDF框架會(huì)調(diào)用Release釋放驅(qū)動(dòng)資源并退出。 HDF_INIT(g_sampleDriverEntry);
驅(qū)動(dòng)編譯腳本編寫
-
LiteOS
涉及Makefile和BUILD.gn修改:
-
Makefile部分:
驅(qū)動(dòng)代碼的編譯必須要使用HDF框架提供的Makefile模板進(jìn)行編譯。
include $(LITEOSTOPDIR)/../../drivers/hdf_core/adapter/khdf/liteos/lite.mk # 【必需】導(dǎo)入hdf預(yù)定義內(nèi)容 MODULE_NAME := #生成的結(jié)果文件 LOCAL_INCLUDE := #本驅(qū)動(dòng)的頭文件目錄 LOCAL_SRCS := #本驅(qū)動(dòng)的源代碼文件 LOCAL_CFLAGS := #自定義的編譯選項(xiàng) include $(HDF_DRIVER) #導(dǎo)入Makefile模板完成編譯
編譯結(jié)果文件鏈接到內(nèi)核鏡像,添加到drivers/hdf_core/adapter/khdf/liteos目錄下的hdf_lite.mk里面,示例如下:
LITEOS_BASELIB += -lxxx #鏈接生成的靜態(tài)庫(kù) LIB_SUBDIRS += #驅(qū)動(dòng)代碼Makefile的目錄
-
BUILD.gn部分:
添加模塊BUILD.gn,可參考如下示例:
import("http://build/lite/config/component/lite_component.gni") import("http://drivers/hdf_core/adapter/khdf/liteos/hdf.gni") module_switch = defined(LOSCFG_DRIVERS_HDF_xxx) module_name = "xxx" hdf_driver(module_name) { sources = [ "xxx/xxx/xxx.c", #模塊要編譯的源碼文件 ] public_configs = [ ":public" ] #使用依賴的頭文件配置 } config("public") { #定義依賴的頭文件配置 include_dirs = [ "xxx/xxx/xxx", #依賴的頭文件目錄 ] }
把新增模塊的BUILD.gn所在的目錄添加到**/drivers/hdf_core/adapter/khdf/liteos/BUILD.gn**里面:
group("liteos") { public_deps = [ ":$module_name" ] deps = [ "xxx/xxx",#新增模塊BUILD.gn所在的目錄,/drivers/hdf_core/adapter/khdf/liteos ] }
-
-
Linux
如果需要定義模塊控制宏,需要在模塊目錄xxx里面添加Kconfig文件,并把Kconfig文件路徑添加到drivers/hdf_core/adapter/khdf/linux/Kconfig里面:
source "drivers/hdf/khdf/xxx/Kconfig" #目錄為hdf模塊軟鏈接到kernel里面的目錄
添加模塊目錄到drivers/hdf_core/adapter/khdf/linux/Makefile:
obj-$(CONFIG_DRIVERS_HDF) += xxx/
在模塊目錄xxx里面添加Makefile文件,在Makefile文件里面添加模塊代碼編譯規(guī)則:
obj-y += xxx.o
驅(qū)動(dòng)配置
HDF使用HCS作為配置描述源碼,HCS詳細(xì)介紹配置管理。
驅(qū)動(dòng)配置包含兩部分,HDF框架定義的驅(qū)動(dòng)設(shè)備描述和驅(qū)動(dòng)的私有配置信息,具體寫法如下:
-
驅(qū)動(dòng)設(shè)備描述(必選)
HDF框架加載驅(qū)動(dòng)所需要的信息來(lái)源于HDF框架定義的驅(qū)動(dòng)設(shè)備描述,因此基于HDF框架開(kāi)發(fā)的驅(qū)動(dòng)必須要在HDF框架定義的device_info.hcs配置文件中添加對(duì)應(yīng)的設(shè)備描述。驅(qū)動(dòng)的設(shè)備描述填寫如下所示:
root { device_info { match_attr = "hdf_manager"; template host { // host模板,繼承該模板的節(jié)點(diǎn)(如下sample_host)如果使用模板中的默認(rèn)值,則節(jié)點(diǎn)字段可以缺省。 hostName = ""; priority = 100; uid = ""; // 用戶態(tài)進(jìn)程uid,缺省為空,會(huì)被配置為hostName的定義值,即普通用戶。 gid = ""; // 用戶態(tài)進(jìn)程gid,缺省為空,會(huì)被配置為hostName的定義值,即普通用戶組。 caps = [""]; // 用戶態(tài)進(jìn)程Linux capabilities配置,缺省為空,需要業(yè)務(wù)模塊按照業(yè)務(wù)需要進(jìn)行配置。 template device { template deviceNode { policy = 0; priority = 100; preload = 0; permission = 0664; moduleName = ""; serviceName = ""; deviceMatchAttr = ""; } } } sample_host :: host{ hostName = "host0"; // host名稱,host節(jié)點(diǎn)是用來(lái)存放某一類驅(qū)動(dòng)的容器。 priority = 100; // host啟動(dòng)優(yōu)先級(jí)(0-200),值越大優(yōu)先級(jí)越低,建議默認(rèn)配100,優(yōu)先級(jí)相同則不保證host的加載順序。 caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"]; // 用戶態(tài)進(jìn)程Linux capabilities配置。 device_sample :: device { // sample設(shè)備節(jié)點(diǎn) device0 :: deviceNode { // sample驅(qū)動(dòng)的DeviceNode節(jié)點(diǎn) policy = 1; // policy字段是驅(qū)動(dòng)服務(wù)發(fā)布的策略,在驅(qū)動(dòng)服務(wù)管理章節(jié)有詳細(xì)介紹。 priority = 100; // 驅(qū)動(dòng)啟動(dòng)優(yōu)先級(jí)(0-200),值越大優(yōu)先級(jí)越低,建議默認(rèn)配100,優(yōu)先級(jí)相同則不保證device的加載順序。 preload = 0; // 驅(qū)動(dòng)按需加載字段。 permission = 0664; // 驅(qū)動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)權(quán)限 moduleName = "sample_driver"; // 驅(qū)動(dòng)名稱,該字段的值必須和驅(qū)動(dòng)入口結(jié)構(gòu)的moduleName值一致。 serviceName = "sample_service"; // 驅(qū)動(dòng)對(duì)外發(fā)布服務(wù)的名稱,必須唯一。 deviceMatchAttr = "sample_config"; // 驅(qū)動(dòng)私有數(shù)據(jù)匹配的關(guān)鍵字,必須和驅(qū)動(dòng)私有數(shù)據(jù)配置表中的match_attr值相等。 } } } } }
說(shuō)明:
- uid、gid、caps等配置項(xiàng)是用戶態(tài)驅(qū)動(dòng)的啟動(dòng)配置,內(nèi)核態(tài)不用配置。
- 根據(jù)進(jìn)程權(quán)限最小化設(shè)計(jì)原則,業(yè)務(wù)模塊uid、gid不用配置,如上面的sample_host,使用普通用戶權(quán)限,即uid和gid被定義為hostName的定義值。
- 如果普通用戶權(quán)限不能滿足業(yè)務(wù)要求,需要把uid、gid定義為system或者root權(quán)限時(shí),請(qǐng)找安全專家進(jìn)行評(píng)審。
- 進(jìn)程的uid在文件base/startup/init/services/etc/passwd中配置,進(jìn)程的gid在文件base/startup/init/services/etc/group中配置,進(jìn)程uid和gid配置參考:系統(tǒng)服務(wù)用戶組添加方法。
- caps值:格式為caps = ["xxx"],如果要配置CAP_DAC_OVERRIDE,此處需要填寫caps = ["DAC_OVERRIDE"],不能填寫為caps = ["CAP_DAC_OVERRIDE"]。
- preload:驅(qū)動(dòng)按需加載字段。
-
驅(qū)動(dòng)私有配置信息(可選)
如果驅(qū)動(dòng)有私有配置,則可以添加一個(gè)驅(qū)動(dòng)的配置文件,用來(lái)填寫一些驅(qū)動(dòng)的默認(rèn)配置信息。HDF框架在加載驅(qū)動(dòng)的時(shí)候,會(huì)將對(duì)應(yīng)的配置信息獲取并保存在HdfDeviceObject中的property里面,通過(guò)Bind和Init(參考驅(qū)動(dòng)實(shí)現(xiàn))傳遞給驅(qū)動(dòng)。驅(qū)動(dòng)的配置信息示例如下:
root { SampleDriverConfig { sample_version = 1; sample_bus = "I2C_0"; match_attr = "sample_config"; // 該字段的值必須和device_info.hcs中的deviceMatchAttr值一致 } }
配置信息定義之后,需要將該配置文件添加到板級(jí)配置入口文件hdf.hcs,示例如下:
#include "device_info/device_info.hcs" #include "sample/sample_config.hcs"
驅(qū)動(dòng)消息機(jī)制管理開(kāi)發(fā)
-
將驅(qū)動(dòng)配置信息中服務(wù)策略policy字段設(shè)置為2(SERVICE_POLICY_CAPACITY,policy定義)。
device_sample :: Device { policy = 2; ... }
-
配置驅(qū)動(dòng)信息中的服務(wù)設(shè)備節(jié)點(diǎn)權(quán)限(permission字段)是框架給驅(qū)動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)的權(quán)限,默認(rèn)是0666,驅(qū)動(dòng)開(kāi)發(fā)者根據(jù)驅(qū)動(dòng)的實(shí)際使用場(chǎng)景配置驅(qū)動(dòng)設(shè)備節(jié)點(diǎn)的權(quán)限。
-
在服務(wù)實(shí)現(xiàn)過(guò)程中,實(shí)現(xiàn)服務(wù)基類成員IDeviceIoService中的Dispatch方法。
// Dispatch是用來(lái)處理用戶態(tài)發(fā)下來(lái)的消息 int32_t SampleDriverDispatch(struct HdfDeviceIoClient *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) { HDF_LOGI("sample driver lite A dispatch"); return HDF_SUCCESS; } int32_t SampleDriverBind(struct HdfDeviceObject *device) { HDF_LOGI("test for lite os sample driver A Open!"); if (device == NULL) { HDF_LOGE("test for lite os sample driver A Open failed!"); return HDF_FAILURE; } static struct ISampleDriverService sampleDriverA = { .ioService.Dispatch = SampleDriverDispatch, .ServiceA = SampleDriverServiceA, .ServiceB = SampleDriverServiceB, }; device->service = (struct IDeviceIoService *)(&sampleDriverA); return HDF_SUCCESS; }
-
驅(qū)動(dòng)定義消息處理函數(shù)中的cmd類型。
#define SAMPLE_WRITE_READ 1 // 讀寫操作碼1
-
用戶態(tài)獲取服務(wù)接口并發(fā)送消息到驅(qū)動(dòng)。
int SendMsg(const char *testMsg) { if (testMsg == NULL) { HDF_LOGE("test msg is null"); return HDF_FAILURE; } struct HdfIoService *serv = HdfIoServiceBind("sample_driver"); if (serv == NULL) { HDF_LOGE("fail to get service"); return HDF_FAILURE; } struct HdfSBuf *data = HdfSbufObtainDefaultSize(); if (data == NULL) { HDF_LOGE("fail to obtain sbuf data"); return HDF_FAILURE; } struct HdfSBuf *reply = HdfSbufObtainDefaultSize(); if (reply == NULL) { HDF_LOGE("fail to obtain sbuf reply"); ret = HDF_DEV_ERR_NO_MEMORY; goto out; } if (!HdfSbufWriteString(data, testMsg)) { HDF_LOGE("fail to write sbuf"); ret = HDF_FAILURE; goto out; } int ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply); if (ret != HDF_SUCCESS) { HDF_LOGE("fail to send service call"); goto out; } out: HdfSbufRecycle(data); HdfSbbufRecycle(reply); HdfIoServiceRecycle(serv); return ret; }
-
用戶態(tài)接收該驅(qū)動(dòng)上報(bào)的消息。
-
用戶態(tài)編寫驅(qū)動(dòng)上報(bào)消息的處理函數(shù)。
static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data) { OsalTimespec time; OsalGetTime(&time); HDF_LOGI("%{public}s received event at %{public}llu.%{public}llu", (char *)priv, time.sec, time.usec); const char *string = HdfSbufReadString(data); if (string == NULL) { HDF_LOGE("fail to read string in event data"); return HDF_FAILURE; } HDF_LOGI("%{public}s: dev event received: %{public}d %{public}s", (char *)priv, id, string); return HDF_SUCCESS; }
-
用戶態(tài)注冊(cè)接收驅(qū)動(dòng)上報(bào)消息的操作方法。
int RegisterListen() { struct HdfIoService *serv = HdfIoServiceBind("sample_driver"); if (serv == NULL) { HDF_LOGE("fail to get service"); return HDF_FAILURE; } static struct HdfDevEventlistener listener = { .callBack = OnDevEventReceived, .priv ="Service0" }; if (HdfDeviceRegisterEventListener(serv, &listener) != 0) { HDF_LOGE("fail to register event listener"); return HDF_FAILURE; } ...... HdfDeviceUnregisterEventListener(serv, &listener); HdfIoServiceRecycle(serv); return HDF_SUCCESS; }
-
驅(qū)動(dòng)上報(bào)事件。
int32_t SampleDriverDispatch(HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) { ... // process api call here return HdfDeviceSendEvent(client->device, cmdCode, data); }
-
驅(qū)動(dòng)服務(wù)管理開(kāi)發(fā)
驅(qū)動(dòng)服務(wù)管理的開(kāi)發(fā)包括驅(qū)動(dòng)服務(wù)的編寫、綁定、獲取或者訂閱,詳細(xì)步驟如下。
驅(qū)動(dòng)服務(wù)編寫
// 驅(qū)動(dòng)服務(wù)結(jié)構(gòu)的定義
struct ISampleDriverService {
struct IDeviceIoService ioService; // 服務(wù)結(jié)構(gòu)的首個(gè)成員必須是IDeviceIoService類型的成員。
int32_t (*ServiceA)(void); // 驅(qū)動(dòng)的第一個(gè)服務(wù)接口。
int32_t (*ServiceB)(uint32_t inputCode); // 驅(qū)動(dòng)的第二個(gè)服務(wù)接口,有多個(gè)可以依次往下累加。
};
// 驅(qū)動(dòng)服務(wù)接口的實(shí)現(xiàn)
int32_t SampleDriverServiceA(void)
{
// 驅(qū)動(dòng)開(kāi)發(fā)者實(shí)現(xiàn)業(yè)務(wù)邏輯
return HDF_SUCCESS;
}
int32_t SampleDriverServiceB(uint32_t inputCode)
{
// 驅(qū)動(dòng)開(kāi)發(fā)者實(shí)現(xiàn)業(yè)務(wù)邏輯
return HDF_SUCCESS;
}
驅(qū)動(dòng)服務(wù)綁定
開(kāi)發(fā)者實(shí)現(xiàn)HdfDriverEntry中的Bind指針函數(shù),如下的SampleDriverBind,把驅(qū)動(dòng)服務(wù)綁定到HDF框架中。
int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject)
{
// deviceObject為HDF框架給每一個(gè)驅(qū)動(dòng)創(chuàng)建的設(shè)備對(duì)象,用來(lái)保存設(shè)備相關(guān)的私有數(shù)據(jù)和服務(wù)接口。
if (deviceObject == NULL) {
HDF_LOGE("Sample device object is null!");
return HDF_FAILURE;
}
static struct ISampleDriverService sampleDriverA = {
.ServiceA = SampleDriverServiceA,
.ServiceB = SampleDriverServiceB,
};
deviceObject->service = &sampleDriverA.ioService;
return HDF_SUCCESS;
}
驅(qū)動(dòng)服務(wù)獲取
應(yīng)用程序開(kāi)發(fā)者獲取驅(qū)動(dòng)服務(wù)有兩種方式:通過(guò)HDF接口直接獲取和通過(guò)HDF提供的訂閱機(jī)制獲取。
通過(guò)HDF接口直接獲取
當(dāng)驅(qū)動(dòng)服務(wù)獲取者明確驅(qū)動(dòng)已經(jīng)加載完成時(shí),獲取該驅(qū)動(dòng)的服務(wù)可以通過(guò)HDF框架提供的能力接口直接獲取,如下所示:
const struct ISampleDriverService *sampleService =
(const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver");
if (sampleService == NULL) {
return HDF_FAILURE;
}
sampleService->ServiceA();
sampleService->ServiceB(5);
通過(guò)HDF提供的訂閱機(jī)制獲取
當(dāng)內(nèi)核態(tài)驅(qū)動(dòng)服務(wù)獲取者對(duì)驅(qū)動(dòng)(同一個(gè)host)加載的時(shí)機(jī)不感知時(shí),可以通過(guò)HDF框架提供的訂閱機(jī)制來(lái)訂閱該驅(qū)動(dòng)服務(wù)。當(dāng)該驅(qū)動(dòng)加載完成時(shí),HDF框架會(huì)將被訂閱的驅(qū)動(dòng)服務(wù)發(fā)布給訂閱者(驅(qū)動(dòng)服務(wù)獲取者),實(shí)現(xiàn)方式如下所示:
// 訂閱回調(diào)函數(shù)的編寫,當(dāng)被訂閱的驅(qū)動(dòng)加載完成后,HDF框架會(huì)將被訂閱驅(qū)動(dòng)的服務(wù)發(fā)布給訂閱者,通過(guò)這個(gè)回調(diào)函數(shù)給訂閱者使用。
// object為訂閱者的私有數(shù)據(jù),service為被訂閱的服務(wù)對(duì)象。
int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service)
{
const struct ISampleDriverService *sampleService =
(const struct ISampleDriverService *)service;
if (sampleService == NULL) {
return HDF_FAILURE;
}
sampleService->ServiceA();
sampleService->ServiceB(5);
}
// 訂閱過(guò)程的實(shí)現(xiàn)
int32_t TestDriverInit(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
HDF_LOGE("Test driver init failed, deviceObject is null!");
return HDF_FAILURE;
}
struct SubscriberCallback callBack;
callBack.deviceObject = deviceObject;
callBack.OnServiceConnected = TestDriverSubCallBack;
int32_t ret = HdfDeviceSubscribeService(deviceObject, "sample_driver", callBack);
if (ret != HDF_SUCCESS) {
HDF_LOGE("Test driver subscribe sample driver failed!");
}
return ret;
}
HDF開(kāi)發(fā)實(shí)例
下面基于HDF框架,提供一個(gè)完整的樣例,包含配置文件的添加,驅(qū)動(dòng)代碼的實(shí)現(xiàn)以及用戶態(tài)程序和驅(qū)動(dòng)交互的流程。
添加配置
在HDF框架的配置文件(例如vendor/hisilicon/xxx/hdf_config/device_info)中添加該驅(qū)動(dòng)的配置信息,如下所示:
root {
device_info {
match_attr = "hdf_manager";
template host {
hostName = "";
priority = 100;
template device {
template deviceNode {
policy = 0;
priority = 100;
preload = 0;
permission = 0664;
moduleName = "";
serviceName = "";
deviceMatchAttr = "";
}
}
}
sample_host :: host {
hostName = "sample_host";
sample_device :: device {
device0 :: deviceNode {
policy = 2;
priority = 100;
preload = 1;
permission = 0664;
moduleName = "sample_driver";
serviceName = "sample_service";
}
}
}
}
}
編寫驅(qū)動(dòng)代碼
基于HDF框架編寫的sample驅(qū)動(dòng)代碼如下:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "hdf_log.h"
#include "hdf_base.h"
#include "hdf_device_desc.h"
#define HDF_LOG_TAG sample_driver
#define SAMPLE_WRITE_READ 123
static int32_t HdfSampleDriverDispatch(
struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
HDF_LOGI("%{public}s: received cmd %{public}d", __func__, id);
if (id == SAMPLE_WRITE_READ) {
const char *readData = HdfSbufReadString(data);
if (readData != NULL) {
HDF_LOGE("%{public}s: read data is: %{public}s", __func__, readData);
}
if (!HdfSbufWriteInt32(reply, INT32_MAX)) {
HDF_LOGE("%{public}s: reply int32 fail", __func__);
}
return HdfDeviceSendEvent(client->device, id, data);
}
return HDF_FAILURE;
}
static void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
// release resources here
return;
}
static int HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
return HDF_FAILURE;
}
static struct IDeviceIoService testService = {
.Dispatch = HdfSampleDriverDispatch,
};
deviceObject->service = &testService;
return HDF_SUCCESS;
}
static int HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
HDF_LOGE("%{public}s::ptr is null!", __func__);
return HDF_FAILURE;
}
HDF_LOGI("Sample driver Init success");
return HDF_SUCCESS;
}
static struct HdfDriverEntry g_sampleDriverEntry = {
.moduleVersion = 1,
.moduleName = "sample_driver",
.Bind = HdfSampleDriverBind,
.Init = HdfSampleDriverInit,
.Release = HdfSampleDriverRelease,
};
HDF_INIT(g_sampleDriverEntry);
編寫用戶程序和驅(qū)動(dòng)交互代碼
基于HDF框架編寫的用戶態(tài)程序和驅(qū)動(dòng)交互的代碼如下(代碼可以放在目錄drivers/hdf_core/adapter/uhdf下面編譯,BUILD.gn可以參考drivers/hdf_core/framework/sample/platform/uart/dev/BUILD.gn):
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"
#define HDF_LOG_TAG sample_test
#define SAMPLE_SERVICE_NAME "sample_service"
#define SAMPLE_WRITE_READ 123
int g_replyFlag = 0;
static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data)
{
const char *string = HdfSbufReadString(data);
if (string == NULL) {
HDF_LOGE("fail to read string in event data");
g_replyFlag = 1;
return HDF_FAILURE;
}
HDF_LOGI("%{public}s: dev event received: %{public}u %{public}s", (char *)priv, id, string);
g_replyFlag = 1;
return HDF_SUCCESS;
}
static int SendEvent(struct HdfIoService *serv, char *eventData)
{
int ret = 0;
struct HdfSBuf *data = HdfSbufObtainDefaultSize();
if (data == NULL) {
HDF_LOGE("fail to obtain sbuf data");
return 1;
}
struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
if (reply == NULL) {
HDF_LOGE("fail to obtain sbuf reply");
ret = HDF_DEV_ERR_NO_MEMORY;
goto out;
}
if (!HdfSbufWriteString(data, eventData)) {
HDF_LOGE("fail to write sbuf");
ret = HDF_FAILURE;
goto out;
}
ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
if (ret != HDF_SUCCESS) {
HDF_LOGE("fail to send service call");
goto out;
}
int replyData = 0;
if (!HdfSbufReadInt32(reply, &replyData)) {
HDF_LOGE("fail to get service call reply");
ret = HDF_ERR_INVALID_OBJECT;
goto out;
}
HDF_LOGI("Get reply is: %{public}d", replyData);
out:
HdfSbufRecycle(data);
HdfSbufRecycle(reply);
return ret;
}
int main()
{
char *sendData = "default event info";
struct HdfIoService *serv = HdfIoServiceBind(SAMPLE_SERVICE_NAME);
if (serv == NULL) {
HDF_LOGE("fail to get service %s", SAMPLE_SERVICE_NAME);
return HDF_FAILURE;
}
static struct HdfDevEventlistener listener = {
.callBack = OnDevEventReceived,
.priv ="Service0"
};
if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
HDF_LOGE("fail to register event listener");
return HDF_FAILURE;
}
if (SendEvent(serv, sendData)) {
HDF_LOGE("fail to send event");
return HDF_FAILURE;
}
while (g_replyFlag == 0) {
sleep(1);
}
if (HdfDeviceUnregisterEventListener(serv, &listener)) {
HDF_LOGE("fail to unregister listener");
return HDF_FAILURE;
}
HdfIoServiceRecycle(serv);
return HDF_SUCCESS;
}
?說(shuō)明:?用戶態(tài)應(yīng)用程序使用了HDF框架中的消息發(fā)送接口,因此在編譯用戶態(tài)程序的過(guò)程中需要依賴HDF框架對(duì)外提供的hdf_core和osal的動(dòng)態(tài)庫(kù),在gn編譯文件中添加如下依賴項(xiàng):
deps = [
? "http://drivers/hdf_core/adapter/uhdf/manager:hdf_core",
? "http://drivers/hdf_core/adapter/uhdf/posix:hdf_posix_osal",
]
最后
有很多小伙伴不知道學(xué)習(xí)哪些鴻蒙開(kāi)發(fā)技術(shù)?不知道需要重點(diǎn)掌握哪些鴻蒙應(yīng)用開(kāi)發(fā)知識(shí)點(diǎn)?而且學(xué)習(xí)時(shí)頻繁踩坑,最終浪費(fèi)大量時(shí)間。所以有一份實(shí)用的鴻蒙(HarmonyOS NEXT)資料用來(lái)跟著學(xué)習(xí)是非常有必要的。?
這份鴻蒙(HarmonyOS NEXT)資料包含了鴻蒙開(kāi)發(fā)必掌握的核心知識(shí)要點(diǎn),內(nèi)容包含了(ArkTS、ArkUI開(kāi)發(fā)組件、Stage模型、多端部署、分布式應(yīng)用開(kāi)發(fā)、音頻、視頻、WebGL、OpenHarmony多媒體技術(shù)、Napi組件、OpenHarmony內(nèi)核、Harmony南向開(kāi)發(fā)、鴻蒙項(xiàng)目實(shí)戰(zhàn)等等)鴻蒙(HarmonyOS NEXT)技術(shù)知識(shí)點(diǎn)。
希望這一份鴻蒙學(xué)習(xí)資料能夠給大家?guī)?lái)幫助,有需要的小伙伴自行領(lǐng)取,限時(shí)開(kāi)源,先到先得~無(wú)套路領(lǐng)?。?!
獲取這份完整版高清學(xué)習(xí)路線,請(qǐng)點(diǎn)擊→純血版全套鴻蒙HarmonyOS學(xué)習(xí)資料
鴻蒙(HarmonyOS NEXT)最新學(xué)習(xí)路線
-
?HarmonOS基礎(chǔ)技能
-
HarmonOS就業(yè)必備技能?
- ?HarmonOS多媒體技術(shù)
- 鴻蒙NaPi組件進(jìn)階
- HarmonOS高級(jí)技能
-
初識(shí)HarmonOS內(nèi)核?
- 實(shí)戰(zhàn)就業(yè)級(jí)設(shè)備開(kāi)發(fā)
有了路線圖,怎么能沒(méi)有學(xué)習(xí)資料呢,小編也準(zhǔn)備了一份聯(lián)合鴻蒙官方發(fā)布筆記整理收納的一套系統(tǒng)性的鴻蒙(OpenHarmony )學(xué)習(xí)手冊(cè)(共計(jì)1236頁(yè))與鴻蒙(OpenHarmony )開(kāi)發(fā)入門教學(xué)視頻,內(nèi)容包含:ArkTS、ArkUI、Web開(kāi)發(fā)、應(yīng)用模型、資源分類…等知識(shí)點(diǎn)。
獲取以上完整版高清學(xué)習(xí)路線,請(qǐng)點(diǎn)擊→純血版全套鴻蒙HarmonyOS學(xué)習(xí)資料
《鴻蒙 (OpenHarmony)開(kāi)發(fā)入門教學(xué)視頻》
《鴻蒙生態(tài)應(yīng)用開(kāi)發(fā)V2.0白皮書》
《鴻蒙 (OpenHarmony)開(kāi)發(fā)基礎(chǔ)到實(shí)戰(zhàn)手冊(cè)》
OpenHarmony北向、南向開(kāi)發(fā)環(huán)境搭建
?《鴻蒙開(kāi)發(fā)基礎(chǔ)》
- ArkTS語(yǔ)言
- 安裝DevEco Studio
- 運(yùn)用你的第一個(gè)ArkTS應(yīng)用
- ArkUI聲明式UI開(kāi)發(fā)
- .……
?《鴻蒙開(kāi)發(fā)進(jìn)階》
- Stage模型入門
- 網(wǎng)絡(luò)管理
- 數(shù)據(jù)管理
- 電話服務(wù)
- 分布式應(yīng)用開(kāi)發(fā)
- 通知與窗口管理
- 多媒體技術(shù)
- 安全技能
- 任務(wù)管理
- WebGL
- 國(guó)際化開(kāi)發(fā)
- 應(yīng)用測(cè)試
- DFX面向未來(lái)設(shè)計(jì)
- 鴻蒙系統(tǒng)移植和裁剪定制
- ……
《鴻蒙進(jìn)階實(shí)戰(zhàn)》
- ArkTS實(shí)踐
- UIAbility應(yīng)用
- 網(wǎng)絡(luò)案例
- ……
?獲取以上完整鴻蒙HarmonyOS學(xué)習(xí)資料,請(qǐng)點(diǎn)擊→純血版全套鴻蒙HarmonyOS學(xué)習(xí)資料
總結(jié)
總的來(lái)說(shuō),華為鴻蒙不再兼容安卓,對(duì)中年程序員來(lái)說(shuō)是一個(gè)挑戰(zhàn),也是一個(gè)機(jī)會(huì)。只有積極應(yīng)對(duì)變化,不斷學(xué)習(xí)和提升自己,他們才能在這個(gè)變革的時(shí)代中立于不敗之地。?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-859562.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-859562.html
到了這里,關(guān)于Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!