国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程

這篇具有很好參考價(jià)值的文章主要介紹了Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

概述

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)模型

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

功能描述

驅(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?配置使用流程圖

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

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ā)

  1. 將驅(qū)動(dòng)配置信息中服務(wù)策略policy字段設(shè)置為2(SERVICE_POLICY_CAPACITY,policy定義)。

    device_sample :: Device {
        policy = 2;
        ...
    }
  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)限。

  3. 在服務(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;
    }
  4. 驅(qū)動(dòng)定義消息處理函數(shù)中的cmd類型。

    #define SAMPLE_WRITE_READ 1    // 讀寫操作碼1
  5. 用戶態(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;
    }
  6. 用戶態(tài)接收該驅(qū)動(dòng)上報(bào)的消息。

    1. 用戶態(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;
      }
    2. 用戶態(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;
      }
    3. 驅(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í)路線

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

  • ?HarmonOS基礎(chǔ)技能

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

  • HarmonOS就業(yè)必備技能?Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux
  • ?HarmonOS多媒體技術(shù)

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

  • 鴻蒙NaPi組件進(jìn)階

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

  • HarmonOS高級(jí)技能

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

  • 初識(shí)HarmonOS內(nèi)核?Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux
  • 實(shí)戰(zhàn)就業(yè)級(jí)設(shè)備開(kāi)發(fā)

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

有了路線圖,怎么能沒(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é)視頻》

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

《鴻蒙生態(tài)應(yīng)用開(kāi)發(fā)V2.0白皮書》

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

《鴻蒙 (OpenHarmony)開(kāi)發(fā)基礎(chǔ)到實(shí)戰(zhàn)手冊(cè)》

OpenHarmony北向、南向開(kāi)發(fā)環(huán)境搭建

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

?《鴻蒙開(kāi)發(fā)基礎(chǔ)》

  • ArkTS語(yǔ)言
  • 安裝DevEco Studio
  • 運(yùn)用你的第一個(gè)ArkTS應(yīng)用
  • ArkUI聲明式UI開(kāi)發(fā)
  • .……

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

?《鴻蒙開(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)移植和裁剪定制
  • ……

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

《鴻蒙進(jìn)階實(shí)戰(zhàn)》

  • ArkTS實(shí)踐
  • UIAbility應(yīng)用
  • 網(wǎng)絡(luò)案例
  • ……

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux

?獲取以上完整鴻蒙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í)代中立于不敗之地。?

