rk3399pro移植openharmony3.0移植笔记3

本文档详细介绍了如何在OpenHarmony系统中开发GPIO驱动,包括在内核层添加led驱动代码,实现GPIO口的读写控制,并在用户态编写应用程序与驱动交互,实现GPIO口状态的切换。驱动程序通过HDF框架进行注册和服务绑定,用户态程序利用HDF_IO_SERVICE接口发送命令。最终,当运行用户态程序时,GPIO口的状态每隔一秒会发生变化。
摘要由CSDN通过智能技术生成

说明

在之前的基础上使用hdf驱动控制GPIO口,再此做记录,方便后期查找。参考文章

内核层

OpenHarmony/drivers/adapter/khdf/linux/platform/gpio/目录下添加led.c

#include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件
#include "hdf_log.h"         // HDF 框架提供的日志接口头文件
#include "device_resource_if.h"
#include "osal_io.h"
#include "osal_mem.h"
#include "gpio_if.h"
#include "osal_irq.h"
#include "osal_time.h"
 
#define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签
#define LED_WRITE_READ 1       // 读写操作码1
 
static int32_t CtlLED(int mode)
{
    int32_t ret;
    uint16_t valRead;
    /* LED的GPIO管脚号 */
    uint16_t gpio = 2 * 32 + 6;  // GPIO2_A6
 
    /* 将GPIO管脚配置为输出 */
    ret = GpioSetDir(gpio, GPIO_DIR_OUT);
    if (ret != 0)
    {
        HDF_LOGE("GpioSerDir: failed, ret %d\n", ret);
        return ret;
    }
 
    if (mode == -1)
    {
        // 翻转输出口
        (void)GpioRead(gpio, &valRead);
        ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
    }
    else
    {
        ret = GpioWrite(gpio, mode);
    }
 
    if (ret != 0)
    {
        HDF_LOGE("GpioWrite: failed, ret %d\n", ret);
        return ret;
    }
    return ret;
}
 
// Dispatch是用来处理用户态发下来的消息
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
{   const char *recv = HdfSbufReadString(data);
    int32_t result = HDF_FAILURE;
    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){
        case LED_WRITE_READ:

            if (recv != NULL)
            {
                //HDF_LOGI("recv: %s", recv);
                result = CtlLED(-1);
                // CtlLED(GPIO_VAL_HIGH);
                if (!HdfSbufWriteInt32(reply, result)){
                    //HDF_LOGE("replay is fail");
                }
                return HdfDeviceSendEvent(client->device, cmdCode, data);
            }
            break;
 
        default:
            break;
    }
    return result;
}
 
//驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL)
    {
        HDF_LOGE("Led driver bind failed!");
        return HDF_ERR_INVALID_OBJECT;
    }
    static struct IDeviceIoService ledDriver = {
        .Dispatch = LedDriverDispatch,
    };
    deviceObject->service = (struct IDeviceIoService *)(&ledDriver);
    HDF_LOGD("Led driver bind success");
    return HDF_SUCCESS;
}
 
// 驱动自身业务初始的接口
int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL)
    {
        HDF_LOGE("Led driver Init failed!");
        return HDF_ERR_INVALID_OBJECT;
    }
    HDF_LOGD("Led driver Init success");
    return HDF_SUCCESS;
}
 
// 驱动资源释放的接口
void HdfLedDriverRelease(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL)
    {
        HDF_LOGE("Led driver release failed!");
        return;
    }
 
    HDF_LOGD("Led driver release success");
    return;
}
 
// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量
struct HdfDriverEntry g_ledDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "led_driver",
    .Bind = HdfLedDriverBind,
    .Init = HdfLedDriverInit,
    .Release = HdfLedDriverRelease,
};
 
// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
HDF_INIT(g_ledDriverEntry);

在OpenHarmony/drivers/adapter/khdf/linux/platform/gpio/Makefile中修改为以下代码:添加led.o

include drivers/hdf/khdf/platform/platform.mk

obj-y  += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/gpio_core.o \
          $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/gpio_if.o \
          ./gpio_adapter.o \
	  ./led.o


LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror

添加此驱动的配置文件:
OpenHarmony/vendor/hisilicon/Hi3516DV300/hdf_config/khdf/device_info/device_info.hcs

                //在device_gpio :: device 下
                device1 :: deviceNode {
                    policy = 2;
                    priority = 100;
                    permission = 0644;
                    moduleName = "led_driver";
                    serviceName = "led_service";
		    deviceMatchAttr = "led_config";
                }

添加内核配置选项

CONFIG_DRIVERS_HDF_PLATFORM_GPIO=y

编译内核

用户态

新建OpenHarmony/applications/standard/led文件夹
在led文件夹下添加CallLED.c

#include <stdio.h>
#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 LED_WRITE_READ 1
#define HDF_LOG_TAG LED_APP
#define LED_SERVICE "led_service"
 
// 接收驱动上报事件
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");
        return HDF_FAILURE;
    }
    HDF_LOGE("%s: dev event received: %u %s", (char *)priv, id, string);
 
    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, LED_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_LOGE("Get reply is: %d", replyData);
out:
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    return ret;
}
  
int main(void)
{
    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE);// 用户态获取驱动的服务
    if (serv == NULL)
    {
        HDF_LOGE("fail to get service %s", LED_SERVICE);
        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;
    }
 
    char *send_cmd = "toggle LED";
    while (1)
    {
        if (SendEvent(serv, send_cmd))
        {
            HDF_LOGE("fail to send event");
            return HDF_FAILURE;
        }
        sleep(1);
    }
 
    if (HdfDeviceUnregisterEventListener(serv, &listener))
    {
        HDF_LOGE("fail to  unregister listener");
        return HDF_FAILURE;
    }
 
    HdfIoServiceRecycle(serv);// 释放驱动服务。
    HDF_LOGI("exit");
 
    return HDF_SUCCESS;
}

在led目录下添加BUILD.gn

import("//build/ohos.gni")
import("//drivers/adapter/uhdf2/uhdf.gni")

ohos_executable("CallLED") {
  sources = [
    "CallLED.c"
  ]
  include_dirs = [    
    "//drivers/framework/include",                                  # <utils/hdf_log.h> <core/hdf_io_service_if.h>
    "//drivers/adapter/uhdf2/osal/include",                         # hdf_log_adapter.h
    "//base/hiviewdfx/hilog/interfaces/native/innerkits/include",   # <hilog/log.h>
    "//drivers/framework/ability/sbuf/include",                     # hdf_sbuf.h
    "//drivers/framework/include/utils",                            # hdf_base.h
  ]
  deps = [
    "//drivers/adapter/uhdf2/osal:libhdf_utils",                    # hdf_log_adapter.h
    "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog"   # <hilog/log.h>
  ]
  subsystem_name = "applications"
  part_name = "prebuilt_hap"
}

在OpenHarmony\applications\standard\hap\ohos.build中添加

	"//applications/standard/led:CallLED",

编译openharmony3.0标准源码,烧写进开发板。

运行结果

在这里插入图片描述
板子gpio2_a6电压每隔一秒发生变化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值