OpenHarmony南向之旅之HDF传感器驱动开发

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenHarmony南向之旅之HDF传感器驱动开发相关的知识,希望对你有一定的参考价值。

(OpenHarmony南向之旅之HDF传感器驱动开发)

前言

开发准备

硬件环境

  1. Unionpi Tiger开发板
  2. SHT31温湿度传感器

在开发之前我们先简单了解一下源码驱动目录

在OpenHarmony根目录下的drivers\\hdf_core\\framework\\model\\sensor\\driver目录,这里存放的是通用传感器驱动代码目录,主要是由HDF Sensor驱动框架提供的Init、Enable、Disable等接口实现

而在drivers\\peripheral\\sensor\\chipset目录下存放的是传感器差异化驱动代码,主要是根据不同的传感器芯片型号在通用传感器驱动代码提供出来的接口上进行开发适配,例如温度传感器有SHT3x、AHT系列等,这就需要分别进行开发

开发流程

添加配置

在HDF框架的配置文件(例如笔者这里是vendor\\unionman\\unionpi_tiger\\hdf_config\\khdf\\device_info\\device_info.hcs)中的Sensor Host添加该驱动的配置信息

/* 温度计传感器设备HCS配置 */
device_sensor_temperature :: device 
    device0 :: deviceNode 
        policy = 1;
        priority = 130;
        preload = 0;
        permission = 0664;
        moduleName = "HDF_SENSOR_TEMPERATURE";
        serviceName = "sensor_temperature";
        deviceMatchAttr = "hdf_sensor_temperature_driver";
    

device_sensor_sht31 :: device 
    device0 :: deviceNode 
        policy = 1;              // 驱动对外发布服务的策略(0-4),具体可以查看参考资料[3]
        priority = 140;          // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序。
        preload = 0;             // 驱动按需加载字段。
        permission = 0664;       // 驱动创建设备节点权限
        moduleName = "HDF_SENSOR_TEMPERATURE_SHT31";      // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致。
        serviceName = "hdf_temperature_sht31";    // 驱动对外发布服务的名称,必须唯一。
        deviceMatchAttr = "hdf_sensor_temperature_sht31_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等。
    

对应关系如下

通用驱动代码开发

1.基于HDF驱动框架,按照驱动Driver Entry程序,完成温度抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现

  • 温度传感器驱动入口函数实现
/* 注册温度计传感器入口数据结构体对象 */
struct HdfDriverEntry g_sensorTemperatureDevEntry = 
    .moduleVersion = 1,                // 温度计传感器模块版本号
    .moduleName = "HDF_SENSOR_TEMPERATURE",  // 温度计传感器模块名,要与device_info.hcs文件里的温度计moduleName字段值一样
    .Bind = TemperatureBindDriver,           // 温度计传感器绑定函数
    .Init = TemperatureInitDriver,           // 温度计传感器初始化函数
    .Release = TemperatureReleaseDriver,     // 温度计传感器资源释放函数
;

/* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_sensorTemperatureDevEntry);
  • 温度传感器驱动操作接口实现
/* 温度计传感器驱动对外提供的服务绑定到HDF框架 */
int32_t TemperatureBindDriver(struct HdfDeviceObject *device)

    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

    struct TemperatureDrvData *drvData = (struct TemperatureDrvData *)OsalMemCalloc(sizeof(*drvData));
    if (drvData == NULL) 
        HDF_LOGI("%s: malloc temperature drv data fail!", __func__);
        return HDF_ERR_MALLOC_FAIL;
    

    drvData->ioservice.Dispatch = DispatchTemperature;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_temperatureDrvData = drvData;
    return HDF_SUCCESS;


/* 注册温度计传感器驱动归一化的接口函数 */
static int32_t InitTemperatureOps(struct SensorCfgData *config, struct SensorDeviceInfo *deviceInfo)

    CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);

    deviceInfo->ops.Enable = SetTemperatureEnable;
    deviceInfo->ops.Disable = SetTemperatureDisable;
    deviceInfo->ops.SetBatch = SetTemperatureBatch;
    deviceInfo->ops.SetMode = SetTemperatureMode;
    deviceInfo->ops.SetOption = SetTemperatureOption;

    if (memcpy_s(&deviceInfo->sensorInfo, sizeof(deviceInfo->sensorInfo), &config->sensorInfo,
            sizeof(config->sensorInfo)) != EOK) 
        HDF_LOGE("%s: Copy sensor info failed", __func__);
        return HDF_FAILURE;
    

    return HDF_SUCCESS;


/* 提供给差异化驱动的初始化接口,完成温度器件基本配置信息解析(温度信息、温度总线配置、温度器件探测寄存器配置)、器件探测、器件寄存器解析 */
static int32_t InitTemperatureAfterDetected(struct SensorCfgData *config)

    struct SensorDeviceInfo deviceInfo;
    CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);

    if (InitTemperatureOps(config, &deviceInfo) != HDF_SUCCESS) 
        HDF_LOGE("%s: Init temperature ops failed", __func__);
        return HDF_FAILURE;
    

    if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) 
        HDF_LOGE("%s: Add temperature device failed", __func__);
        return HDF_FAILURE;
    

    if (ParseSensorRegConfig(config) != HDF_SUCCESS) 
        HDF_LOGE("%s: Parse sensor register failed", __func__);
        (void)DeleteSensorDevice(&config->sensorInfo);
        ReleaseSensorAllRegConfig(config);
        return HDF_FAILURE;
    
    return HDF_SUCCESS;


/* 温度计传感器驱动初始化入口函数,主要功能为对传感器私有数据的结构体对象进行初始化,传感器HCS数据配置对象空间分配,传感器HCS数据配置初始化入口函数调用,传感器设备探测是否在位功能,传感器数据上报定时器创建,传感器归一化接口注册,传感器设备注册功能 */ 
int32_t TemperatureInitDriver(struct HdfDeviceObject *device)

    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct TemperatureDrvData *drvData = (struct TemperatureDrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    /* 工作队列资源初始化 */
    if (InitTemperatureData(drvData) != HDF_SUCCESS) 
        HDF_LOGE("%s: Init accel config failed", __func__);
        return HDF_FAILURE;
    
    /* 分配温度配置信息资源 */
    drvData->temperatureCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->temperatureCfg));
    if (drvData->temperatureCfg == NULL) 
        HDF_LOGE("%s: Malloc temperature config data failed", __func__);
        return HDF_FAILURE;
    
    /* 注册寄存器分组信息 */
    drvData->temperatureCfg->regCfgGroup = &g_regCfgGroup[0];

    HDF_LOGI("%s: Init temperature driver success", __func__);
    return HDF_SUCCESS;

