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. ……

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


http://www.niftyadmin.cn/n/5311918.html

相关文章

Codeforces Round 761 (Div. 2) D2. Too Many Impostors (hard version)(交互+构造 最小次数)

题目 n(6<n<1e4&#xff0c;n是3的倍数)个人&#xff0c;其中k个人是好人&#xff0c;n-k个人是坏人 k是未知的&#xff0c;但保证1/3n<k<2/3n&#xff0c;你可以询问若干次&#xff0c; 每次你可以选择三个不同的人a,b,c&#xff0c;系统告诉你这三个人中好人更…

建模软件Rhinoceros mac介绍说明

Rhinoceros mac是一款3D设计软件“犀牛”&#xff0c;在当今众多三维建模软件中&#xff0c;Rhinoceros 版因为其体积小、功能强大、对硬件要求低而广受欢迎&#xff0c;对于专业的3D设计人员来说它是一款不错的3D建模软件&#xff0c;Rhinoceros Mac中文版能轻易整合3DS MAX与…

Unity 编辑器篇|(一)MenuItem菜单栏

目录 1.MenuItem 属性2.创建多级菜单3.创建带快捷键的菜单4.创建带快捷键的菜单5.检查菜单是否使用6.菜单排序7.扩展右键菜单7.1 Hierarchy 右键菜单7.2 Project 右键菜单7.3 Inspector 组件右键菜单 8. AddComponentMenu 特性9. ContextMenu 特性 添加组件右键菜单 1.MenuItem…

练习-sizeof()和strlen()

目录 前言解题技巧一、sizeof()练习题1.1 整型数组1.2 字符数组1.3 字符指针 二、strlen()练习题2.1 字符数组初始化时不包含\02.2 字符数组初始化包含\02.3 字符指针指向字符串常量 总结 前言 最近有点疲倦&#xff0c;啊啊啊&#xff0c;麻了… 今天写点轻松的东西&#xff…

Apache SSI 远程命令执行漏洞

Apache SSI 远程命令执行漏洞 1.cd到ssi-rce cd /opt/vulhub/httpd/ssi-rce/ 2.执行docker-compose up -d docker-compose up -d 3.查看靶场是否开启成功 dooker ps 拉取成功了 4.访问url 这里已经执行成功了&#xff0c;注意这里需要加入/upload.php 5.写入一句话木马 &…

设计模式的艺术P1基础—2.1 uml概述

设计模式的艺术P1基础—2.1 uml概述 设计模式的艺术P1基础—第2章 UML类图与面向对象设计原则 UML类图可用于描述每一个设计模式的结构以及对模式实例进行说明&#xff0c;而模式结构又是设计模式解法的核心组成部分。学一个设计模式&#xff0c;如果不能绘制和理解其结构图&am…

Js使用ffmpeg在视频中合成音频背景音乐

Js使用ffmpeg在视频中合成音频背景音乐 ffmpeg 使用场景是需要在web端对视频的背景音乐进行混音合成。 注意: 以下所有的使用案例均基于vue3 setup。 同时由于ffmpeg版本不同会导致使用的api不同&#xff0c;使用案例前需要注意ffmpeg版本问题。 如果使用的是0.12需要使用…

ES6---Set和Map详解

ES6里面的Set和Map用法&#xff1a; 1.Set是一种新的数据结构&#xff0c;类似于数组&#xff0c;里面的成员是唯一的&#xff0c;没有重复的值。 Set实例的方法分为两大类&#xff1a; let set new Set()(1)操作方法: 1>set.add() — 添加某个值&#xff0c;返回set结构…