鴻蒙HI3516-驅動開發(1.1-LTS)
程式碼在://gitee.com/kwydm/open-harmony-taurus
目錄大致結構
1.驅動開發
創建目錄://vendor/huawei/hdf/LED/src
新建Makefile
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk
MODULE_NAME := hdf_led_driver
LOCAL_SRCS += led.c
LOCAL_INCLUDE := ./include
LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror
include $(HDF_DRIVER)
打開//device/hisilicon/drivers/lite.mk 編譯結果文件鏈接到內核鏡像
## 在頭部添加變數
VENDOR_HDF_DRIVERS_ROOT := $(LITEOSTOPDIR)/../../vendor/huawei/hdf
LITEOS_BASELIB += -lhdf_led_driver
LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/LED/src
新建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 = 5 * 8 + 1; // 紅外補光燈
// uint16_t gpio = 2 * 8 + 3; // 綠色指示燈
// uint16_t gpio = 3 * 8 + 4; // 紅色指示燈
/* 將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)
{
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:
const char *recv = HdfSbufReadString(data);
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);
2.用戶態
\vendor\huawei\hdf\LED\dispatch\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;
}
\vendor\huawei\hdf\LED\dispatch\BUILD.gn
# Copyright (c) 2020 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# //www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
HDF_FRAMEWORKS = "//drivers/framework"
# 暫時放在這裡編譯用戶態設備驅動消息調用程式,回頭在考慮移到獨立組件去編譯Gavin Lee
executable("CallLED") {
sources = [
"//vendor/huawei/hdf/LED/dispatch/CallLED.c"
]
include_dirs = [
"//vendor/huawei/hdf/LED/include",
"$HDF_FRAMEWORKS/core/adapter/vnode/include",
"$HDF_FRAMEWORKS/core/adapter/syscall/include",
"$HDF_FRAMEWORKS/core/shared/include",
"$HDF_FRAMEWORKS/core/host/include",
"$HDF_FRAMEWORKS/core/manager/include",
"$HDF_FRAMEWORKS/ability/sbuf/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/utils",
"$HDF_FRAMEWORKS/utils/include",
"$HDF_FRAMEWORKS/include/osal",
"$HDF_FRAMEWORKS/../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/posix:hdf_posix",
"//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",
"-Werror",
]
}
vendor\huawei\hdf\LED\BUILD.gn
import("//build/lite/config/component/lite_component.gni")
lite_component("led_gpio"){
features = ["dispatch:CallLED"]
}
build\lite\components\drivers.json
3.燒錄運行
串口發送下面的程式碼
./bin/CallLED
執行之後這個補光燈會1S閃一次
參考://harmonyos.51cto.com/posts/2820,Gavin,Dweb九弓子
作者:卡哇伊大喵
想了解更多內容,請訪問51CTO和華為合作共建的鴻蒙社區://harmonyos.51cto.com
Tags: 鴻蒙