/* 释放驱动初始化时分配的资源 */
void TemperatureReleaseDriver(struct HdfDeviceObject *device)

    CHECK_NULL_PTR_RETURN(device);

    struct TemperatureDrvData *drvData = (struct TemperatureDrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);
    /* 器件在位,释放已分配资源 */
    if (drvData->detectFlag && drvData->temperatureCfg != NULL) 
        TemperatureReleaseCfgData(drvData->temperatureCfg);
    

    OsalMemFree(drvData->temperatureCfg);
    drvData->temperatureCfg = NULL;
    /* 器件在位,销毁工作队列资源 */
    HdfWorkDestroy(&drvData->temperatureWork);
    HdfWorkQueueDestroy(&drvData->temperatureWorkQueue);
    OsalMemFree(drvData);

2.完成温度传感器抽象驱动内部接口开发,包括Enable、Disable、SetBatch、SetMode、SetOption、AccelCreateCfgData、AccelReleaseCfgData、AccelRegisterChipOps接口实现

/* 下发使能寄存器组的配置 */
static int32_t SetTemperatureEnable(void)

    int32_t ret;
    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    CHECK_NULL_PTR_RETURN_VALUE(drvData->temperatureCfg, HDF_ERR_INVALID_PARAM);

    if (drvData->enable) 
        HDF_LOGE("%s: temperature sensor is enabled", __func__);
        return HDF_SUCCESS;
    

    ret = SetSensorRegCfgArray(
        &drvData->temperatureCfg->busCfg, drvData->temperatureCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: temperature sensor enable config failed", __func__);
        return ret;
    

    ret = OsalTimerCreate(&drvData->temperatureTimer, SENSOR_TIMER_MIN_TIME, TemperatureTimerEntry, (uintptr_t)drvData);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: temperature create timer failed[%d]", __func__, ret);
        return ret;
    

    ret = OsalTimerStartLoop(&drvData->temperatureTimer);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: temperature start timer failed[%d]", __func__, ret);
        return ret;
    
    drvData->enable = true;

    return HDF_SUCCESS;

/* 下发去使能寄存器组的配置 */
static int32_t SetTemperatureDisable(void)

    int32_t ret;
    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    CHECK_NULL_PTR_RETURN_VALUE(drvData->temperatureCfg, HDF_ERR_INVALID_PARAM);

    if (!drvData->enable) 
        HDF_LOGE("%s: temperature sensor had disable", __func__);
        return HDF_SUCCESS;
    

    ret = SetSensorRegCfgArray(
        &drvData->temperatureCfg->busCfg, drvData->temperatureCfg->regCfgGroup[SENSOR_DISABLE_GROUP]);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: temperature sensor disable config failed", __func__);
        return ret;
    

    ret = OsalTimerDelete(&drvData->temperatureTimer);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: temperature delete timer failed", __func__);
        return ret;
    
    drvData->enable = false;
    return HDF_SUCCESS;

/* 配置传感器采样率和数据上报间隔 */
static int32_t SetTemperatureBatch(int64_t samplingInterval, int64_t interval)

    (void)interval;

    struct TemperatureDrvData *drvData = NULL;

    drvData = TemperatureGetDrvData();
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    drvData->interval = samplingInterval;

    return HDF_SUCCESS;

/* 设置传感器工作模式,当前支持实时模式 */
static int32_t SetTemperatureMode(int32_t mode)

    if (mode <= SENSOR_WORK_MODE_DEFAULT || mode >= SENSOR_WORK_MODE_MAX) 
        HDF_LOGE("%s: The current mode is not supported", __func__);
        return HDF_FAILURE;
    

    return HDF_SUCCESS;

/* 设置传感器可选配置 */
static int32_t SetTemperatureOption(uint32_t option)

    (void)option;
    return HDF_SUCCESS;

/* 创建传感器配置数据接口 */
struct SensorCfgData *TemperatureCreateCfgData(const struct DeviceResourceNode *node)

    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    if (drvData == NULL || node == NULL) 
        HDF_LOGE("%s: Temperature node pointer NULL", __func__);
        return NULL;
    
    /* 如果探测不到器件在位,返回进行下个器件探测 */
    if (drvData->detectFlag) 
        HDF_LOGE("%s: Temperature sensor have detected", __func__);
        return NULL;
    

    if (drvData->temperatureCfg == NULL) 
        HDF_LOGE("%s: Temperature temperatureCfg pointer NULL", __func__);
        return NULL;
    
	/* 解析器件HCS私有配置信息 */
    if (GetSensorBaseConfigData(node, drvData->temperatureCfg) != HDF_SUCCESS) 
        HDF_LOGE("%s: Get sensor base config failed", __func__);
        goto BASE_CONFIG_EXIT;
    
    /* 如果探测不到器件在位,返回进行下个器件探测 */
    if (DetectSensorDevice(drvData->temperatureCfg) != HDF_SUCCESS) 
        HDF_LOGI("%s: Temperature sensor detect device no exist", __func__);
        drvData->detectFlag = false;
        goto BASE_CONFIG_EXIT;
    

    drvData->detectFlag = true;
    /* 器件寄存器解析 */
    if (InitTemperatureAfterDetected(drvData->temperatureCfg) != HDF_SUCCESS) 
        HDF_LOGE("%s: Temperature sensor detect device no exist", __func__);
        goto INIT_EXIT;
    
    return drvData->temperatureCfg;

INIT_EXIT:
    (void)ReleaseSensorBusHandle(&drvData->temperatureCfg->busCfg);
BASE_CONFIG_EXIT:
    drvData->temperatureCfg->root = NULL;
    (void)memset_s(
        &drvData->temperatureCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo));
    (void)memset_s(&drvData->temperatureCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));
    (void)memset_s(&drvData->temperatureCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));
    return drvData->temperatureCfg;

/* 释放传感器配置数据接口 */
void TemperatureReleaseCfgData(struct SensorCfgData *temperatureCfg)

    CHECK_NULL_PTR_RETURN(temperatureCfg);

    (void)DeleteSensorDevice(&temperatureCfg->sensorInfo);
    ReleaseSensorAllRegConfig(temperatureCfg);
    (void)ReleaseSensorBusHandle(&temperatureCfg->busCfg);

    temperatureCfg->root = NULL;
    (void)memset_s(&temperatureCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo));
    (void)memset_s(&temperatureCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));
    (void)memset_s(&temperatureCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));

/* 注册传感器差异化接口 */
int32_t TemperatureRegisterChipOps(const struct TemperatureOpsCall *ops)

    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    CHECK_NULL_PTR_RETURN_VALUE(ops, HDF_ERR_INVALID_PARAM);

    drvData->ops.Init = ops->Init;
    drvData->ops.ReadData = ops->ReadData;
    return HDF_SUCCESS;

