说明
在之前的基础上使用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电压每隔一秒发生变化