一、背景说明

本文主要以标准系统上对NFC的驱动加载流程进行的通用介绍。以下是一种通用的驱动适配方法,在适配前先以小熊派芯片,在liteos上进行基本的nfc_example.c的功能使用,然后结合标准系统的驱动适配流程进行HDF层的适配说明,过程供参考。

二、适配思路

1、NFC组件服务架构图

 

2、上层引用目录

/foundation/communication/nfc
├── interfaces                        # 接口
│   └── inner_api                     # 系统内部件间接口
├── frameworks                        # 框架层接口
│   └── js                            # JS API的实现
│       └── napi                      # 通过napi封装的JS接口代码实现
├── services                          # NFC服务进程的实现
├── test                              # 测试代码
├── BUILD.gn                          # 编译入口
└── bundle.json                       # 部件描述文件

services中通过调用HDI接口,比如:

ErrCode NfcTagServiceImpl::WriteNdefTag(std::string data)
{
    if (!PermissionTools::IsGranted(OHOS::NFC::TAG_PERMISSION)) {
        HILOGE("NfcTagServiceImpl:WriteNdefTag() IsGranted failed!");
        return NFC_FAILED;
    }
    if (NfcTagHdiAdapter::GetInstance().WriteNdefTag(data) == 0) {
        return NFC_SUCCESS;
    }
    return NFC_FAILED;
}

3、驱动加载

1)先在.\drivers\hdf_core\framework\model下新建nfc/driver/src文件夹,添加nfc_driver.c,加载驱动

openharmony

|--------\drivers\hdf_core\framework\model\nfc\driver\src

|-------------------------------------------------------------└──nfc_driver.c

添加驱动加载:

static struct HdfDriverEntry g_nfcinterfaceDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "nfc_driver",
    .Bind = HdfNfcInterfaceDriverBind,
    .Init = HdfNfcInterfaceDriverInit,
    .Release = HdfNfcInterfaceDriverRelease,
};

通过HDF模块初始化:

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
HDF_INIT(g_nfcinterfaceDriverEntry);
#ifdef __cplusplus
}

添加基本的HdfNfcInterfaceDriverBind、HdfNfcInterfaceDriverInit、HdfNfcInterfaceDriverRelease接口实现:

struct HdfNfcInterfaceHost {
    struct IDeviceIoService ioservice;
    OHOS::sptr<OHOS::IRemoteObject> stub;
};////////---------------
//HdfNfcInterfaceDriverBind驱动服务绑定到HDF
static int HdfNfcInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("HdfNfcInterfaceDriverBind enter");
    auto *hdfNfcInterfaceHost = new (std::nothrow) HdfNfcInterfaceHost;
    if (hdfNfcInterfaceHost == nullptr) {
        HDF_LOGE("HdfNfcInterfaceDriverBind, failed to create HdfNfcInterfaceDriverBind Object!");
        return HDF_FAILURE;
    }
​
    hdfNfcInterfaceHost->ioservice.Dispatch = NfcInterfaceDriverDispatch;
    hdfNfcInterfaceHost->ioservice.Open = nullptr;
    hdfNfcInterfaceHost->ioservice.Release = nullptr;
​
    auto serviceImpl = INfcInterface::Get(true);
    if (serviceImpl == nullptr) {
        HDF_LOGE("HdfNfcInterfaceDriverBind, failed to get of implement service");
        delete hdfNfcInterfaceHost;
        return HDF_FAILURE;
    }
​
    hdfNfcInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
        INfcInterface::GetDescriptor());
    if (hdfNfcInterfaceHost->stub == nullptr) {
        HDF_LOGE("HdfNfcInterfaceDriverBind, failed to get stub object");
        delete hdfNfcInterfaceHost;
        return HDF_FAILURE;
    }
​
    deviceObject->service = &hdfNfcInterfaceHost->ioservice;
    HDF_LOGI("HdfNfcInterfaceDriverBind Success");
    return HDF_SUCCESS;
}
static int32_t NfcInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
    struct HdfSBuf *reply)
{
    auto *hdfNfcInterfaceHost =
        CONTAINER_OF(client->device->service, struct HdfNfcInterfaceHost, ioservice);
​
    OHOS::MessageParcel *dataParcel = nullptr;
    OHOS::MessageParcel *replyParcel = nullptr;
    OHOS::MessageOption option;
​
    if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
        HDF_LOGE("NfcInterfaceDriverDispatc, invalid data sbuf object to dispatch");
        return HDF_ERR_INVALID_PARAM;
    }
    if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
        HDF_LOGE("NfcInterfaceDriverDispatch, invalid reply sbuf object to dispatch");
        return HDF_ERR_INVALID_PARAM;
    }