Harmony鴻蒙南向驅(qū)動(dòng)開(kāi)發(fā)流程,OpenHarmony,鴻蒙南向開(kāi)發(fā),鴻蒙,harmonyos,華為,鴻蒙,鴻蒙系統(tǒng),驅(qū)動(dòng)開(kāi)發(fā),linux文章來(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)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • OpenHarmony鴻蒙南向開(kāi)發(fā)案例:【智能門鈴】

    OpenHarmony鴻蒙南向開(kāi)發(fā)案例:【智能門鈴】

    樣例簡(jiǎn)介 智能門鈴?fù)ㄟ^(guò)監(jiān)控來(lái)訪者信息,告訴主人門外是否有人按鈴、有陌生人靠近或者無(wú)人狀態(tài)。主人可以在數(shù)字管家中遠(yuǎn)程接收消息,并根據(jù)需要進(jìn)行遠(yuǎn)程取消報(bào)警和一鍵開(kāi)鎖。同時(shí),也可以通過(guò)室內(nèi)屏幕獲取門外狀態(tài)。室內(nèi)屏幕顯示界面使用DevEco Studio 編寫的js應(yīng)用,

    2024年04月26日
    瀏覽(17)
  • OpenHarmony鴻蒙南向開(kāi)發(fā)案例:【智能貓眼(基于3518開(kāi)發(fā)板)】

    OpenHarmony鴻蒙南向開(kāi)發(fā)案例:【智能貓眼(基于3518開(kāi)發(fā)板)】

    樣例簡(jiǎn)介 本Demo是基于Hi3518開(kāi)發(fā)板,使用開(kāi)源OpenHarmony開(kāi)發(fā)的RTSP協(xié)議流媒體應(yīng)用。達(dá)到將Hi3518開(kāi)發(fā)板中攝像頭獲取的數(shù)據(jù)通過(guò)RTSP協(xié)議傳輸?shù)绞謾C(jī)并顯示 。 rtsp實(shí)現(xiàn)可參考文檔:openharmony_1.0.1實(shí)現(xiàn)RTSPServer 運(yùn)行效果 樣例原理 如上圖所示,手機(jī)播放3518攝像頭采集的視頻數(shù)據(jù)。 工

    2024年04月28日
    瀏覽(41)
  • HarmonyOS 鴻蒙開(kāi)發(fā)DevEco Studio OpenHarmony:創(chuàng)建OpenHarmony工程

    目錄 創(chuàng)建和配置新工程 將原子化服務(wù)工程改為應(yīng)用工程 當(dāng)開(kāi)始開(kāi)發(fā)一個(gè)OpenHarmony應(yīng)用/服務(wù)時(shí),首先需要根據(jù)工程創(chuàng)建向?qū)В瑒?chuàng)建一個(gè)新的工程,工具會(huì)自動(dòng)生成對(duì)應(yīng)的代碼和資源模板。 說(shuō)明 在運(yùn)行DevEco Studio工程時(shí),建議每一個(gè)運(yùn)行窗口有2GB以上的可用內(nèi)存空間。 通過(guò)如下

    2024年01月25日
    瀏覽(22)
  • 鴻蒙應(yīng)用開(kāi)發(fā)學(xué)習(xí)路線(OpenHarmony/HarmonyOS)

    鴻蒙應(yīng)用開(kāi)發(fā)學(xué)習(xí)路線(OpenHarmony/HarmonyOS)

    作者:堅(jiān)果 團(tuán)隊(duì):堅(jiān)果派 公眾號(hào):“大前端之旅” 潤(rùn)開(kāi)鴻技術(shù)專家,華為HDE,InfoQ簽約作者,OpenHarmony布道師,擅長(zhǎng)HarmonyOS應(yīng)用開(kāi)發(fā)、熟悉服務(wù)卡片開(kāi)發(fā),在“戰(zhàn)碼先鋒”活動(dòng)中作為大隊(duì)長(zhǎng),累計(jì)培養(yǎng)三個(gè)小隊(duì)長(zhǎng),帶領(lǐng)100+隊(duì)員完成Pr的提交合入。 歡迎通過(guò)主頁(yè)或者私信聯(lián)系

    2024年02月15日
    瀏覽(97)
  • 鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)能找到工作么?_harmony os 應(yīng)用開(kāi)發(fā)前景

    鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)能找到工作么?_harmony os 應(yīng)用開(kāi)發(fā)前景

    四、如何學(xué)習(xí)鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)技術(shù)? 為了能夠幫助大家快速掌握鴻蒙(Harmony NEXT)應(yīng)用開(kāi)發(fā)技術(shù)知識(shí)。 首先得是開(kāi)發(fā)語(yǔ)言 ArkTS,這個(gè)尤為重要,然后就是ArkUI聲明式UI開(kāi)發(fā)、Stage模型、網(wǎng)絡(luò)/數(shù)據(jù)庫(kù)管理、分布式應(yīng)用開(kāi)發(fā)、進(jìn)程間通信與線程間通信技術(shù)、OpenHarmony多媒體技

    2024年04月27日
    瀏覽(32)
  • HarmonyOS 鴻蒙開(kāi)發(fā)DevEco Studio OpenHarmony:配置開(kāi)發(fā)環(huán)境

    目錄 下載OpenHarmony SDK及工具鏈 參考信息 配置DevEco Studio代理 配置NPM代理 在進(jìn)行OpenHarmony應(yīng)用/服務(wù)開(kāi)發(fā)前,需要提前在DevEco Studio中下載對(duì)應(yīng)版本的SDK。下載OpenHarmony SDK需要連接網(wǎng)絡(luò),一般情況下,可以直接下載;但部分用戶的網(wǎng)絡(luò)可能受限,此時(shí)需要先根據(jù)參考信息 配置相

    2024年02月19日
    瀏覽(93)
  • HarmonyOS 鴻蒙開(kāi)發(fā)DevEco Studio OpenHarmony:使用低代碼進(jìn)行開(kāi)發(fā)

    HarmonyOS 鴻蒙開(kāi)發(fā)DevEco Studio OpenHarmony:使用低代碼進(jìn)行開(kāi)發(fā)

    OpenHarmony低代碼開(kāi)發(fā)方式,具有豐富的UI界面編輯功能,遵循JS、TS開(kāi)發(fā)規(guī)范 ,通過(guò)可視化界面開(kāi)發(fā)方式快速構(gòu)建布局,可有效降低用戶的時(shí)間成本和提升用戶構(gòu)建UI界面的效率。 說(shuō)明 支持使用低代碼進(jìn)行JS/eTS頁(yè)面開(kāi)發(fā),本章節(jié)以開(kāi)發(fā)eTS頁(yè)面為例,介紹低代碼功能及使用方法。

    2024年02月19日
    瀏覽(88)
  • HarmonyOS 鴻蒙開(kāi)發(fā)DevEco Studio OpenHarmony:編譯構(gòu)建概述

    目錄 OpenHarmony構(gòu)建體系 構(gòu)建工具Hvigor 構(gòu)建插件hvigor-ohos-plugin 工程目錄及配置文件說(shuō)明 如何構(gòu)建應(yīng)用/服務(wù) 啟動(dòng)應(yīng)用/服務(wù)構(gòu)建 查看編譯過(guò)程

    2024年02月22日
    瀏覽(93)
  • 鴻蒙OpenHarmony HDF 驅(qū)動(dòng)開(kāi)發(fā)

    鴻蒙OpenHarmony HDF 驅(qū)動(dòng)開(kāi)發(fā)

    最近忙于適配OpenHarmonyOS LiteOS-M 平臺(tái),已經(jīng)成功實(shí)踐適配平臺(tái)GD32F407、STM32F407、STM32G474板卡,LiteOS適配已經(jīng)算是有實(shí)際經(jīng)驗(yàn)了。 但是,鴻蒙代碼學(xué)習(xí)進(jìn)度慢下來(lái)了。還是得不斷學(xué)習(xí)理論知識(shí)豐富自己的認(rèn)知。接下來(lái)時(shí)間要把HDF驅(qū)動(dòng)框架熟悉,完善南向開(kāi)發(fā)技術(shù)點(diǎn)。 HDF(Hardwa

    2024年03月16日
    瀏覽(20)
  • OpenHarmony南向開(kāi)發(fā)案例:【智能風(fēng)扇】

    OpenHarmony南向開(kāi)發(fā)案例:【智能風(fēng)扇】

    樣例簡(jiǎn)介 智能風(fēng)扇設(shè)備不僅可以接收數(shù)字管家應(yīng)用下發(fā)的指令來(lái)控制風(fēng)扇開(kāi)啟的時(shí)間,調(diào)節(jié)風(fēng)扇擋位,更改風(fēng)扇定時(shí)時(shí)間,而且還可以加入到數(shù)字管家的日程管理中。通過(guò)日程可以設(shè)定風(fēng)扇相關(guān)的任務(wù),使其在特定的時(shí)間段內(nèi),風(fēng)扇自動(dòng)打開(kāi)或者關(guān)閉,調(diào)節(jié)擋位大小和定時(shí)時(shí)

    2024年04月16日
    瀏覽(25)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包