新增hdf驱动demo
目录结构 驱动入口: drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_driver.cpp vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs HDI接口: drivers/interface/tvservice/video/v1_0/
目录结构
驱动入口:
drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_driver.cpp
vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs
HDI接口:
drivers/interface/tvservice/video/v1_0/ITvserviceVideo.idl
drivers/interface/tvservice/video/v1_0/ITvserviceVideoHdiCallback.idl
drivers/interface/tvservice/video/v1_0/TvserviceVideoTypes.idl
drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_service.cpp
drivers/peripheral/tvservice/video/interfaces/hdi_service/include/tvservice_video_service.h
ipc通信:
out/rk3568/gen/drivers/interface/tvservice/video/v1_0/tvservice_video_proxy.cpp
out/rk3568/gen/drivers/interface/tvservice/video/v1_0/tvservice_video_stub.cpp
VDI适配接口:
drivers/peripheral/tvservice/video/interfaces/vdi_base/include/tvservice_video_vdi_impl.h
drivers/peripheral/tvservice/video/interfaces/vdi_base/src/tvservice_video_vdi_impl.cpp
驱动入口
路径:drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_driver.cpp
static void HdfTvserviceVideoDriverRelease(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HdfTvserviceVideoDriverRelease enter");
}
static struct HdfDriverEntry g_tvservicevideoDriverEntry = {
.moduleVersion = 1,
.moduleName = "tvservice_video_service",
.Bind = HdfTvserviceVideoDriverBind,
.Init = HdfTvserviceVideoDriverInit,
.Release = HdfTvserviceVideoDriverRelease,
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
HDF_INIT(g_tvservicevideoDriverEntry);
#ifdef __cplusplus
}
#endif /* __cplusplus */
此处为tvservice的hdf入口,进行tvservice的初始化、接口绑定等操作,如果新增驱动需要在此处完成Bind、Init、Release等接口内容。
HCS配置文件
路径:vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs
tvservice_video :: host {
hostName = "tvservice_video_host";
priority = 40;
threadPriority = 1;
uid = "tvservice_video_host";
gid = ["tvservice_video_host", "tvservice_video_host", "tvservice_video_host","root"];
device_video_manager :: device {
device0 :: deviceNode {
policy = 2;
priority = 100;
preload = 0;
permission = 0660;
moduleName = "libtvservice_video_driver.z.so";
serviceName = "tvservice_video_service";
}
}
}
配置tvservice_host的进程的信息。
hostName:host进程名。HDF框架会根据HCS配置在out中生成包含进程信息的hdf_peripheral.cfg文件,HDF框架会启动此host进程完成:驱动加载、节点生成、so库加载、接口实例化等一系列操作。
关键log:
行 2940: 08-05 17:03:06.495 524 524 I C02510/hdf_device_host: hdf device host tvservice_video_host 13 start
行 3980: 08-05 17:03:08.029 524 524 I C02510/device_node: launch devnode tvservice_video_service
关键进程:
设备ps -ef命令查看会出现tvservice_video_host进程。
moduleName:HDF框架DevHostServiceAddDevice会根据HCS配置打开这个库,并且利用g_tvservicevideoDriverEntry入口,执行Init、Bind、Release等接口内容。
HDI接口
路径:drivers/interface/tvservice/video/v1_0/ITvserviceVideo.idl
drivers/interface/tvservice/video/v1_0/ITvserviceVideoHdiCallback.idl
drivers/interface/tvservice/video/v1_0/TvserviceVideoTypes.idl
在ITvserviceVideo.idl定义HDI接口,供上层调用:
package ohos.hdi.tvservice.video.v1_0;
import ohos.hdi.tvservice.video.v1_0.ITvserviceVideoHdiCallback;
import ohos.hdi.tvservice.video.v1_0.TvserviceVideoTypes;
interface ITvserviceVideo {
SetBrightness([in] unsigned int brightness);
}
ITvserviceVideo类:必须与文件名相同,并且后续使用hdi接口时,也要用ITvserviceVideo类调用。
此处为idl语法,编译之后会在out目录下根据模板生成相应代码,不需要关注具体实现,定义好接口即可。
其余内容见IPC通信章节。
IPC通信
路径:out/rk3568/gen/drivers/interface/tvservice/video/v1_0
IDL中配置好的模板会在out下生成如图所示内容。
5.1. tvservice_video_proxy.cpp
HDI接口客户端代码,主要内容包含实例化接口、各个接口的远程实现。
5.1.1. 实例化接口
Get接口参数isStub如果为false,则说明是proxy端,会进行IPC通信命令的发送,调用接口proxy实现;如果为true则是stub端,此时与tvservice_video_stub.cpp中的处理一样,进行接口实例化。
sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(bool isStub)
{
return ITvserviceVideo::Get("tvservice_video_service", isStub);
}
sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(const std::string& serviceName, bool isStub)
{
if (isStub) {
std::string desc = Str16ToStr8(OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor());
void *impl = LoadHdiImpl(desc.c_str(), serviceName == "tvservice_video_service" ? "service" : serviceName.c_str());
if (impl == nullptr) {
HDF_LOGE("failed to load hdi impl %{public}s", desc.data());
return nullptr;
}
return reinterpret_cast<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo *>(impl);
}
using namespace OHOS::HDI::ServiceManager::V1_0;
auto servMgr = IServiceManager::Get();
if (servMgr == nullptr) {
HDF_LOGE("%{public}s:get IServiceManager failed!", __func__);
return nullptr;
}
sptr<IRemoteObject> remote = servMgr->GetService(serviceName.c_str());
if (remote == nullptr) {
HDF_LOGE("%{public}s:get remote object failed!", __func__);
return nullptr;
}
sptr<OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy> proxy = new OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy(remote);
if (proxy == nullptr) {
HDF_LOGE("%{public}s:iface_cast failed!", __func__);
return nullptr;
}
proxy->servMgr_ = OHOS::HDI::hdi_objcast<IServiceManager>(servMgr);
proxy->deathRecipient_ = new OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy::IServiceManagerDeathRecipient(proxy);
proxy->servMgr_->AddDeathRecipient(proxy->deathRecipient_);
proxy->isReconnected_ = false;
proxy->serviceName_ = serviceName;
uint32_t serMajorVer = 0;
uint32_t serMinorVer = 0;
int32_t tvserviceVideoRet = proxy->GetVersion(serMajorVer, serMinorVer);
if (tvserviceVideoRet != HDF_SUCCESS) {
HDF_LOGE("%{public}s:get version failed!", __func__);
return nullptr;
}
if (serMajorVer != 1) {
HDF_LOGE("%{public}s:check version failed! version of service:%u.%u, version of client:1.0", __func__, serMajorVer, serMinorVer);
return nullptr;
}
return proxy;
}
5.1.2. 接口远程调用
调用此接口时,会向stub端发送cmd,此处为CMD_TVSERVICE_VIDEO_SET_BRIGHTNESS,通知stub端进行调用。
int32_t OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy::SetBrightness_(uint32_t brightness,
const sptr<IRemoteObject> remote)
{
MessageParcel tvserviceVideoData;
MessageParcel tvserviceVideoReply;
MessageOption tvserviceVideoOption(MessageOption::TF_SYNC);
if (!tvserviceVideoData.WriteInterfaceToken(OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor())) {
HDF_LOGE("%{public}s: failed to write interface descriptor!", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (!tvserviceVideoData.WriteUint32(brightness)) {
HDF_LOGE("%{public}s: write brightness failed!", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (remote == nullptr) {
HDF_LOGE("%{public}s: invalid remote object!", __func__);
return HDF_ERR_INVALID_OBJECT;
}
int32_t tvserviceVideoRet = remote->SendRequest(CMD_TVSERVICE_VIDEO_SET_BRIGHTNESS, tvserviceVideoData, tvserviceVideoReply, tvserviceVideoOption);
if (tvserviceVideoRet != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, tvserviceVideoRet);
return tvserviceVideoRet;
}
return tvserviceVideoRet;
}
5.2. tvservice_video_stub.cpp
HDI接口服务端代码,主要内容包含实例化接口、各个接口的本地实现。
5.2.1. 实例化接口
这里需要注意,stub和proxy的Get接口定义时一样的,都属于ITvserviceVideo类。进行HDI接口调用的时候应使用proxy远程接口,如果调用stub本地接口则会绕过ipc通信进行接口调用。
sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(bool isStub)
{
return OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get("tvservice_video_service", isStub);
}
sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(const std::string& serviceName, bool isStub)
{
if (!isStub) {
return nullptr;
}
std::string desc = Str16ToStr8(OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor());
void *impl = LoadHdiImpl(desc.c_str(), serviceName == "tvservice_video_service" ? "service" : serviceName.c_str());
if (impl == nullptr) {
HDF_LOGE("failed to load hdi impl %{public}s", desc.c_str());
return nullptr;
}
return reinterpret_cast<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo *>(impl);
}
5.2.2. 接口本地调用
此处会对proxy发送的命令进行接受,然后做分发处理:
int32_t OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
{
switch (code) {
case CMD_TVSERVICE_VIDEO_GET_VERSION:
return TvserviceVideoStubGetVersion(data, reply, option);
case CMD_TVSERVICE_VIDEO_SET_BRIGHTNESS:
return TvserviceVideoStubSetBrightness(data, reply, option);
default: {
HDF_LOGE("%{public}s: cmd %{public}d is not supported", __func__, code);
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
}
}
分发之后调用如下接口,通过 int32_t tvserviceVideoRet = impl->SetBrightness(brightness);调用到vdi接口。
int32_t OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoStub::TvserviceVideoStubSetBrightness_(MessageParcel& tvserviceVideoData, MessageParcel& tvserviceVideoReply, MessageOption& tvserviceVideoOption, sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> impl)
{
if (tvserviceVideoData.ReadInterfaceToken() != OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor()) {
HDF_LOGE("%{public}s: interface token check failed!", __func__);
return HDF_ERR_INVALID_PARAM;
}
uint32_t brightness = 0;
if (!tvserviceVideoData.ReadUint32(brightness)) {
HDF_LOGE("%{public}s: read brightness failed!", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (impl == nullptr) {
HDF_LOGE("%{public}s: impl is nullptr!", __func__);
return HDF_ERR_INVALID_PARAM;
}
int32_t tvserviceVideoRet = impl->SetBrightness(brightness);
if (tvserviceVideoRet != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, tvserviceVideoRet);
return tvserviceVideoRet;
}
return tvserviceVideoRet;
}
VDI接口
路径:drivers/peripheral/tvservice/video/interfaces/vdi_base/include/tvservice_video_vdi_impl.h
drivers/peripheral/tvservice/video/interfaces/vdi_base/src/tvservice_video_vdi_impl.cpp
此处应对接底层SetBrightness接口实现,由VDI调用芯片SDK提供的接口。
int32_t TvserviceVideoVdiImpl::SetBrightness(uint32_t brightness)
{
TVSERVICE_LOGI("%s is not supported", __func__);
return HDF_SUCCESS;
}
HDI接口调用例程
7.1. build.gn编译脚本
import("//build/ohos.gni")
import("../../tvservice.gni")
config("tvservice_video_test_config") {
visibility = [ ":*" ]
cflags = [
"-Wall",
"-Werror",
"-g3",
]
}
config("tvservice_video_test_public_config") {
include_dirs = [
".",
"include",
"../interfaces/hdi_service/include",
"../interfaces/vdi_base/include",
"../utils/include",
]
}
ohos_executable("tvservice_video_test") {
install_enable = true
sources = [
"//drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_service.cpp",
"main.cpp",
]
configs = [ ":tvservice_video_test_config" ]
public_configs = [ ":tvservice_video_test_public_config" ]
deps = [ "//drivers/peripheral/tvservice/video/interfaces/hdi_service:hdf_tvservice_video_host"]
deps += [ "//drivers/peripheral/tvservice/video/interfaces/vdi_base:tvservice_video_vdi_impl_default" ]
external_deps = [
"c_utils:utils",
"drivers_interface_tvservice:libtvservice_video_proxy_1.0",
"hdf_core:libhdf_utils",
"hilog:libhilog",
"hitrace:hitrace_meter",
"ipc:ipc_single",
]
part_name = "drivers_peripheral_tvservice"
subsystem_name = "hdf"
}
只需要依赖proxy端即可,即"drivers_interface_tvservice:libtvservice_video_proxy_1.0"。
7.2. 测试代码
sptr<ITvserviceVideo> iTvserviceVideo_ = nullptr;
int32_t VideoTest::test(int32_t argc, const char *argv[])
{
if(iTvserviceVideo_ == nullptr) {
iTvserviceVideo_ = ITvserviceVideo::Get();
}
if(iTvserviceVideo_ == nullptr) {
HDF_LOGI("====== iTvserviceVideo_ is nullptr");
return -1;
}
int32_t ret = -1;
int brightness = std::stoi(argv[1]);
HDF_LOGI("====== SetBrightness brightness:%{public}d, %{public}d, %{public}d", argc,*argv[0], brightness);
if (argc == 2) {
HDF_LOGI("====== SetBrightness brightness 1:%{public}d", brightness);
ret = iTvserviceVideo_->SetBrightness(brightness);
HDF_LOGI("====== SetBrightness brightness 2:%{public}d", brightness);
}
if (ret != 0) {
HDF_LOGI("====== SetBrightness failed:%{public}d", ret);
} else {
HDF_LOGI("====== SetBrightness succedd:%{public}d", ret);
}
return 0;
}
接口实例化:iTvserviceVideo_ = ITvserviceVideo::Get();,调用HDI接口时,应使用proxy端的实例化接口,Get接口参数应为false或为空。
更多推荐
所有评论(0)