5

【FFH】小熊派驱动调用流程(以调用LED灯驱动为例)

 2 years ago
source link: https://blog.51cto.com/harmonyos/5010577
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【FFH】小熊派驱动调用流程(以调用LED灯驱动为例)

推荐 原创

 春节不停更,此文正在参加「星光计划-春节更帖活动」

一、流程总览

驱动调用的流程和纯代码开发的流程十分相似,本文着重点在于驱动调用的逻辑。

创建目录及相应源码文件–>编写驱动调用代码–>编写编译构建文件BUILD.gn–>编译烧录运行

二、源码目录结构

在./applications/BearPi/BearPi-HM_Micro/samples/目录下创建

my_led_app 源码目录

*my_led_app.c 驱动调用源码

*BUILD.gn 源码编译脚本

【FFH】小熊派驱动调用流程(以调用LED灯驱动为例)_OpenHarmony

三、编写驱动调用代码

在my_led_app.c中编写如下代码

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"

#define LED_WRITE_READ 1
#define LED_SERVICE "hdf_led"

static int SendEvent(struct HdfIoService *serv, uint8_t eventData)
{
    int ret = 0;
    struct HdfSBuf *data = HdfSBufObtainDefaultSize();
    if (data == NULL)
    {
        printf("fail to obtain sbuf data!\r\n");
        return 1;
    }

    struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
    if (reply == NULL)
    {
        printf("fail to obtain sbuf reply!\r\n");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }
    /* 写入数据 */
    if (!HdfSbufWriteUint8(data, eventData))
    {
        printf("fail to write sbuf!\r\n");
        ret = HDF_FAILURE;
        goto out;
    }
    /* 通过Dispatch发送到驱动 */
    ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply);
    if (ret != HDF_SUCCESS)
    {
        printf("fail to send service call!\r\n");
        goto out;
    }

    int replyData = 0;
    /* 读取驱动的回复数据 */
    if (!HdfSbufReadInt32(reply, &replyData))
    {
        printf("fail to get service call reply!\r\n");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }
    printf("\r\nGet reply is: %d\r\n", replyData);
out:
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    return ret;
}

int main(int argc, char **argv)
{
    int i;
    
    /* 获取服务 */
    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE);
    if (serv == NULL)
    {
        printf("fail to get service %s!\r\n", LED_SERVICE);
        return HDF_FAILURE;
    }

    for (i=0; i < argc; i++)
    {
        printf("\r\nArgument %d is %s.\r\n", i, argv[i]);
    }

    SendEvent(serv, atoi(argv[1]));

    HdfIoServiceRecycle(serv);
    printf("exit");

    return HDF_SUCCESS;
}

这一部分是本文的重点部分

OpenHarmony的设备开发中的驱动调用与单片机的驱动开发不太相同,以往单片机的驱动调用往往是采用库函数调用的方式,但OpenHarmony的驱动调用采用的是驱动程序暴露出一个server,程序通过Dispatch发送指令的方式。有点类似与ROS的消息通信机制中的话题发布和订阅。在OpenHarmony中驱动调用的这部分程序属于用户程序,是用户态的内容,而驱动是内核态的内容。所以用户程序无法直接访问驱动,上面代码通过Dispatch向驱动程序发送指令从而实现LED灯的亮灭。

3.1 发送指令到驱动程序

我们看下my_led_app.c中SendEvent函数中通过Dispatch发送到驱动的代码

/* 通过Dispatch发送到驱动 */
    ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply);
    if (ret != HDF_SUCCESS)
    {
        printf("fail to send service call!\r\n");
        goto out;
    }

    int replyData = 0;

这段代码实现将指令发送到驱动程序

驱动程序指令接受的的代码在 上一篇文章中的led.c驱动代码中的LedDriverDispatch函数

// Dispatch是用来处理用户态发下来的消息
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    uint8_t contrl;
    HDF_LOGE("Led driver dispatch");
    if (client == NULL || client->device == NULL)
    {
        HDF_LOGE("Led driver device is NULL");
        return HDF_ERR_INVALID_OBJECT;
    }

    switch (cmdCode)
    {
    /* 接收到用户态发来的LED_WRITE_READ命令 */
    case LED_WRITE_READ:
        /* 读取data里的数据,赋值给contrl */
        HdfSbufReadUint8(data,&contrl);                  
        switch (contrl)
        {
        /* 开灯 */
        case LED_ON:                                            
            GpioWrite(g_Stm32Mp1ILed.gpioNum, GPIO_VAL_LOW);
            status = 1;
            break;
        /* 关灯 */
        case LED_OFF:                                           
            GpioWrite(g_Stm32Mp1ILed.gpioNum, GPIO_VAL_HIGH);
            status = 0;
            break;
        /* 状态翻转 */
        case LED_TOGGLE:
            if(status == 0)
            {
                GpioWrite(g_Stm32Mp1ILed.gpioNum, GPIO_VAL_LOW);
                status = 1;
            }
            else
            {
                GpioWrite(g_Stm32Mp1ILed.gpioNum, GPIO_VAL_HIGH);
                status = 0;
            }                                        
            break;
        default:
            break;
        }
        /* 把LED的状态值写入reply, 可被带至用户程序 */
        if (!HdfSbufWriteInt32(reply, status))                
        {
            HDF_LOGE("replay is fail");
            return HDF_FAILURE;
        }
        break;
    default:
        break;
    }
    return HDF_SUCCESS;
}

3.2 从驱动程序接受数据

刚刚实现了用户态向内核态发送指令,同理,内核态也可以向用户态发送数据。

让我们看看驱动代码中向用户发送LED状态信息的代码(在led.c中LedDriverDispatch函数的一部分)

/* 把LED的状态值写入reply, 可被带至用户程序 */
        if (!HdfSbufWriteInt32(reply, status))                
        {
            HDF_LOGE("replay is fail");
            return HDF_FAILURE;
        }

下面是用户程序接收的部分

/* 读取驱动的回复数据 */
    if (!HdfSbufReadInt32(reply, &replyData))
    {
        printf("fail to get service call reply!\r\n");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }
    printf("\r\nGet reply is: %d\r\n", replyData);

四、编写编译构建文件BUILD.gn

在BUILD.gn中添加以下代码

import("//build/lite/config/component/lite_component.gni")

HDF_FRAMEWORKS = "//drivers/framework"

executable("led_lib") {
    output_name = "my_led"
    sources = [
        "my_led_app.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",
    ]
}

lite_component("my_led_app") {
    features = [
        ":led_lib",
    ]
}

五、编译烧录

参考之前文章 Linux下配置小熊派-鸿蒙·叔设备开发(南向)的开发环境

串口连接小熊派终端

./bin/my_led 0 #关闭LED
./bin/my_led 1 #开启LED
./bin/my_led 2 #翻转LED

 想了解更多关于鸿蒙的内容,请访问:

 51CTO和华为官方合作共建的鸿蒙技术社区

 https://harmonyos.51cto.com/#bkwz

【FFH】小熊派驱动调用流程(以调用LED灯驱动为例)_FFH_02

  • 打赏
  • 收藏
  • 评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK