瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工藝,搭載一顆四核Cortex-A55處理器和Mali G52 2EE 圖形處理器。RK3568 支持4K 解碼和 1080P 編碼,支持SATA/PCIE/USB3.0 外圍接口。RK3568內置獨立NPU,可用于輕量級人工智能應用。RK3568 支持安卓 11 和 linux 系統,主要面向物聯網網關、NVR 存儲、工控平板、工業檢測、工控盒、卡拉 OK、云終端、車載中控等行業。

?
【本文摘自】【北京迅為】iTOP-RK3568OpenHarmony系統南向驅動開發
【相關視頻】OpenHarmony學習開發系列教程(第1期 北向基礎篇一)
OpenHarmony學習開發系列教程(第2期 南向基礎篇一)
第3章 實操-HDF驅動配置LED
從本章節開始,我們來實操一下,配置HDF驅動控制LED。
3.1 查看原理圖
首先打開底板原理圖,如下圖所示:

由上圖可以看出,LED燈是由GPIO0_B7控制的。當GPIO0_B7為高電平時,三極管Q16導通,LED9點亮。當GPIO0_B7為低電平時,三極管Q16截止,LED9不亮。由1.2小節可以計算出GPIO的引腳編號是15。
3.2 修改HCS硬件配置
驅動的設備描述修改/vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs文件,添加如下代碼,如下所示:
device_topeet_led :: device {
device0::deviceNode {
policy = 2;
priority = 100;
preload = 0;
permission = 0666;
moduleName = "topeet_led_driver";
serviceName = "topeet_led_service";
deviceMatchAttr = "topeet_led_config";
}
}

接下來解釋一下上面的節點配置
device_topeet_led設備節點歸類于platform這個host
device_topeet_led :: device表示led類設備
device0::deviceNode表示led類設備下的某個具體設備節點的配置
policy = 2;表示驅動服務發布策略,內核態用戶態都可調用
priority = 100;表示驅動啟動優先級
preload = 0;表示驅動按需加載字段,啟動加載
permission = 0666;表示驅動創建設備節點
moduleName = "topeet_led_driver";表示驅動名稱是topeet_led_driver,必須和驅動入口結構中的moduleName值一致。
serviceName = "topeet_led_service";表示驅動對外發布服務的名稱,必須唯一
deviceMatchAttr = "topeet_led_config";表示驅動私有數據匹配關鍵詞,必須和驅動私有數據配置節點的match_attr匹配
3.3 創建私有配置文件
接下來新建vendor/hihope/rk3568/hdf_config/khdf/topeet/topeet_config.hcs文件,topeet_config.hcs為驅動私有配置文件,用來填寫一些驅動的默認配置信息。HDF 框架在加載驅動時,會獲取相應的配置信息并將其保存在 HdfDeviceObject 的 property 中。這些配置信息通過 Bind 和 Init 方法傳遞給驅動。
topeet_config.hcs具體內容如下所示:
root {
platform{
topeet_led_config {
//該字段的值必須和device_info.hcs中的deviceMatchAttr一致
match_attr = "topeet_led_config";
led_version = 1;//版本號
led_number = 15;//GPIO引腳號
}
}
}
驅動私有配置文件寫完之后,我們需要將該配置文件添加到板級配置入口文件vendor/hihope/rk3568/hdf_config/khdf/hdf.hcs中,如下圖所示:

3.4 新增topeet子系統
在Openharmony源碼根目錄下新建topeet文件夾及其文件夾下的文件。目錄如下所示:

接下來依次解釋一下每個文件的作用。
bundle.json:
demos:組件目錄
hdf_led:子組件目錄
app:led應用層目錄
├── BUILD.gn:應用APP的GN文件
└── led_test.c:應用層LED測試程序
driver:內核HDF驅動程序目錄
├── led_driver.c:內核LED HDF驅動程序
└── Makefile:內核LED HDF驅動編譯腳本
3.4.1 編寫bundle.json文件
bundle.json文件內容如下所示:
{
"name":"@ohos/demos",
"description":"topeet demos",
"version":"4.1",
"license":"Apache-2.0",
"publishAs":"code-segment",
"segment":{
"destPath":"topeet/demos"
},
"dirs":{},
"scripts":{},
"component":{
"name":"demos",
"subsystem":"topeet",
"features":[],
"syscap":[],
"adapted_system_type":["standard"],
"rom":"675KB",
"ram":"7400KB",
"deps":{
"components":[
"c_utils",
"hilog",
"hdf_core",
"napi"
],
"third_party":[]
},
"build":{
"sub_component":[
"http://topeet/demos/hdf_led/app:led_test"
]
}
}
}
下面是對各個字段的解釋:
name: "@ohos/demos" - 這是組件或項目的名稱,這里表示它屬于OHOS(OpenHarmony OS)生態系統下的一個名為"demos"的組件。
description: "topeet demos" -它描述了組件的簡短說明
version: "4.1" - 組件的版本號。
license: "Apache-2.0" - 組件使用的許可證類型,這里是Apache 2.0許可證。
publishAs: "code-segment" - 表示這個組件或項目是以代碼段的形式發布的。
segment:
destPath: "topeet/demos" - 代碼段的目標路徑,即這個組件或項目在系統中的存放位置。
dirs: {} - 一個空對象,可能用于定義與組件相關的目錄結構,但在這個配置中未使用。
scripts: {} - 一個空對象,可能用于定義與組件相關的腳本,如構建腳本、測試腳本等,但在這個配置中未使用。
component:
name: "demos" - 組件的名稱。
subsystem: "topeet" - 組件所屬的子系統名稱。
features: [] - 組件的功能列表,這里為空,表示沒有列出特定功能。
syscap: [] - 系統能力列表,這里為空,表示沒有列出特定的系統能力。
adapted_system_type: ["standard"] - 適配的系統類型,這里表示適用于標準系統。
rom: "675KB" - 組件所需的ROM大小。
ram: "7400KB" - 組件所需的RAM大小。
deps:
components: ["c_utils", "hilog", "hdf_core", "napi"] - 組件依賴的其他組件列表。
third_party: [] - 第三方依賴列表,這里為空。
build:
sub_component: ["http://topeet/demos/hdf_led/app:led_test"] - 構建時包含的子組件路徑,這里指定了一個具體的構建目標。
這個JSON配置文件提供了關于如何構建、部署和管理這個名為"demos"的組件的詳細信息。它定義了組件的基本屬性、依賴關系、構建信息以及目標系統類型等。
3.4.2 編寫內核LED HDF驅動程序
接下來編譯LED驅動,該驅動用于在基于華為設備框架(HDF)的系統中控制LED燈的開關,完整代碼如下所示:
#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "gpio_if.h"
#define HDF_LOG_TAG led_driver
#define LED_WRITE 1
#define LED_VERSION 1
#define LED_ON 1
#define LED_OFF 0
struct Led_config{
uint32_t led_version;
uint32_t led_number;
};
struct Led_config g_LedCfg = {0};
/**
* @brief 控制LED的GPIO引腳
*
* 根據傳入的GPIO引腳號和模式,控制LED的開關狀態。
*
* @param gpio GPIO引腳號
* @param mode 控制模式,LED_ON表示打開LED,LED_OFF表示關閉LED
*
* @return 成功返回HDF_SUCCESS,失敗返回HDF_FAILURE
*/
static int32_t LedGpioCtl(uint16_t gpio, uint32_t mode){
// 設置GPIO電平為高電平
uint16_t level = GPIO_VAL_HIGH;
// 設置GPIO為輸出方向
if(HDF_SUCCESS != GpioSetDir(gpio, GPIO_DIR_OUT)){
// 設置GPIO方向失敗
HDF_LOGE("GpioSetDir fail");
return HDF_FAILURE;
}
// 根據mode設置GPIO電平
if(mode == LED_ON){
level = GPIO_VAL_HIGH;
}else if(mode==LED_OFF){
level = GPIO_VAL_LOW;
}
// 日志記錄GPIO操作
HDF_LOGE("%s:Write gpio %d:%d",__func__,gpio,mode);
// 向GPIO寫入電平
if(HDF_SUCCESS != GpioWrite(gpio, level)){
// 寫入GPIO電平失敗
HDF_LOGE("GpioWrite fail",__func__);
}
return HDF_SUCCESS;
}
/**
* @brief 驅動LED設備
*
* 根據傳入的命令ID和數據,控制LED設備的狀態。
*
* @param client HDF設備客戶端指針
* @param cmdId 命令ID,用于指示執行的操作類型
* @param dataBuf 輸入數據緩沖區指針,包含需要傳遞給設備的數據
* @param replyBuf 輸出數據緩沖區指針,用于存儲設備返回的數據
*
* @return 返回操作結果,成功返回HDF_SUCCESS,失敗返回相應的錯誤碼
*/
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int32_t cmdId, struct HdfSBuf *dataBuf, struct HdfSBuf *replyBuf){
int32_t result = HDF_FAILURE;
int32_t LedMode = 0;
// 檢查客戶端和設備是否為空
if(client == NULL || client->device == NULL){
HDF_LOGE("driver device is NULL");
return HDF_ERR_INVALID_OBJECT;
}
// 檢查LED配置版本是否支持
if(g_LedCfg.led_version != LED_VERSION){
HDF_LOGE("led version is not support");
return HDF_FAILURE;
}
switch(cmdId){
case LED_WRITE:
// 從數據緩沖區讀取LED模式
result = HdfSbufReadInt32(dataBuf,&LedMode);
if(result ){
// 根據LED模式控制GPIO
LedGpioCtl(g_LedCfg.led_number, (LedMode == LED_ON) ? LED_ON: LED_OFF);
}
break;
default:
// 不支持的命令ID
HDF_LOGE("cmdId is not support");
break;
}
return result;
}
/**
* @brief 綁定LED設備驅動
*
* 將LED設備驅動綁定到HDF設備對象上。
*
* @param deviceObject HDF設備對象指針
*
* @return 返回HDF狀態碼,成功返回HDF_SUCCESS,失敗返回相應的錯誤碼
*/
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject){
// 檢查deviceObject是否為空
if(deviceObject == NULL){
// 如果為空,則記錄錯誤日志并返回錯誤碼
HDF_LOGE("HdfLedDriverBind: %s failed",__func__);
return HDF_ERR_INVALID_OBJECT;
}
// 定義一個靜態的IDeviceIoService結構體變量ledDriverServ
static struct IDeviceIoService ledDriverServ = {
.Dispatch = LedDriverDispatch,
};
// 將ledDriverServ的地址賦值給deviceObject的service成員
deviceObject->service =(struct IDeviceIoService *)(&ledDriverServ);
// 記錄綁定成功的日志,包括設備名稱
HDF_LOGI("g_LedDriverEntry: %s success NodeName[%s]", __func__, deviceObject->property->name);
// 返回成功碼
return HDF_SUCCESS;
}
/**
* @brief 初始化HDF LED驅動
*
* 該函數用于初始化HDF LED驅動,從HCS配置文件中讀取硬件相關配置屬性。
*
* @param deviceObject 設備對象指針
*
* @return 初始化結果
* - HDF_SUCCESS: 初始化成功
* - HDF_ERR_INVALID_OBJECT: 設備對象無效
* - HDF_FAILURE: 初始化失敗
*/
int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject){
// 檢查deviceObject是否為空
if(deviceObject == NULL){
HDF_LOGE("g_LedDriverEntry: %s failed",__func__);
return HDF_ERR_INVALID_OBJECT;
}
// 獲取DeviceResourceIface實例
struct DeviceResourceIface *cfgops= NULL;
cfgops = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
// 檢查cfgops及其方法GetUint32是否有效
if (cfgops == NULL || cfgops->GetUint32 == NULL) {
HDF_LOGE("%s:DeviceResourceGetIfaceInstance failed", __func__);
return HDF_FAILURE;
}
// 讀取hcs配置中的硬件相關配置屬性:led_version
// 讀取led_version
if(cfgops->GetUint32(deviceObject->property,"led_version",&g_LedCfg.led_version,0)!= HDF_SUCCESS){
HDF_LOGE("%s: read led_version failed", __func__);
return HDF_FAILURE;
}
// 讀取引腳號:led_number
// 讀取led_number
if(cfgops->GetUint32(deviceObject->property,"led_number",&g_LedCfg.led_number,0)!= HDF_SUCCESS){
HDF_LOGE("%s:Gread led_number failed", __func__);
return HDF_FAILURE;
}
// 打印初始化成功日志
HDF_LOGI("g_LedDriverEntry: %s success", __func__);
return HDF_SUCCESS;
}
/**
* @brief 釋放HDF LED驅動資源
*
* 該函數用于釋放HDF LED驅動的資源。如果傳入的HdfDeviceObject指針為空,則打印錯誤日志并直接返回。
* 如果HdfDeviceObject指針不為空,則打印成功日志并返回。
*
* @param HdfDeviceObject HDF設備對象指針
*/
void HdfLedDriverRelease(struct HdfDeviceObject *HdfDeviceObject){
// 如果傳入的HdfDeviceObject為空
if(HdfDeviceObject == NULL){
// 打印錯誤日志
HDF_LOGE("HdfLedDriverRelease: %s failed",__func__);
// 返回
return;
}
// 打印成功日志
HDF_LOGI("HdfLedDriverRelease: %s success", __func__);
// 返回
return;
}
//定義了一個結構體HdfDriverEntry的實例g_LedDriverEntry,并初始化了它的成員變量
struct HdfDriverEntry g_LedDriverEntry = {
.moduleVersion = 1,
.moduleName = "topeet_led_driver",
.Bind = HdfLedDriverBind,
.Init = HdfLedDriverInit,
.Release = HdfLedDriverRelease,
};
//使用HDF_INIT宏來注冊或初始化這個結構體實例g_LedDriverEntry
HDF_INIT(g_LedDriverEntry);
3.4.3 接口函數
在一小節的代碼中實現了一個簡單的LED驅動,下面是對代碼的詳細解釋:
包含的頭文件如下所示:
#include "device_resource_if.h":提供設備資源接口,用于從配置文件中讀取設備信息
#include "hdf_device_desc.h":包含HDF設備描述相關的定義
#include "hdf_log.h":提供日志記錄功能
#include "gpio_if.h:提供GPIO接口,用于控制LED燈的開關
宏定義如下所示:
#define HDF_LOG_TAG led_driver :定義日志標簽,用于區分不同模塊的日志
#define LED_WRITE 1:定義LED控制命令的ID
#define LED_VERSION 1: 定義LED驅動的版本號
#define LED_ON 1 :定義LED燈打開的狀態
#define LED_OFF 0:定義LED燈關閉的狀態
數據結構如下所示:
struct Led_config{ //led_config結構體用于存儲LED配置信息,包括LED驅動版本號和LED GPIO編號
uint32_t led_version;
uint32_t led_number;
};
struct Led_config g_LedCfg = {0}; //全局變量,用于存儲LED配置
g_LedDriverEntry結構體是驅動入口結構體,如下所示,包含了驅動的版本號、模塊名、綁定、初始化和釋放函數。
struct HdfDriverEntry g_LedDriverEntry = {
.moduleVersion = 1,
.moduleName = "topeet_led_driver",
.Bind = HdfLedDriverBind,
.Init = HdfLedDriverInit,
.Release = HdfLedDriverRelease,
};
HDF_INIT(g_LedDriverEntry);
HdfLedDriverInit函數是驅動初始化函數。
參數:deviceObject(設備對象)。
流程:獲取設備資源接口,讀取設備配置中的led_version和led_number(GPIO號),并保存到全局配置變量中。
int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject){
// 檢查deviceObject是否為空
if(deviceObject == NULL){
HDF_LOGE("g_LedDriverEntry: %s failed",__func__);
return HDF_ERR_INVALID_OBJECT;
}
// 獲取DeviceResourceIface實例
struct DeviceResourceIface *cfgops= NULL;
cfgops = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
// 檢查cfgops及其方法GetUint32是否有效
if (cfgops == NULL || cfgops->GetUint32 == NULL) {
HDF_LOGE("%s:DeviceResourceGetIfaceInstance failed", __func__);
return HDF_FAILURE;
}
// 讀取hcs配置中的硬件相關配置屬性:led_version
// 讀取led_version
if(cfgops->GetUint32(deviceObject->property,"led_version",&g_LedCfg.led_version,0)!= HDF_SUCCESS){
HDF_LOGE("%s: read led_version failed", __func__);
return HDF_FAILURE;
}
// 讀取引腳號:led_number
// 讀取led_number
if(cfgops->GetUint32(deviceObject->property,"led_number",&g_LedCfg.led_number,0)!= HDF_SUCCESS){
HDF_LOGE("%s:Gread led_number failed", __func__);
return HDF_FAILURE;
}
// 打印初始化成功日志
HDF_LOGI("g_LedDriverEntry: %s success", __func__);
return HDF_SUCCESS;
}
HdfLedDriverRelease:驅動釋放函數。
參數:HdfDeviceObject(設備對象)。
流程:記錄日志,表示驅動釋放成功。
void HdfLedDriverRelease(struct HdfDeviceObject *HdfDeviceObject){
// 如果傳入的HdfDeviceObject為空
if(HdfDeviceObject == NULL){
// 打印錯誤日志
HDF_LOGE("HdfLedDriverRelease: %s failed",__func__);
// 返回
return;
}
// 打印成功日志
HDF_LOGI("HdfLedDriverRelease: %s success", __func__);
// 返回
return;
}
HdfLedDriverBind:綁定解析函數
參數:deviceObject(設備對象)。
流程:將LED驅動的服務對象賦值給設備對象的服務成員。
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject){
// 檢查deviceObject是否為空
if(deviceObject == NULL){
// 如果為空,則記錄錯誤日志并返回錯誤碼
HDF_LOGE("HdfLedDriverBind: %s failed",__func__);
return HDF_ERR_INVALID_OBJECT;
}
// 定義一個靜態的IDeviceIoService結構體變量ledDriverServ
static struct IDeviceIoService ledDriverServ = {
.Dispatch = LedDriverDispatch,
};
// 將ledDriverServ的地址賦值給deviceObject的service成員
deviceObject->service =(struct IDeviceIoService *)(&ledDriverServ);
// 記錄綁定成功的日志,包括設備名稱
HDF_LOGI("g_LedDriverEntry: %s success NodeName[%s]", __func__, deviceObject->property->name);
// 返回成功碼
return HDF_SUCCESS;
}
LedDriverDispatch:解析函數,解析應用層下發的命令,執行命令對應的操作,控制led燈的亮滅。
參數:client(客戶端信息),cmdId(命令ID),dataBuf(輸入數據緩沖區),replyBuf(回復數據緩沖區)。
流程:檢查設備對象的有效性,驗證LED版本,根據命令ID讀取數據并調用LedGpioCtl控制LED。
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int32_t cmdId, struct HdfSBuf *dataBuf, struct HdfSBuf *replyBuf){
int32_t result = HDF_FAILURE;
int32_t LedMode = 0;
// 檢查客戶端和設備是否為空
if(client == NULL || client->device == NULL){
HDF_LOGE("driver device is NULL");
return HDF_ERR_INVALID_OBJECT;
}
// 檢查LED配置版本是否支持
if(g_LedCfg.led_version != LED_VERSION){
HDF_LOGE("led version is not support");
return HDF_FAILURE;
}
switch(cmdId){
case LED_WRITE:
// 從數據緩沖區讀取LED模式
result = HdfSbufReadInt32(dataBuf,&LedMode);
if(result ){
// 根據LED模式控制GPIO
LedGpioCtl(g_LedCfg.led_number, (LedMode == LED_ON) ? LED_ON: LED_OFF);
}
break;
default:
// 不支持的命令ID
HDF_LOGE("cmdId is not support");
break;
}
return result;
}
LedGpioCtl:控制指定GPIO(LED)的高低電平,從而控制LED燈的開關。
參數:gpio(GPIO號),mode(LED模式,開或關)。
流程:設置GPIO為輸出方向,根據mode設置GPIO的電平,最后記錄日志。
static int32_t LedGpioCtl(uint16_t gpio, uint32_t mode){
// 設置GPIO電平為高電平
uint16_t level = GPIO_VAL_HIGH;
// 設置GPIO為輸出方向
if(HDF_SUCCESS != GpioSetDir(gpio, GPIO_DIR_OUT)){
// 設置GPIO方向失敗
HDF_LOGE("GpioSetDir fail");
return HDF_FAILURE;
}
// 根據mode設置GPIO電平
if(mode == LED_ON){
level = GPIO_VAL_HIGH;
}else if(mode==LED_OFF){
level = GPIO_VAL_LOW;
}
// 日志記錄GPIO操作
HDF_LOGE("%s:Write gpio %d:%d",__func__,gpio,mode);
// 向GPIO寫入電平
if(HDF_SUCCESS != GpioWrite(gpio, level)){
// 寫入GPIO電平失敗
HDF_LOGE("GpioWrite fail",__func__);
}
return HDF_SUCCESS;
}
3.4.4 添加內核編譯
編譯內核時將該HDF驅動編譯到鏡像中,接下來編寫驅動編譯腳本Makefile,代碼如下所示:
include drivers/hdf/khdf/platform/platform.mk
obj-y += led_driver.o
加入編譯體系,填加模塊目錄到drivers/hdf_core/adapter/khdf/linux/Makefile 文件
obj-$(CONFIG_DRIVERS_HDF) += ../../../../../topeet/demos/hdf_led/driver/
3.4.5 編寫應用APP
在應用代碼中我們實現如下功能:
當應用程序啟動后會獲取命令行參數。如果命令行沒有參數,LED燈將循環閃爍;如果命令行帶有參數,則根據傳輸的參數控制LED燈的開啟或關閉。通過HdfIoServiceBind 綁定LED燈的HDF服務,獲取HDF空間緩存區,并向該緩沖區寫入控制數據。然后,通過 LED_WRITE 命令將數據發送到 HDF 驅動,從而控制 LED 燈的亮滅。在程序結束時,會回收 HDF 空間緩沖區和 HDF 服務。
接下來編寫應用測試文件led_test.c,完整代碼如下所示。
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "hdf_base.h"
#include "hdf_io_service.h"
#include "hilog/log.h"
#undef LOG_TAG
#undef LOG_DOMAIN
#define LOG_TAG "led_test"
#define LOG_DOMAIN 0xD0020240
#define ARGS_NUM 2
#define LED_SERVICE_NAME "topeet_led_service"
#define LED_WRITE 1
/**
* @brief 主函數,用于控制LED燈的開關狀態
*
* 根據傳入的參數控制LED燈的開關狀態,如果沒有傳入參數,則進入主循環,不斷切換LED燈的開關狀態。
*
* @param argc 命令行參數的數量
* @param argv 命令行參數的數組
*
* @return 返回HDF_SUCCESS表示成功,否則返回錯誤碼
*/
int main(int argc, char *argv[]){
int ret = HDF_SUCCESS;
int32_t mode = -1;
// 判斷命令行參數數量
if (argc == ARGS_NUM) {
// 將命令行參數轉換為整數并賦值給 mode
mode = atoi(argv[1]);
// 打印 mode 的狀態
printf("mode[%s][0x%x]\n",(mode==1)?"On":"Off",mode);
} else {
// 命令行參數數量不正確,打印提示信息
printf("led main loop. \n");
}
// 綁定 LED 服務
struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE_NAME);
if(serv == NULL){
// 綁定服務失敗,打印錯誤信息并返回 -1
HILOG_ERROR(LOG_APP, "get service %s failed!", LED_SERVICE_NAME);
return -1;
}
// 打印綁定服務成功的日志
HILOG_ERROR(LOG_APP, "get service %s succeed", LED_SERVICE_NAME);
// 獲取默認大小的 SBuf 對象
struct HdfSBuf *data = HdfSbufObtainDefaultSize();
if(data == NULL){
// 獲取 SBuf 對象失敗,打印錯誤信息并返回 -1
HILOG_ERROR(LOG_APP,"obtain data failed\n");
return -1;
}
// 打印獲取 SBuf 對象成功的日志
HILOG_ERROR(LOG_APP,"obtain data succeed\n");
// 如果 mode 為 -1,則進入循環
if(mode == -1){
while(1){
// 清空 SBuf 對象
HdfSbufFlush(data);
// 向 SBuf 對象寫入整數 1
if(!HdfSbufWriteInt32(data, 1)){
// 寫入數據失敗,打印錯誤信息并返回 -1
HILOG_ERROR(LOG_APP,"write data failed");
return -1;
}
// 調用 Dispatch 方法,發送 LED 寫入命令
ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE, data, NULL);
usleep(500 * 1000);
// 清空 SBuf 對象
HdfSbufFlush(data);
// 向 SBuf 對象寫入整數 0
if(!HdfSbufWriteInt32(data, 0)){
// 寫入數據失敗,打印錯誤信息并返回 -1
HILOG_ERROR(LOG_APP,"write data failed");
return -1;
}
// 調用 Dispatch 方法,發送 LED 寫入命令
ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE, data, NULL);
usleep(500 * 1000);
}
} else {
// 如果 mode 不為 -1,則向 SBuf 對象寫入 mode 值
if(!HdfSbufWriteInt32(data, mode)){
// 寫入數據失敗,打印錯誤信息并返回 -1
HILOG_ERROR(LOG_APP,"write data failed");
return -1;
}
// 調用 Dispatch 方法,發送 LED 寫入命令
ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE, data, NULL);
// 打印 Dispatch 成功的日志
HILOG_ERROR(LOG_APP,"Dispatch succeed");
}
// 回收 SBuf 對象
HdfSbufRecycle(data);
// 回收服務對象
HdfIoServiceRecycle(serv);
// 打印主程序退出的日志
HILOG_INFO(LOG_APP,"[%s] main exit.",LOG_TAG);
return ret;
}
接下來編寫應用APP的GN文件BUILD.gn,代碼內容如下所示:
HDF_FRAMEWORKS = "http://drivers/hdf_core/framework"
HDF_ADAPTER = "http://drivers/hdf_core/adapter"
import("http://build/ohos.gni")
import("$HDF_ADAPTER/uhdf2/uhdf.gni")
print("demos: compile led_test")
ohos_executable("led_test"){
sources = ["led_test.c"]
include_dirs = [
"$HDF_FRAMEWORKS/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/osal",
"$HDF_FRAMEWORKS/include/platform",
"$HDF_FRAMEWORKS/include/utils",
"$HDF_ADAPTER/uhdf2/ipc/include",
"$HDF_ADAPTER/uhdf2/osal/include",
"http://base/hiviewdfx/hilog/interfaces/native/innerkits/include",
"http://third_party/bounds_checking_function/include",
]
external_deps = [
"c_utils:utils",
"hdf_core:libhdf_platform",
"hdf_core:libhdf_utils",
"hilog:libhilog",
]
cflags = [
"-Wall",
"-Wextra",
"-Werror",
"-Wno-format",
"-Wno-format-extra-args",
]
part_name = "demos"
install_enable = true
}
上面的代碼用于構建一個“led_test”的可執行文件的構建腳本,它使用了GN(Generate Ninja)構建系統,這是一種元構建系統,用于生成Ninja構建文件。
1-2行定義了兩個變量HDF_FRAMEWORKS和HDF_ADAPTER,它們分別指向HDF(Hardware Driver Foundation,硬件驅動框架)核心框架和適配器的路徑。這些路徑是相對于項目根目錄的。
4-5行 使用import語句導入兩個GNI(GN Include)文件。GNI文件是GN構建系統用來包含變量定義、函數和模板的文件。這里導入的文件可能包含了一些預定義的變量、函數或構建規則,用于支持構建過程。//build/ohos.gni可能包含了OpenHarmony特有的構建配置,而$HDF_ADAPTER/uhdf2/uhdf.gni可能包含了與uHDF(Unified Hardware Driver Framework,統一硬件驅動框架)相關的配置。
7行 打印一條消息到控制臺,表明正在編譯led_test示例。
9-40行 定義一個名為led_test的ohos_executable目標,這是一個構建規則,用于生成一個可執行文件。下面是該目標的具體配置:
sources:指定源文件列表,這里只有一個文件led_test.c。
include_dirs:指定頭文件搜索路徑列表。這些路徑用于在編譯時查找包含的文件(#include指令引用的文件)。這些路徑包括了HDF框架、適配器的多個子目錄,以及一些第三方庫和內部工具庫的頭文件路徑。
external_deps:指定外部依賴項列表。這些依賴項是在構建過程中需要鏈接的庫。這里列出了幾個庫,如c_utils:utils、hdf_core:libhdf_platform等,這些庫提供了構建led_test所需的功能。
cflags:指定傳遞給C編譯器的標志列表。這里包括了一些常見的編譯選項,如-Wall(打開所有警告)、-Wextra(打開額外警告)、-Werror(將所有警告視為錯誤)、以及兩個用于關閉特定警告的選項。
part_name:指定構建產物所屬的部件名稱,這里是demos。
install_enable:設置為true,表示構建產物應該被安裝。這可能意味著在構建成功后,led_test可執行文件會被復制到某個特定的目錄,以便于執行或分發。
3.5 在產品中新增子系統
在build/subsystem_config.json文件中增加名為topeet的子系統,在3.4節已經新建了topeet文件夾存放子系統代碼。添加topeet子系統進行一個登記,說明路徑和子系統名稱,如下所示:
“topeet”: {
“path”: “topeet”,
“name”: ”topeet”
}

在vendor/hihope/rk3568/config.json文件中增加topeet子系統的引入,如下所示:
{
"subsystem": "topeet",
"components": [
{
"component": "demos",
"features": [
]
}
]
}

修改完成之后,保存修改。
3.6 編譯源碼
重新編譯Openharmony4.1源碼,如下所示:
./build.sh --product-name rk3568 --ccache
或者單獨編譯部件
./build.sh --product-name rk3568 --build-target demos --ccache
編譯之后,在源碼out/rk3568/topeet目錄下生成編譯產物,如下圖所示:

3.7 LED測試
將編譯好的鏡像全部進行燒寫,鏡像在源碼根目錄out/rk3568/packages/phone/images/目錄下。

燒寫完成之后,在調試串口查看打印日志,如下圖所示:

然后打開hdc工具,運行測試程序,輸入“led_test 1”,LED燈點亮,如下圖所示:


輸入“led_test 0”,LED燈熄滅,如下圖所示:


-
開發板
+關注
關注
25文章
5223瀏覽量
99210 -
OpenHarmony
+關注
關注
25文章
3771瀏覽量
17062 -
RK3568
+關注
關注
4文章
542瀏覽量
5513
發布評論請先 登錄
相關推薦
評論