差异化驱动代码开发

1.基于HDF驱动框架,按照驱动Driver Entry程序,完成温度传感器差异化驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现

/* 温度计传感器差异化驱动消息交互 */
static int32_t DispatchSHT31(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)

    (void)client;
    (void)cmd;
    (void)data;
    (void)reply;

    return HDF_SUCCESS;

/* 温度计传感器差异化驱动对外提供的服务绑定到HDF框架 */
int32_t SHT31BindDriver(struct HdfDeviceObject *device)

    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

    struct SHT31DrvData *drvData = (struct SHT31DrvData *)OsalMemCalloc(sizeof(*drvData));
    if (drvData == NULL) 
        HDF_LOGE("%s: Malloc SHT31 drv data fail", __func__);
        return HDF_ERR_MALLOC_FAIL;
    

    drvData->ioService.Dispatch = DispatchSHT31;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_sht31DrvData = drvData;

    return HDF_SUCCESS;

/* 温度计传感器差异化驱动初始化 */
int32_t SHT31InitDriver(struct HdfDeviceObject *device)

    int32_t ret;
    struct TemperatureOpsCall ops;

    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct SHT31DrvData *drvData = (struct SHT31DrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    drvData->sensorCfg = TemperatureCreateCfgData(device->property);
    if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) 
        HDF_LOGD("%s: Creating temperaturecfg failed because detection failed", __func__);
        return HDF_ERR_NOT_SUPPORT;
    

    ops.Init = NULL;
    ops.ReadData = ReadSHT31Data;
    ret = TemperatureRegisterChipOps(&ops);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: Register SHT31 temperature failed", __func__);
        return HDF_FAILURE;
    

    ret = InitSHT31(drvData->sensorCfg);
    if (ret != HDF_SUCCESS) 
        HDF_LOGE("%s: Init SHT31 temperature failed", __func__);
        return HDF_FAILURE;
    

    HDF_LOGI("%s: Init SHT31 temperature success", __func__);
    return HDF_SUCCESS;

/* 释放驱动初始化时分配的资源 */
void SHT31ReleaseDriver(struct HdfDeviceObject *device)

    CHECK_NULL_PTR_RETURN(device);

    struct SHT31DrvData *drvData = (struct SHT31DrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);

    if (drvData->sensorCfg != NULL) 
        TemperatureReleaseCfgData(drvData->sensorCfg);
        drvData->sensorCfg = NULL;
    
    OsalMemFree(drvData);

/* 温度传感器差异化驱动对应的HdfDriverEntry对象 */
struct HdfDriverEntry g_temperatureSHT31DevEntry = 
    .moduleVersion = 1,
    .moduleName = "HDF_SENSOR_TEMPERATURE_SHT31",
    .Bind = SHT31BindDriver,
    .Init = SHT31InitDriver,
    .Release = SHT31ReleaseDriver,
;

HDF_INIT(g_temperatureSHT31DevEntry);

2.完成温度传感器差异化驱动中差异化接口ReadData函数实现

int32_t ReadSHT31Data(struct SensorCfgData *data)

    int32_t ret;
    static int32_t tmp;
    struct TemperaturemeterData temperaturemeterData = 0;
    OsalTimespec time;
    struct SensorReportEvent event;

    (void)memset_s(&time, sizeof(time), 0, sizeof(time));
    (void)memset_s(&event, sizeof(event), 0, sizeof(event));

    if (OsalGetTime(&time) != HDF_SUCCESS) 
        HDF_LOGE("%s: Get time failed", __func__);
        return HDF_FAILURE;
    
    event.timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT;

    ret = ReadSHT31RawData(data, &temperaturemeterData);
    if (ret != HDF_SUCCESS) 
        return HDF_FAILURE;
    

    event.sensorId = data->sensorInfo.sensorId;
    event.mode = SENSOR_WORK_MODE_REALTIME;

    tmp = temperaturemeterData.temperature;

    event.dataLen = sizeof(tmp);
    event.data = (uint8_t *)&tmp;
    ret = ReportSensorEvent(&event);
    return ret;

添加差异化配置文件

sht31_config.hcs文件参考

文件路径

vendor\\unionman\\unionpi_tiger\\hdf_config\\khdf\\sensor\\temperature\\sht31_config.hcs
#include "../sensor_common.hcs"
root 
    temperature_sht31_chip_config : sensorConfig 
        match_attr = "hdf_sensor_temperature_sht31_driver";
        sensorInfo :: sensorDeviceInfo 
            sensorName = "temperaturemeter";
            vendorName = "sensirion_sht31"; // max string length is 16 bytes
            sensorTypeId = 9; // enum SensorTypeTag
            sensorId = 1; // user define sensor id
            power = 230;
            minDelay = 0;
            maxDelay = 0;
        
        sensorBusConfig :: sensorBusInfo 
            busType = 0; // 0:i2c 1:spi
            busNum = 5;
            busAddr = 0x45;
            regWidth = 2; // 2 byte
        
        sensorIdAttr :: sensorIdInfo 
            chipName = "sht31";
            chipIdRegister = 0xF32D;
            chipIdValue = 0x80;
        
        sensorRegConfig 
            /*  regAddr: register address
                value: config register value
                len: size of value
                mask: mask of value
                delay: config register delay time (ms)
                opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check 4-update_bit
                calType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shift
                shiftNum: shift bits
                debug: 0-no debug 1-debug
                save: 0-no save 1-save
            */
            /* regAddr, value, mask, len, delay, opsType, calType, shiftNum, debug, save */
            initSeqConfig = [
                0x30A2,    0x0, 0x0,   0,     5,       2,       0,        0,     0,    0
            ];
            enableSeqConfig = [
                0x2C06,    0x0, 0x0,   0,     5,       2,       0,        0,     0,    0
            ];
            disableSeqConfig = [
                0x2400,    0x0, 0x0,   0,     5,       2,       0,        0,     0,    0
            ];
        
    

对应关系如下

编译准备

打开vendor\\unionman\\unionpi_tiger\\hdf_config\\khdf\\sensor\\sensor_config.hcs文件并include差异化配置文件

修改drivers\\hdf_core\\adapter\\khdf\\linux\\model\\sensor\\Makefile编译文件

修改drivers\\hdf_core\\adapter\\khdf\\linux\\model\\sensor\\Kconfig配置文件

device\\board\\unionman\\unionpi_tiger\\kernel\\build\\unionpi_tiger_standard_defconfig打开CONFIG_DRIVERS_HDF_SENSOR 对应关系如下

运行结果

成功初始化SHT31传感器驱动

测试

测试代码参考

代码路径

vendor\\unionman\\unionpi_tiger\\sample\\hdf\\temperature\\temperature.cpp
#include <unistd.h>
#include <stdio.h>
#include "hdf_base.h"
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"
#include "sensor_if.h"
#include "sensor_type.h"

/* 创建回调函数 */
int32_t SensorDataCallback(const struct SensorEvents *event)

    if (event == NULL) 
        return HDF_FAILURE;
    
    float *data = (float *)event->data;
    printf("sensor data %.2f°C\\n", *data);
    return HDF_SUCCESS;


void SensorSample(void)

    int ret;
    struct SensorInformation *sensorInfo = NULL;
    int32_t count = 0;
    int32_t sensorInterval = 200000000; /* 数据采样率设置200毫秒,单位纳秒 */
    int32_t reportInterval = 400000000;

    /* 1.创建传感器接口实例 */
    const struct SensorInterface *sensorDev = NewSensorInterfaceInstance();
    if (sensorDev == NULL) 
        return;
    
    printf("NewSensorInterfaceInstance success\\n");
    /* 2.订阅者注册传感器数据回调处理函数 */
    ret = sensorDev->Register(0, SensorDataCallback);
    if (ret != 0) 
        return;
    
    printf("Register success\\n");
    /* 3.获取设备支持的Sensor列表 */
    ret = sensorDev->GetAllSensors(&sensorInfo, &count);
    if (ret != 0) 
        return;
    
    printf("GetAllSensors success,count: %d\\n sensorName:%s\\n vendorName:%s\\n sensorTypeId:%d\\n sensorId:%d\\n", count,
           sensorInfo->sensorName, sensorInfo->vendorName, sensorInfo->sensorTypeId, sensorInfo->sensorId);
    /* 4.设置传感器采样率 */
    ret = sensorDev->SetBatch(sensorInfo->sensorId, sensorInterval, reportInterval);
    if (ret != 0) 
        printf("SetBatch failed\\n ,ret: %d", ret);
        return;
    
    printf("SetBatch success\\n");
    /* 5.使能传感器 */
    ret = sensorDev->Enable(sensorInfo->sensorId);
    if (ret != 0) 
        return;
    
    printf("Enable success\\n");

    usleep(2000 * 1000);

    /* 6.去使能传感器 */
    ret = sensorDev->Disable(sensorInfo->sensorId);
    if (ret != 0) 
        printf("Disable failed\\n ,ret: %d", ret);
        return;
    
    printf("Disable success\\n");
    /* 7.取消传感器数据订阅函数 */
    ret = sensorDev->Unregister(0, SensorDataCallback);
    if (ret != 0) 
        return;
    
    printf("Unregister success\\n");
    /* 8.释放传感器接口实例 */
    ret = FreeSensorInterfaceInstance();
    if (ret != 0) 
        return;
    
    printf("FreeSensorInterfaceInstance success\\n");


int main(int argc, char *argv[])

    SensorSample();
    return HDF_SUCCESS;

BUILD.gn参考

import("//build/ohos.gni")

ohos_executable("temperature") 
  sources = [ "temperature.cpp" ]

  deps = [ "//drivers/peripheral/sensor/hal:hdi_sensor" ]

  external_deps = [
    "hiviewdfx_hilog_native:libhilog",
  ]

  cflags = [
    "-Wall",
    "-Wextra",
    "-Werror",
    "-Wno-format",
    "-Wno-format-extra-args",
  ]

  install_enable = true
  install_images = [ "vendor" ]
  module_install_dir = "bin"
  part_name = "unionman_products"

编译命令

./build.sh --product-name unionpi_tiger --build-target vendor/unionman/unionpi_tiger/sample/hdf/temperature:temperature

生成可执行文件所在位置

out\\unionpi_tiger\\device_unionpi_tiger\\unionman_products

将可执行文件push到system/bin目录下,添加执行权限

hdc shell mount -o remount,rw /
hdc file send <PATH>\\out\\unionpi_tiger\\device_unionpi_tiger\\unionman_products\\temperature /system/bin
hdc shell chmod 744 system/bin/temperature

运行结果

成功打印驱动上报的温度数据

踩坑记录

基本上按照HDF框架开发步骤来还是比较简单的,笔者是第一次玩驱动开发,相信对驱动开发熟悉的开发者来说HDF框架是很友好的。笔者踩的一些坑主要是因为笔者对南向开发不熟悉,没有玩过硬件

1.这款传感器的寄存器地址是两个字节,而HDF框架源码的逻辑只能处理一个字节,会出现以下错误

2.由于这款传感器没有chipId,所以私有化配置文件中的chipIdValue字段的值填写打印出来的128,也就是0x80(这样做可能不太正规,有更好的做法欢迎指出)

3.由于笔者不太理解ReadSensor接口中的regAddr参数,传了不正确的值

int32_t ReadSensor(struct SensorBusCfg *busCfg, uint16_t regAddr, uint8_t *data, uint16_t dataLen)

导致出现了如下结果

结语

以上仅为个人浅见,如有疑问,欢迎留言交流

参考文档

[1]Sensor驱动模型接口说明

[2]drivers_peripheral

[3]驱动服务管理

本文作者:Haoc_小源同学

想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com/#bkwz​

OpenHarmony驱动框架HDF中设备管理服务构建过程详解

作者: 侯旗

前言

如下图,开源鸿蒙系统驱动框架HDF在内核中的实现,可以分为向用户层提供设备服务的管理模块(Manager),和实际管理硬件的Host模块。
Manager分为DeviceManageService和 DeviceServiceManage,前者负责提供服务的设备,包括设备驱动匹配、设备驱动装载、设备启动等;后者负责关联设备提供的服务,包括管理Host端提供的设备服务,和接收用户发起的设备服务订阅请求。

图1 开源鸿蒙系统驱动框架软件架构模块图

本文主要关注点在DeviceManageService,叙述其如何启动设备、创建设备服务节点、装载驱动,以及发布服务的过程。

文章内容简介

开源鸿蒙系统驱动框架HDF内核实现部分完全使用C语言实现,也引入了面向对象编程的思想,使用C语言实现了诸如类继承、虚函数、单例类等的概念,使得HDF内核部分包含了大量的对象类型,对象类型又通过的接口形式对外提供服务。

为了向读者展现开源鸿蒙系统驱动框架HDF内核实现蓝图,本文仅仅介绍介绍DevMgr过程中Manager域和Host域内的对象类型与其接口,先奠定读者对HDF内对象类型的基本认识;然后,在下一篇文章中介绍DevMgrService如何启动设备、装载驱动、发布设备服务的整个过程。

本文章节内容如下:

    1. DevMgr域中的对象类型及接口
    1. Host域中的对象类型及接口

1 DevMgr域中的对象类型及接口

1.1 DevmgrService