​
    return hdfNfcInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
}
//HdfNfcInterfaceDriverInit驱动初始化
static int HdfNfcInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("HdfNfcInterfaceDriverInit enter");
    return HDF_SUCCESS;
}
//HdfNfcInterfaceDriverRelease
static void HdfNfcInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("HdfNfcInterfaceDriverRelease enter");
    if (deviceObject->service == nullptr) {
        HDF_LOGE("HdfNfcInterfaceDriverRelease not initted");
        return;
    }
​
    auto *hdfNfcInterfaceHost =
        CONTAINER_OF(deviceObject->service, struct HdfNfcInterfaceHost, ioservice);
    delete hdfNfcInterfaceHost;
    HDF_LOGI("HdfNfcInterfaceDriverRelease Success");
}

2)同级目录添加接口引用文件

添加nfc_impl.h和对应的cpp文件,供接口调用

//nfc_impl.h
namespace OHOS {
namespace HDI {
namespace Nfc {
namespace V1_0 {
class NfcImpl : public INfcInterface {
public:
    virtual ~NfcImpl() {}
    int32_t Open(const sptr<INfcCallback> &callbackObj, NfcStatus &status) override;
    int32_t CoreInitialized(const std::vector<uint8_t> &data, NfcStatus &status) override;
    int32_t Prediscover(NfcStatus &status) override;
    int32_t Write(const std::vector<uint8_t> &data, NfcStatus &status) override;
    int32_t ControlGranted(NfcStatus &status) override;
    int32_t PowerCycle(NfcStatus &status) override;
    int32_t Close(NfcStatus &status) override;
    int32_t Ioctl(NfcCommand cmd, const std::vector<uint8_t> &data, NfcStatus &status) override;
private:
    NfcVendorAdaptions adaptor_;
};
} // V1_0
} // Nfc
} // HDI
} // OHOS

cpp接口实现:

//nfc_impl.cpp
namespace OHOS {
namespace HDI {
namespace Nfc {
namespace V1_0 {
static sptr<V1_0::INfcCallback> g_callbackV1_0 = nullptr;
​
static void EventCallback(unsigned char event, unsigned char status)
{
    if (g_callbackV1_0 != nullptr) {
        g_callbackV1_0->OnEvent((NfcEvent)event, (NfcStatus)status);
    }
}
​
static void DataCallback(uint16_t len, uint8_t *data)
{
    if (g_callbackV1_0 != nullptr) {
        std::vector<uint8_t> vec(data, data + len / sizeof(uint8_t));
        g_callbackV1_0->OnData(vec);
    }
}
​
extern "C" INfcInterface *NfcInterfaceImplGetInstance(void)
{
    using OHOS::HDI::Nfc::V1_0::NfcImpl;
    NfcImpl *service = new (std::nothrow) NfcImpl();
    if (service == nullptr) {
        return nullptr;
    }
    return service;
}
​
int32_t NfcImpl::Open(const sptr<INfcCallback> &callbackObj, NfcStatus &status)
{
    if (callbackObj == nullptr) {
        HDF_LOGE("Open, callback is nullptr!");
        return HDF_ERR_INVALID_PARAM;
    }
    g_callbackV1_0 = callbackObj;
​
    int ret = adaptor_.VendorOpen(EventCallback, DataCallback);
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::CoreInitialized(const std::vector<uint8_t> &data, NfcStatus &status)
{
    if (data.empty()) {
        HDF_LOGE("CoreInitialized, data is nullptr!");
        return HDF_ERR_INVALID_PARAM;
    }
    int ret = adaptor_.VendorCoreInitialized(data.size(), (uint8_t *)&data[0]);
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::Prediscover(NfcStatus &status)
{
    int ret = adaptor_.VendorPrediscover();
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::Write(const std::vector<uint8_t> &data, NfcStatus &status)
{
    if (data.empty()) {
        HDF_LOGE("Write, data is nullptr!");
        return HDF_ERR_INVALID_PARAM;
    }
    int ret = adaptor_.VendorWrite(data.size(), (uint8_t *)&data[0]);
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::ControlGranted(NfcStatus &status)
{
    int ret = adaptor_.VendorControlGranted();
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::PowerCycle(NfcStatus &status)
{
    int ret = adaptor_.VendorPowerCycle();
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::Close(NfcStatus &status)
{
    g_callbackV1_0 = nullptr;
    int ret = adaptor_.VendorClose(true);
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
​
int32_t NfcImpl::Ioctl(NfcCommand cmd, const std::vector<uint8_t> &data, NfcStatus &status)
{
    if (data.empty()) {
        HDF_LOGE("Ioctl, data is nullptr!");
        return HDF_ERR_INVALID_PARAM;
    }
    int ret = adaptor_.VendorIoctl(data.size(), (uint8_t *)&data[0]);
    if (ret == 0) {
        status = NfcStatus::OK;
        return HDF_SUCCESS;
    }
    status = NfcStatus::FAILED;
    return HDF_FAILURE;
}
} // V1_0
} // Nfc
} // HDI
} // OHOS

//该层对外接口也可不提供,直接在添加驱动时,进行接口调用。比如在HdfNfcInterfaceDriverInit驱动初始化时,先定义与驱动配置nfc_config.hcs中对应的结构g_nfcCfg,示例:

struct DeviceResourceIface *devIface = NULL;
devIface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
//获取驱动配置信息
if (devIface->GetUint32(deviceObject,"nfc_version",&g_nfcCfg.nfcVersion),0 != HDF_SUCCESS) {
    g_nfcCfg.nfcVersion = 0;
    HDF_LOGE("%s:Get nfc_version is fail!");
}

4、Mekefile及Kconfig文件编写

在.\drivers\hdf_core\adapter\khdf\linux\model目录下新建nfc文件夹,添加Kconfig文件

config DRIVERS_HDF_NFC
    bool "Enable HDF nfc driver"
    default n
    depends on DRIVERS_HDF
    help
      Answer Y to enable HDF nfc driver.

在上面nfc目录下添加Makefile文件

LIGHT_ROOT_DIR = ../../../../../../framework/model/nfc/driver
​
obj-$(CONFIG_DRIVERS_HDF_NFC) += \
               $(LIGHT_ROOT_DIR)/src/nfc_driver.o
​
ccflags-y +=--I$(srctree)/drivers/hdf/framework/include/core \
            -I$(srctree)/drivers/hdf/framework/core/common/include/host \
            -I$(srctree)/drivers/hdf/framework/include/utils \
            -I$(srctree)/drivers/hdf/framework/include/osal \
            -I$(srctree)/drivers/hdf/framework/include/platform \
            -I$(srctree)/drivers/hdf/framework/include/config \
            -I$(srctree)/drivers/hdf/framework/core/host/include \
            -I$(srctree)/drivers/hdf/framework/core/shared/include \
            -I$(srctree)/drivers/hdf/framework/utils/include \
            -I$(srctree)/drivers/hdf/khdf/osal/include \
            -I$(srctree)/bounds_checking_function/include

将新建的Makefile及Kconfig添加到外层的对应文件中,路径如下:

//.\drivers\hdf_core\adapter\khdf\linux\Kconfig;
source "drivers/hdf/khdf/model/nfc/Kconfig"
//.\drivers\hdf_core\adapter\khdf\linux\Makefile;
obj-$(CONFIG_DRIVERS_HDF_NFC) += model/nfc/

5、配置硬件属性

//.\vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs,示例供参考:
 root {
    device_info {
        .........
        .........
        nfc :: host {
            hostName = "nfc_host";
            device_nfc :: device {                  
                device0 :: deviceNode {             //设备的某个具体节点配置信息
                    policy = 2;                     //驱动服务发布策略
                    priority = 100;                 //驱动启动优先级
                    permission = 0644;              //驱动按需加载字段
                    moduleName = "nfc_driver";      //驱动名称,需和驱动入口的moduleName一致
                    serviceName = "nfc_service";    //驱动
                    deviceMatchAttr = "nfc_config"
                }
            }
        }
        .........
        .........
    }
 }
 

6、配置私有属性

在.\vendor\hihope\rk3568\hdf_config\khdf目录下新建nfc文件夹,然后再nfc下添加nfc_config.hcs文件,添加私有属性。示例供参考:

root {
      nfc_config {
      match_attr = "nfc_config";//该字段必须和evice_info.hcs中deviceMatchAttr的值一致
      nfc_version = 1.0;//版本信息
      gpio_sda = 0;//复用I2C_SDA的管脚号
      gpio_scl = 1;//复用I2C_SCL的管脚号
      .........
      .........
    }
}

在hdf.hcs文件添加编译:

//.\vendor\hihope\rk3568\hdf_config\khdf\hdf.hcs
#include "nfc/nfc_config.hcs"

7、参考资料

1、https://gitee.com/openharmony/vendor_hisilicon/tree/master/hispark_pegasus/demo/nfc_demo

2、https://gitee.com/openharmony/drivers_peripheral/tree/OpenHarmony-4.0-Beta1/connected_nfc_tag

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