OpenHarmony基于HDF简单驱动开发实例

背景

  • OpenHarmony-3.0-LTS
  • qemu_small_system_demo
  • liteos_a
  • qemu

添加配置

device/qemu/arm_virt/liteos_a/hdf_config/device_info/device_info.hcs

device_info 新增:

复制代码
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";
        }
    }
}

添加驱动代码

目录:device/qemu/arm_virt/liteos_a/drivers

新建驱动实现

mkdir sample_driver

vim sample_driver/sample_driver.c

复制代码
#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);

新建Makefile和BUILD.gn

新建Makefile和BUILD.gn,可参考其他平台,例如 device/hisilicon/drivers/rtc/

Makefile:

复制代码
include $(LITEOSTOPDIR)/config.mk
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk

MODULE_NAME := sample_driver

LOCAL_CFLAGS += $(HDF_INCLUDE)

LOCAL_SRCS += sample_driver.c

LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror -fsigned-char -fno-strict-aliasing -fno-common

include $(HDF_DRIVER)

BUILD.gn

复制代码
import("//drivers/adapter/khdf/liteos/hdf.gni")

#module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_RTC)
module_name = "sample_driver"
hdf_driver(module_name) {
  sources = [ "sample_driver.c" ]
}

修改上层BUILD.gn

复制代码
import("//drivers/adapter/khdf/liteos/hdf.gni")

group("drivers") {
  public_deps = [ "../../../drivers" ]

  #新增
  deps = [
    "sample_driver",
  ]

}

config("public") {
  configs = [ "../../../drivers:public" ]
}

编写驱动交互代码

目录:vendor/ohemu/qemu_small_system_demo/

新建用户代码实现

mkdir hdf_test

vim hdf_test/sample_service.c

复制代码
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_log.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";

    HDF_LOGI(SAMPLE_SERVICE_NAME "start");

    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;
}

新建BUILD.gn

vim sample_service/BUILD.gn,可参考huawei/hdf/sample/platform/uart/dispatch/BUILD.gn

复制代码
import("//build/lite/config/component/lite_component.gni")
HDF_FRAMEWORKS = "//drivers/framework"

lite_component("hdf_test") {
  features = [ ":sample_service" ]
}

executable("sample_service") {
  sources = [ "sample_service.c" ]

  include_dirs = [
    "$HDF_FRAMEWORKS/ability/sbuf/include",
    "$HDF_FRAMEWORKS/core/shared/include",
    "$HDF_FRAMEWORKS/core/host/include",
    "$HDF_FRAMEWORKS/core/master/include",
    "$HDF_FRAMEWORKS/include/core",
    "$HDF_FRAMEWORKS/include/utils",
    "$HDF_FRAMEWORKS/utils/include",
    "$HDF_FRAMEWORKS/include/osal",
    "//drivers/adapter/uhdf/posix/include",
    "//third_party/bounds_checking_function/include",
    "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
  ]

  deps = [
    "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
    "//drivers/adapter/uhdf/manager:hdf_core",
    "//drivers/adapter/uhdf/posix:hdf_posix_osal",
  ]

  public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
  defines = [ "__USER__" ]

  cflags = [
    "-Wall",
    "-Wextra",
    "-Wno-format",
    "-Wno-format-extra-args",
  ]

}

说明: 用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf_core和osal的动态库,在gn编译文件中添加如下依赖项:

复制代码
deps = [
​ "//drivers/hdf_core/adapter/uhdf/manager:hdf_core",
​ "//drivers/hdf_core/adapter/uhdf/posix:hdf_posix_osal",
]

修改上层BUILD.gn

复制代码
group("qemu_small_system_demo") {
  deps = [
    "apps",
    "init_configs",
    "hdf_test",  #新增
  ]
}

以上都是趟过了许多坑后再跑通的

编译测试

使用 hb 重新编译镜像,会生成对应带新增驱动的内核和带用户程序的镜像

复制代码
复制代码
#编译
hb clean
hb build

运行新编译的镜像

复制代码
#运行qemu
./vendor/ohemu/qemu_small_system_demo/patches/qemu-run

注: 需要修改上述脚本中的 rebuild=yes,让其每次都重新生成qemu镜像

开机log有如下打印,说明驱动已加载成功,并且在/dev/hdf/下面会生成 sample_service的节点:

复制代码
...

01-01 00:00:00.119 2 4 W 02500/driver_loader: failed to load node, property is null, match attr is: 
01-01 00:00:00.119 2 4 I 02500/sample_driver: Sample driver Init success
01-01 00:00:00.119 2 4 I 02500/osal_cdev: OsalRegisterCdev:register /dev/hdf/sample_service
01-01 00:00:00.119 2 4 D 02500/devmgr_service: DevmgrServiceUpdateStatus host:sample_host 0 device:sample_service 0 status:1

...