1.1.1 DevmgrService及接口

DevmgrService是设备管理的总入口,其Hosts域是一个双向链表,hcs设备配置中的所有Host设备被挂载在这个Hosts双向链表上。

DevmgrService内容及其接口定义如下:

struct IDevmgrService 
    struct HdfObject base;
    struct HdfDeviceObject object;
    // 将Host节点链接到DevMgr的hosts列表
    int (*AttachDeviceHost)(struct IDevmgrService *, uint16_t, struct IDevHostService *);
    // 将HDF设备节点以Token的形式连接到host的devices列表
    int (*AttachDevice)(struct IDevmgrService *, const struct HdfDeviceInfo *, struct IHdfDeviceToken *);
    // 启动DevmgrService服务
    int (*StartService)(struct IDevmgrService *);
    int (*PowerStateChange)(struct IDevmgrService *, enum HdfPowerState pEvent);
;

struct DevmgrService 
    struct IDevmgrService super;
    struct DListHead hosts;
    struct OsalMutex devMgrMutex;
;

由DevmgrService结构体的内容可知,DevmgrService只管理者host设备节点。 有下面章节可知,Host节点下的所有设备则由Host自己管理。

1.1.2 DevMgrService构建过程

下面DevMgrService构建过程,HDF内核实现部分中使用static局部变量实现了C++中单例类的概念,将DevMgrService作为一个单例类,所有的对象指向同一个实体。

 DevmgrServiceCreate()
    |  // C++,单例类概念
    |-> static struct DevmgrService devmgrServiceInstance;
    |-> DevmgrServiceConstruct(&devmgrServiceInstance)
        |-> devMgrSvcIf = (struct IDevmgrService *)inst;
        |
        |-> devMgrSvcIf->AttachDevice =  DevmgrServiceAttachDevice;
        |-> devMgrSvcIf->AttachDeviceHost = DevmgrServiceAttachDeviceHost;
        |-> devMgrSvcIf->StartService =  DevmgrServiceStartService;
        |-> devMgrSvcIf->PowerStateChange = DevmgrServicePowerStateChange;

1.1.3 IDevmgrService接口介绍

(1)StartService:DevmgrServiceStartService()

DevmgrServiceStartService()主要功能是挂载并启动hcs设备配置中的所有host设备节点DevmgrService的hosts链表;然后,启动host节点,间接地启动Host节点下的所有设备(装载设备驱动、发布设备服务等)。

DevmgrServiceStartService()
|-> DevmgrServiceStartDeviceHosts()
    |-> DriverInstallerGetInstance() //  installer
    | // (1) 为每一个Hcs配置中的Host设备创建一个DevHostClnt
    |-> HdfAttributeManagerGetHostList(&hostList);
    |-> HdfSListIteratorInit(&it, &hostList);
    |-> hostAttr = HdfSListIteratorNext(&it);
    |
    |-> hostClnt = DevHostServiceClntNewInstance(
    |                    hostAttr->hostId,
    |                    hostAttr->hostName);
    | // (2) 添加HostClnt到DevMgr的hosts链表
    |-> DListInsertTail(&hostClnt->node, &inst->hosts);
    |
    | // (3) 启动host设备对应的DevHostClnt。
    |-> hostClnt->hostPid = installer->StartDeviceHost()
(2)AttachDeviceHost:DevmgrServiceAttachDeviceHost()

DevmgrServiceAttachDeviceHost()遍历host节点先的所有设备信息,使用DriverLoader构建设备节点,装载驱动,发布服务,然后将设备链接到Host的devices列表。

DevmgrServiceAttachDeviceHost( struct IDevmgrService *inst, uint16_t hostId,
|                               struct IDevHostService *hostService) 
|
| // DevHostServiceClnt 已经在 StartDeviceHost() 内按照hcs设备配置树中的host节点创建
|-> struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, hostId);
|
|-> hostClnt->hostService = hostService;
|   // 获得Host节点下所有的设备节点配置信息
|-> hostClnt->deviceInfos = HdfAttributeManagerGetDeviceList()
|-> hostClnt->devCount = HdfSListCount(hostClnt->deviceInfos);
|
|-> DevHostServiceClntInstallDriver(hostClnt)
    | // 遍历 Host 节点下的所有设备(设备+驱动),并将它们挂载到host的devices列表
    |-> HdfSListIteratorInit(&it, hostClnt->deviceInfos);
    |-> deviceInfo = (struct HdfDeviceInfo *)HdfSListIteratorNext(&it);
    |-> devHostSvcIf->AddDevice(devHostSvcIf, deviceInfo);
(3) AttachDevice:DevmgrServiceAttachDevice

被AttachDeviceHost接口实现DevmgrServiceAttachDeviceHost()调用,在完成host下的设备的驱动匹配、装载及设备服务发布后,将HdfDeviceNode以Token的Token 的形式挂接到 DevHostServiceClnt 的 devices 链表。具体过程如下:

DevmgrServiceAttachDevice(struct IDevmgrService *inst, 
|                          const struct HdfDeviceInfo *deviceInfo,
|                          struct IHdfDeviceToken *token)
|
|-> struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, deviceInfo->hostId);
|-> struct DeviceTokenClnt *tokenClnt = 
|                DeviceTokenClntNewInstance(token); // tokenClnt包含指针指向DeviceToken
|                |-> tokenClnt = (struct DeviceTokenClnt *)OsalMemCalloc(sizeof(struct DeviceTokenClnt));
|                |-> DeviceTokenClntConstruct(tokenClnt, tokenIf);
|                    |-> tokenClnt->tokenIf = tokenIf;
|
|-> tokenClnt->deviceInfo = deviceInfo;
|-> DevmgrServiceUpdateStatus(hostClnt, deviceInfo->deviceId, HDF_SERVICE_USABLE);
|-> HdfSListAdd(&hostClnt->devices, &tokenClnt->node);

1.2 DevHostServiceClnt

1.2.1 DevHostServiceClnt对象类型

DevHostServiceClnt为Host域内DevHostService的概念在Manager域的一个表示,hostService成员为IDevHostService的指针,指向被DevHostService包含的IDevHostService对象地址。此处,又借鉴了C++中基类的概念。

struct DevHostServiceClnt 
    struct DListHead node;               // 链表节点,host设备依次对象挂载在DevMgrService的hosts链表上
    struct HdfSList devices;             // 链表,挂载所有host下的所有设备(以token的形式)
    struct HdfSList *deviceInfos;        // 属于Host设备的所有子设备的devInfo信息
    Map *deviceHashMap;
    struct IDevHostService *hostService; // 指向Host域的host设备服务的实现
    uint16_t devCount;                   // 子设备个数
    uint16_t hostId;                     // 系统内Host设备节点标识,按照加载顺序依次+1;
    int hostPid;                         // 父Host设备节点标识
    const char *hostName;                // Host设备名
;

1.2.2 DevHostServiceClnt 构建流程

DevHostServiceClnt的构建过程如下,若该DevHostServiceClnt不存在,则创建一个对象,初始化其hostService和deviceInfos成员,在其下的设备完全启动后,则将该对象链接到DevMgrService的hosts链表。

static int DevmgrServiceAttachDeviceHost(
    struct IDevmgrService *inst, uint16_t hostId, struct IDevHostService *hostService)

    struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, hostId);
    if (hostClnt == NULL) 
        HDF_LOGE("failed to attach device host, hostClnt is null");
        return HDF_FAILURE;
    
    if (hostService == NULL) 
        HDF_LOGE("failed to attach device host, hostService is null");
        return HDF_FAILURE;
    

    hostClnt->hostService = hostService;
    hostClnt->deviceInfos = HdfAttributeManagerGetDeviceList(hostClnt->hostId, hostClnt->hostName);
    if (hostClnt->deviceInfos == NULL) 
        HDF_LOGW("failed to get device list ");
        return HDF_SUCCESS;
    
    hostClnt->devCount = HdfSListCount(hostClnt->deviceInfos);
    return DevHostServiceClntInstallDriver(hostClnt);

2 Host域内对象类型与接口

2.1 DriverInstaller

2.1.1 DriverInstaller 结构体内容描述

DriverInstaller的功能是根据Hcs设备配置文件中的host节点的名称,启动Host节点服务,包括依次创建Host节点下的所有设备、匹配设备驱动、初始化驱动,发布设备服务等。DriverInstaller的内容定义如下:

struct IDriverInstaller 
    struct HdfObject object;
    int (*StartDeviceHost)(uint32_t, const char *);
;

struct DriverInstaller 
    struct IDriverInstaller super;
;

2.1.2 DriverInstaller构建过程

DriverInstaller 也作为单例类,使用同一个局部static变量实现。

DriverInstallerCreate()
|-> static struct DriverInstaller driverInstaller;
|
|-> DriverInstallerConstruct(&driverInstaller);
    |-> driverInstallIf->StartDeviceHost = DriverInstallerStartDeviceHost;

2.1.3 DriverInstaller 接口简介StartDeviceHost : DriverInstallerStartDeviceHost()

DriverInstallerStartDeviceHost()名义上是启动Host节点服务,实则通过DevMgrService在Host域的client(DevmgrServiceClnt)挂载Host节点到DevMgrService的hosts链表,同时还通过DevHostService的AddDevice()接口将host节点其下的所有设备依次匹配驱动、加载驱动、发布设备服务等。

DriverInstallerStartDeviceHost(uint32_t devHostId, const char *devHostName)
| // 创建Host端DevService
|-> struct IDevHostService *hostServiceIf = DevHostServiceNewInstance(devHostId, devHostName);
|
| // hostServiceIf->StartService(hostServiceIf);
|-> DevHostServiceStartService()
    |-> DevmgrServiceClntAttachDeviceHost()
        | // 创建Host端的DevMgr的Client(“代理”,更合适), DevmgrServiceClnt即IDevmgrService
        |-> struct DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
        |
        | // 将hostService、devInfo和hostClnt关联,并装载匹配的设备驱动
        | // devMgrSvcIf->AttachDeviceHost()
        |-> DevmgrServiceAttachDeviceHost() 
            |-> struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, hostId);
            |-> hostClnt->hostService = hostService;
            |-> hostClnt->deviceInfos = HdfAttributeManagerGetDeviceList()
            |-> DevHostServiceClntInstallDriver(hostClnt)

2.2 DriverLoader

2.2.1 DriverLoader 结构体

DriverLoader主要是完成Host节点下的设备的装载,包括匹配驱动(GetDriverEntry())、初始化驱动、发布设备服务等。

struct IDriverLoader 
    struct HdfObject object;
    struct HdfDriverEntry *(*GetDriverEntry)(const struct HdfDeviceInfo *deviceInfo);
    struct HdfDeviceNode *(*LoadNode)(struct IDriverLoader *, const struct HdfDeviceInfo *deviceInfo);
    void (*UnLoadNode)(struct IDriverLoader *, const struct HdfDeviceInfo *deviceInfo);
;

struct HdfDriverLoader 
    struct IDriverLoader super;
;

2.2.2 DriverLoader 构建

DriverLoader 同样也作为单例类,使用同一个局部static变量实现,比较其不独占任何设备,只是完成设备节点驱动的装载。

HdfDriverLoaderCreate()
|-> static struct HdfDriverLoader driverLoader;
|
|-> HdfDriverLoaderConstruct(&driverLoader);
    |-> struct IDriverLoader *driverLoaderIf = (struct IDriverLoader *)inst;
    |-> driverLoaderIf->LoadNode = HdfDriverLoaderLoadNode;
    |-> driverLoaderIf->UnLoadNode = HdfDriverLoaderUnLoadNode;
    |-> driverLoaderIf->GetDriverEntry = HdfDriverLoaderGetDriverEntry;

2.2.3 DriverLoader 接口简介

(1) GetDriverEntry : HdfDriverLoaderGetDriverEntry()

从DriverEntry列表中获得指定设备的驱动:

HdfDriverLoaderGetDriverEntry()
|-> static struct HdfDriverEntry *driverEntry = NULL;
|-> static int32_t driverCount = 0;
|
|-> strcmp(deviceInfo->moduleName, driverEntry[i].moduleName) == 0
|-> return &driverEntry[i];
(2) LoadNode : HdfDriverLoaderLoadNode()

简介调用自己的接口GetDriverEntry()完成驱动匹配,然后将设备驱动提供的ioService与HdfDeviceNode的IoService绑定。

HdfDriverLoaderLoadNode(struct IDriverLoader *loader,
|                          const struct HdfDeviceInfo *deviceInfo)
|    // 获得对应设备驱动对象
|-> driverEntry = loader->GetDriverEntry(deviceInfo);
|    // 创建设备节点
|-> devNode = HdfDeviceNodeNewInstance();
|    // 绑定驱动与设备节点
|-> devNode->driverEntry = driverEntry;
|-> devNode->deviceInfo = deviceInfo;
|   // 绑定设备服务与IoService
|-> driverEntry->Bind(&devNode->deviceObject)
|
|-> return devNode;

2.3 DevHostService

Sorry,前面引用了那么多Host,一直未明确其概念。 Host在开源鸿蒙系统中可以理解为平台设备子系统,例如display、Input、Network、Sensor、storage等,在这些子系统中又保护了多种接口的实现。以Display子系统为例,可以是SPI接口的设备,也可以是SDIO接口的设备;而具体到SPI设备,有包括了SPI设备1、2、3等。所以才有了“图1.1.1 DevMgr与host及设备关系图”描述的Host与设备之间的关系。

在host域中,使用DevHostService为host设备节点。

2.3.1 DevHostService 结构体

DevHostService作为Host设备在Host域中的表示,管理着其下的所有设备,每一个具体的设备都以HdfDevice的形式挂载到DevHostService的devices链表,不同于DevHostServiceClnt对设备的管理。

struct IDevHostService 
    struct HdfObject object;
    // 添加设备到DevHostService到devices链表
    int (*AddDevice)(struct IDevHostService *hostService, const struct HdfDeviceInfo *devInfo);
    int (*DelDevice)(struct IDevHostService *hostService, const struct HdfDeviceInfo *devInfo);
    // 启动host服务
    int (*StartService)(struct IDevHostService *hostService);
    int (*PmNotify)(struct IDevHostService *service, uint32_t powerState);
;

struct DevHostService 
    struct IDevHostService super;
    uint16_t hostId;                // host设备在系统中的唯一表示,按照加载顺序,依次+1
    const char *hostName;
    struct DListHead devices;       // 链表,挂载着host下所有设备的
    struct HdfServiceObserver observer;
    struct HdfSysEventNotifyNode sysEventNotifyNode;
}

2.3.2 DevHostService 构建流程

DevHostService对象的构建比较简单,分配内存,然后初始化,因为对应的是一个个的Host节点,所有也没有单例类的感念。

void DevHostServiceConstruct(struct DevHostService *service)

    struct IDevHostService *hostServiceIf = &service->super;
    if (hostServiceIf != NULL) 
        hostServiceIf->AddDevice = DevHostServiceAddDevice;
        hostServiceIf->DelDevice = DevHostServiceDelDevice;
        hostServiceIf->StartService = DevHostServiceStartService;
        hostServiceIf->PmNotify = DevHostServicePmNotify;
        DListHeadInit(&service->devices);
        HdfServiceObserverConstruct(&service->observer);
    

2.3.3 IDevHostService 接口简介

(1)StartService : DevHostServiceStartService()

DevHostServiceStartService()启动HostService,间接调用AddDevice接口,依次加载host下的所有子设备。

DevHostServiceStartService(struct IDevHostService *service)
|-> DevmgrServiceClntAttachDeviceHost()
    |  //  通过DevMgr在Host端的Client,调用
    |-> DevmgrServiceAttachDeviceHost()
        | // 将DevService和deviceInfo与DevHostClnt关联。
        |-> hostClnt->hostService = hostService;
        |-> hostClnt->deviceInfos = HdfAttributeManagerGetDeviceList()
        |
        |-> DevHostServiceClntInstallDriver(hostClnt)
            |-> devHostSvcIf = (struct IDevHostService *)hostClnt->hostService;
            |-> HdfSListIteratorInit(&it, hostClnt->deviceInfos);
            |-> deviceInfo = (struct HdfDeviceInfo *)HdfSListIteratorNext(&it);
            |-> devHostSvcIf->AddDevice(devHostSvcIf, deviceInfo);
(2)AddDevice : DevHostServiceAddDevice()

DevHostServiceAddDevice()的功能前面有所带过,主要是根据deviceInfo创建HdfDevice对象、匹配设备驱动、装载设备驱动、DevHostServiceClnt的devcies链表等。

DevHostServiceAddDevice(struct IDevHostService *inst, struct HdfDeviceInfo *deviceInfo)
|-> struct HdfDevice *device = NULL;
|-> struct DevHostService *hostService = CONTAINER_OF(inst, struct DevHostService, super);
|
|-> device = DevHostServiceGetDevice(hostService, deviceInfo->deviceId);
|
|-> devNode = driverLoader->LoadNode(driverLoader, deviceInfo);
|                            |-> HdfDriverLoaderLoadNode()
|                                |-> 
|                                |-> 
|                                |-> driverEntry = loader->GetDriverEntry(deviceInfo);
|                                |                          |-> HdfDriverLoaderGetDriverEntry()
|                                | 
|                                |-> devNode = HdfDeviceNodeNewInstance();
|                                |-> devNode->driverEntry = driverEntry;
|                                |-> devNode->deviceInfo = deviceInfo;
|                                |-> devNode->deviceObject.xx = xx;
|                                | // 绑定HdfDevice与DeviceIoService
|                                | // Device -> service -> Dispatch
|                                |-> driverEntry->Bind(&devNode->deviceObject)
| // 将服务于设备相关联
|-> devNode->hostService = hostService;
| // 挂载DevNode到设备(同一接口设备类)的节点列表(一个设备类中的一个具体设备)
|-> device->super.Attach(&device->super, devNode);

2.4 HdfDevice

2.4.1 HdfDevice 及接口

HdfDevice为Host下的设备在Host域内的表示,内容如下:

struct IHdfDevice 
    struct HdfObject object;
    // 挂载HdfDeviceNode到HdfDevice的node链表
    int (*Attach)(struct IHdfDevice *, struct HdfDeviceNode *);
    void (*Detach)(struct IHdfDevice *, struct HdfDeviceNode *);
;

struct HdfDevice 
    struct IHdfDevice super;
    struct DListHead node;
    struct DListHead devNodes;  // 某接口相同的设备类的具体设备节点,如I2C总线上挂着设备0,设备1
    uint16_t deviceId;          // 接口相同的设备类,例如UART、I2C等。
    uint16_t hostId;            // 应用子设备系统类,例如:display、Input、Network、Sensor、storage等。
;

2.4.2 HdfDevice 构建流程

比较简单,分配对象内存空间,然后初始化接口和其中的链表:

void HdfDeviceConstruct(struct HdfDevice *device)

    device->super.Attach = HdfDeviceAttach;
    DListHeadInit(&device->devNodes);


struct HdfObject *HdfDeviceCreate()

    struct HdfDevice *device =
        (struct HdfDevice *)OsalMemCalloc(sizeof(struct HdfDevice));
    if (device != NULL) 
        HdfDeviceConstruct(device);
    
    return (struct HdfObject *)device;

HdfDevice为Host域内一个设备的表示,一个HdfDevice可以对应多个DeviceNode节点,但是一个DeviceNode节点只对应一个设备驱动。即用户可以将设备驱动程序进行分层,协同完成对设备的支撑。

2.4.3 IHdfDevice 接口 Attach 简介

HdfDeviceAttach()的功能是(1)将设备Node节点挂载到设备的DevNode检点链表上;(2)然后启动节点,即初始化驱动、发布设备服务等。

static int HdfDeviceAttach(struct IHdfDevice *devInst, struct HdfDeviceNode *devNode)

    struct HdfDevice *device = (struct HdfDevice *)devInst;
    struct IDeviceNode *nodeIf = (struct IDeviceNode *)devNode;
    if (device == NULL || nodeIf == NULL || nodeIf->LaunchNode == NULL) 
        HDF_LOGE("failed to attach device, input params invalid");
        return HDF_ERR_INVALID_PARAM;
    
    DListInsertTail(&devNode->entry, &device->devNodes);
    return nodeIf->LaunchNode(devNode, devInst);

2.5 HdfDeviceNode(DeviceNodeExt)

设备节点,对应着一个设备服务节点,与DriverEntry一一对应。

2.5.1 HdfDeviceNode与DeviceNodeExt对象类型定义

现在才是真正与驱动一一对应的设备节点,代表着一个服务设备。

struct IDeviceNode 
    struct HdfObject object;
    // 发布设备服务
    int (*PublishService)(struct HdfDeviceNode *, const char *);
    // 启动设备节点
    int (*LaunchNode)(struct HdfDeviceNode *, struct IHdfDevice *);
;

struct HdfDeviceNode 
    struct IDeviceNode super;
    struct DListHead entry;
    struct PowerStateToken *powerToken;
    struct DevHostService *hostService;
    struct HdfDeviceObject deviceObject;
    struct IHdfDeviceToken *token;
    struct HdfDriverEntry *driverEntry;
    const struct HdfDeviceInfo *deviceInfo;
;

struct DeviceNodeExt 
    struct HdfDeviceNode super;
    struct HdfIoService *ioService;
;

2.5.2 DeviceNodeExt 构建流程

DeviceNodeExt包含HdfDeviceNode,在C++上表现为继承关系,构建过程如下:

DeviceNodeExtCreate()
|-> struct DeviceNodeExt *instance =
|            (struct DeviceNodeExt *)OsalMemCalloc();
|
|-> DeviceNodeExtConstruct()
    |-> HdfDeviceNodeConstruct()
    |    |-> struct IDeviceNode *nodeIf = &devNode->super;
    |    |-> devNode->token = HdfDeviceTokenNewInstance();
    |    |-> nodeIf->LaunchNode = HdfDeviceLaunchNode;
    |    |-> nodeIf->PublishService = HdfDeviceNodePublishPublicService; // 被覆盖
    |
    |-> nodeIf->PublishService = DeviceNodeExtPublishService;

2.5.3 HdfDeviceNode 接口简介

(1)LaunchNode : HdfDeviceLaunchNode()

HdfDeviceLaunchNode()功能为启动设备节点,初始化设备驱动吗,间接地调用PublishService接口发布设备服务。

HdfDeviceLaunchNode(struct HdfDeviceNode *devNode, struct IHdfDevice *devInst)
|-> device = (struct HdfDevice *)devInst;
|-> driverEntry = devNode->driverEntry;
|
|    // (1)初始化设备驱动
|-> driverEntry->Init(&devNode->deviceObject);
|    // (2)发布设备服务,挂载
|-> HdfDeviceNodePublishService()
|    |  // 将设备节点发布到系统设备节点,并添加服务到DevSvcMgr的服务链表
|    |-> // nodeIf->PublishService()
|    |-> HdfDeviceNodePublishLocalService()
|
|    // (3)挂载HDFDevice到DevMgr的设备链表
|-> deviceToken = devNode->token;
|    // 挂载DevNode(通过DeviceToken)到DevHostServiceClnt的device链表上。
|-> DevmgrServiceClntAttachDevice()
    |-> DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
    |-> devMgrSvcIf = inst->devMgrSvcIf;
    | // 将Device挂载DevMgr的设备链表上,以DeviceTokenClnt的形式挂载
    |-> devMgrSvcIf->AttachDevice(devMgrSvcIf, deviceInfo, deviceToken);
(2)PublishService : HdfDeviceNodePublishPublicService()

发布设备服务即为发布设备节点(DevNode)头部的HdfObject

DeviceNodeExtPublishService(struct HdfDeviceNode *inst, const char *serviceName)
|-> HdfDeviceNodePublishPublicService() // 发布Public服务
|    |-> DevSvcManagerClntAddService()
|        |-> devSvcMgrClnt = DevSvcManagerClntGetInstance();
|        |-> serviceManager = devSvcMgrClnt->devSvcMgrIf; // SvcMgrClnt即为SvcMgr的代理
|        |   // 添加设备服务到设备服务管理器
|        |-> serviceManager->AddService(serviceManager, svcName, service);
|    
|    // 创建设备节点,返回与之关联的VnodeAdapter的ioService域
|-> devNodeExt->ioService = HdfIoServicePublish()
|-> static struct HdfIoDispatcher dispatcher = 
|->        .Dispatch = DeviceNodeExtDispatch
|-> ;
|-> devNodeExt->ioService->dispatcher = &dispatcher;

2.6 HdfDriverEntry

HdfDriverEntry即设备驱动对象,对应一个设备节点。

struct HdfDriverEntry 
    // Driver version
    int32_t moduleVersion;

    // Driver module name, to match the driver information in .hcs file
    const char *moduleName;

    //to bind DriverIoService to HdfDevService
    int32_t (*Bind)(struct HdfDeviceObject *deviceObject); // 

    // Initializes the driver.
    int32_t (*Init)(struct HdfDeviceObject *deviceObject);

    // Releases driver resources
    void (*Release)(struct HdfDeviceObject *deviceObject);
;

3 总结

至此,本文已经介绍了DevMgrService构建过程中遇到的绝大部分对象类型,其目的是先为读者勾画出每个对象类型的功能,使读者在阅读源码的初始阶段,可以在不深入调入流程的情况下,对DevMgrService的构建流程有个大概的印象,而不是被代码牵引,一层层向下深入,最后被众多的对象所淹没。

以此铺垫,在下一篇文章中,将介绍DevMgrService的构建过程,众多的对象类型,诸如DevHostServiceClnt、DevHostService、HdfDevice、HdfDeviceNode、HdfDriverEntry以及HdfDeviceToken等,将关联成一张负责的关系网。

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com/#bkwz

以上是关于OpenHarmony南向之旅之HDF传感器驱动开发的主要内容,如果未能解决你的问题,请参考以下文章

OpenHarmony驱动框架HDF中设备管理服务构建过程详解

HDF驱动框架探路:openharmony最新源码,打通应用态到内核态

[FFH]openharmony南向研究 - 南北向接口Napi实现

#星光计划2.0# linux内核增加HDF驱动子系统

OpenHarmony中的HDF单链表及其迭代器

鸿蒙-南向轻内核开发实战系列基于小熊派鸿蒙季开发板环境搭建