OHOS:/$ ls /dev/hdf/                                                           
dev_mgr  event2  hdf_input_event1  input_dev_manager  sample_service 

运行测试应用 sample_service,会有如下打印:

复制代码
OHOS:/$ sample_service                                                         
01-01 00:00:59.059 10 44 I 02500/sample_test: sample_servicestart
01-01 00:00:59.063 10 44 I 02500/sample_driver: HdfSampleDriverDispatch: received cmd 123
01-01 00:00:59.063 10 44 E 02500/sample_driver: HdfSampleDriverDispatch: read data is: default event info
01-01 00:00:59.064 10 44 I 02500/sample_test: Get reply is: 2147483647
01-01 00:00:59.068 10 45 I 02500/sample_test: Service0: dev event received: 123 default event info
01-01 00:01:00.065 10 44 D 02500/hdf_syscall_adapter: ioctl send poll thread(4) exit event, ret=0
OHOS:/$ 01-01 00:01:00.066 10 45 I 02500/hdf_syscall_adapter: event listener task received exit event
01-01 00:01:00.066 10 45 I 02500/hdf_syscall_adapter: event listener task exit
01-01 00:01:00.067 10 44 I 02500/hdf_syscall_adapter: poll thread exited
^C
OHOS:/$ ^C

总结

以上的内容主要简单介绍了OpenHarmony基于HDF简单驱动开发实例

要想成为一名鸿蒙高级开发,以上知识点是必须要掌握的,除此之外,还需要掌握一些鸿蒙应用开发相关的一些技术,需要我们共同去探索。

为了节省大家一些查找的时间,这边联合几位行业大佬,为大家准备了一份《Open Harmony4.0&Next》的学习导图从入门到进阶再到南北向开发实战的一整套完整体系,想要学习了解更多鸿蒙开发的相关知识可以借鉴:

除了以上的知识内容,我还为大家整理了一份**《鸿蒙 (Harmony OS)开发学习手册》都是整理成PDF文档方式,分享给大家参考学习:《鸿蒙开发学习指南》**

《鸿蒙 (Harmony OS)开发学习手册》

一、入门必看

  1. 应用开发导读(ArkTS)

  2. 应用开发导读(Java)

3.......

二、HarmonyOS 概念

  1. 系统定义

  2. 技术架构

  3. 技术特性

  4. 系统安全

5......

三、如何快速入门?《鸿蒙基础入门开发宝典!

  1. 基本概念

  2. 构建第一个ArkTS应用

  3. 构建第一个JS应用

  4. ......

四、开发基础知识

  1. 应用基础知识

  2. 配置文件

  3. 应用数据管理

  4. 应用安全管理

  5. 应用隐私保护

  6. 三方应用调用管控机制

  7. 资源分类与访问

  8. 学习ArkTS语言

  9. ......

五、基于ArkTS 开发

  1. Ability开发

  2. UI开发

  3. 公共事件与通知

  4. 窗口管理

  5. 媒体

  6. 安全

  7. 网络与链接

  8. 电话服务

  9. 数据管理

  10. 后台任务(Background Task)管理

  11. 设备管理

  12. 设备使用信息统计

  13. DFX

  14. 国际化开发

  15. 折叠屏系列

  16. ......

更多了解更多鸿蒙开发的相关知识可以参考:《做鸿蒙应用开发到底学习些啥?

相关推荐
盐焗西兰花6 小时前
鸿蒙学习实战之路-Reader Kit修改翻页方式字体大小及行间距最佳实践
学习·华为·harmonyos
园小异9 小时前
2026年技术面试完全指南:从算法到系统设计的实战突破
算法·面试·职场和发展
lbb 小魔仙10 小时前
【HarmonyOS实战】React Native 表单实战:在 OpenHarmony 上构建高性能表单
react native·华为·harmonyos
Epiphany.55612 小时前
蓝桥杯备赛题目-----爆破
算法·职场和发展·蓝桥杯
YuTaoShao12 小时前
【LeetCode 每日一题】1653. 使字符串平衡的最少删除次数——(解法三)DP 空间优化
算法·leetcode·职场和发展
一只大侠的侠12 小时前
React Native开源鸿蒙跨平台训练营 Day16自定义 useForm 高性能验证
flutter·开源·harmonyos
早點睡39013 小时前
高级进阶 React Native 鸿蒙跨平台开发:@react-native-community-slider 滑块组件
react native·react.js·harmonyos
一只大侠的侠14 小时前
Flutter开源鸿蒙跨平台训练营 Day11从零开发商品详情页面
flutter·开源·harmonyos
一只大侠的侠14 小时前
React Native开源鸿蒙跨平台训练营 Day18自定义useForm表单管理实战实现
flutter·开源·harmonyos
一只大侠的侠14 小时前
React Native开源鸿蒙跨平台训练营 Day20自定义 useValidator 实现高性能表单验证
flutter·开源·harmonyos