一、外接环境光传感器驱动程序

1.目标

基于HDF驱动框架的Sensor驱动模型开发RK3568-外接环境光传感器驱动程序(包括环境光传感器抽象驱动、环境光传感器差异化驱动),从而可以通过Sensor HDI能力接口为上层应用提供服务。

2.开发环境

   硬件平台:润和DAYU200开发板

   软件版本:OpenHarmony v3.1 Release

   外接传感器:ROHM BH1750FVI

3.准备工作

   根据扩展IO原理图,使用杜邦线将BH1750FVI环境光传感器连接上开发板。

   扩展IO原理图如下:

   连接示意图:

   

4.Sensor驱动模型介绍

Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供稳定的Sensor基础能力接口,包括Sensor列表查询、Sensor启停、Sensor订阅及取消订阅,Sensor参数配置等功能,具体如下:

接口名
功能描述
int32_t GetAllSensors(struct SensorInformation
**sensorInfo, int32_t
*count)
 
获取系统中注册的所有传感器信息,一组完整传感器信息包括传感器名字、设备厂商、固件版本号、硬件版本号、传感器类型编号、传感器标识、最大量程、精度、功耗。
int32_t Enable(int32_t
sensorId)
使能指定传感器设备,只有数据订阅者使能传感器后,才能获取订阅的传感器数据。
int32_t Disable(int32_t
sensorId) 
去使能指定传感器设备。
int32_t SetBatch(iint32_t
sensorId, int64_t
samplingInterval, int64_t
reportInterval)
设置指定传感器的数据采样间隔和数据上报间隔
int32_t SetMode(int32_t
sensorId, int32_t mode)
设置指定传感器的工作模式,不同的工作模式,上报数据方式不同。
int32_t SetOption(int32_t
sensorId, uint32_t option)
设置指定传感器量程,精度等可选配置。
int32_t Register(int32_t
groupId,
RecordDataCallback cb)
订阅者根据不同groupId注册传感器数据回调函数,系统会将获
取到的传感器数据上报给订阅者。
int32_t Unregister(int32_t
groupId,
RecordDataCallback cb)
订阅者根据groupId和回调函数注销对应订阅者的传感器数据回
调函数。

以加速度传感器驱动为例,Sensor驱动模型的加载以及运行流程如下:
1. 从device info HCS 的Sensor Host读取Sensor设备管理配置信息。
2. HDF配置框架从HCB数据库解析Sensor设备管理配置信息,并关联对应设备驱动。
3. 加载并初始化Sensor设备管理驱动。
4. Sensor设备管理驱动向HDI发布Sensor基础能力接口。
5. 从device info HCS 的Sensor Host读取加速度传感器驱动配置信息。
6. 加载加速度传感器抽象驱动,调用初始化接口,完成Sensor器件驱动资源分配和数据处理队列创建。
7. 从accel_xxx_config HCS读取加速度传感器差异化驱动配置和私有化配置信息。
8. 加速度传感器差异化驱动,调用通用配置解析接口,完成器件属性信息解析,器件寄存器解析。
9. 加速度传感器差异化驱动完成器件探测,并分配加速度传感器配置资源,完成加速度传感器差异化接口注册。
10. 加速度传感器探测成功之后,加速度传感器差异化驱动通知加速度传感器抽象驱动,注册加速度传感器设备到Sensor设备管理中。

Sensor驱动模型包括三种驱动:Sensor设备管理驱动、传感器抽象驱动、传感器差异化驱动。

OpenHarmony自带有Sensor设备管理驱动,所以基于Sensor驱动模型开发某一类传感器驱动,需要实现对应的传感器抽象驱动、传感器差异化驱动,以环境光传感器为例,需要实现:环境光传感器抽象驱动、环境光传感器差异化驱动。

5.目录结构

基于HDF驱动框架的Sensor驱动模型进行环境光传感器驱动开发需要实现:环境光传感器抽象驱动、环境光传感器差异化驱动,涉及的源码文件如下:

OpenHarmony
    ├──drivers/framework/model/sensor/driver
    │     │                             ├──als
    │     │                             │   ├──sensor_als_driver.h
    │     │                             │   └──sensor_als_driver.c
    │     │                             │
    │     │                             └──chipset/als
    │     │                                         ├──als_bh1750.h
    │     │                                         └──als_bh1750.c
    │     │
    │     └──adapter/khdf/linux/model/sensor
    │                                     ├──Kconfig
    │                                     └──Makefile
    │
    └──vendor/hihope/rk3568/hdf_config/khdf
                                        ├──device_info
                                        │     └──device_info.hcs
                                        └──sensor
                                            ├──als
                                            │   └──bh1750_config.hcs
                                            └──sensor_config.hcs

6.开发步骤

6.1 驱动源文件编写

6.1.1 环境光传感器抽象驱动源文件

OpenHarmony自带有环境光传感器抽象驱动,以下仅展示使用或修改的部分代码。

sensor_als_driver.h文件

......
struct AlsOpsCall { // 差异化接口对象
    int32_t (*Init)(struct SensorCfgData *data);
    int32_t (*ReadData)(struct SensorCfgData *data);
};

struct AlsDrvData { // Als驱动数据结构体
    struct IDeviceIoService ioService;
    struct HdfDeviceObject *device;
    HdfWorkQueue alsWorkQueue;
    HdfWork alsWork;
    OsalTimer alsTimer;
    bool detectFlag;
    bool enable;
    int64_t interval;
    struct SensorCfgData *alsCfg;
    struct AlsOpsCall ops;
};

int32_t AlsRegisterChipOps(const struct AlsOpsCall *ops); // 注册差异化接口
struct SensorCfgData *AlsCreateCfgData(const struct DeviceResourceNode *node);
// 获取传感器配置信息
void AlsReleaseCfgData(struct SensorCfgData *alsCfg); // 资源释放
......

sensor_als_driver.c文件

  • 定义并注册驱动入口对象HdfDriverEntry
// 抽象驱动入口
struct HdfDriverEntry g_sensorAlsDevEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_SENSOR_ALS",
    .Bind = AlsBindDriver,
    .Init = AlsInitDriver,
    .Release = AlsReleaseDriver,
};

HDF_INIT(g_sensorAlsDevEntry);
  • 实现Bind函数、Dispatch函数——AlsBindDriver、DispatchAls
/* Dispatch函数 */
static int32_t DispatchAls(struct HdfDeviceIoClient *client,int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    (void)client;
    (void)cmd;
    (void)data;
    (void)reply;

    return HDF_SUCCESS;
}

/* Bind函数 */
int32_t AlsBindDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

    struct AlsDrvData *drvData = (struct AlsDrvData*)OsalMemCalloc(sizeof(*drvData));
    if (drvData == NULL) {
        HDF_LOGE("%s: Malloc als drv data fail!", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }

    drvData->ioService.Dispatch = DispatchAls;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_alsDrvData = drvData;
    return HDF_SUCCESS;
}
  • 实现Init函数——AlsInitDriver、InitAlsData、AlsDataWorkEntry
/* Init函数 */
int32_t AlsInitDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct AlsDrvData *drvData = (struct AlsDrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    if (InitAlsData(drvData) != HDF_SUCCESS) {
        HDF_LOGE("%s: Init als config failed", __func__);
        return HDF_FAILURE;
    }

    drvData->alsCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->alsCfg));
    if (drvData->alsCfg == NULL) {
        HDF_LOGE("%s: Malloc als config data failed", __func__);
        return HDF_FAILURE;
    }

    drvData->alsCfg->regCfgGroup = &g_regCfgGroup[0];
    drvData->alsCfg->extendedRegCfgGroup = &g_extendAlsRegCfgGroup[0];

    return HDF_SUCCESS;
}

static int32_t InitAlsData(struct AlsDrvData *drvData)
{
    if (HdfWorkQueueInit(&drvData->alsWorkQueue, HDF_ALS_WORK_QUEUE_NAME) != HDF_SUCCESS) {        
        HDF_LOGE("%s: Als init work queue failed", __func__);
        return HDF_FAILURE;
    }

    if (HdfWorkInit(&drvData->alsWork, AlsDataWorkEntry, drvData) != HDF_SUCCESS) {
        HDF_LOGE("%s: Als create thread failed", __func__);
        return HDF_FAILURE;
    }

    drvData->interval = SENSOR_TIMER_MIN_TIME;
    drvData->enable = false;
    drvData->detectFlag = false;

    return HDF_SUCCESS;
}

static void AlsDataWorkEntry(void *arg)
{
    struct AlsDrvData *drvData = NULL;

    drvData = (struct AlsDrvData *)arg;
    CHECK_NULL_PTR_RETURN(drvData);

    if (drvData->ops.ReadData == NULL) {
        HDF_LOGI("%s: Als ReadData function NULl", __func__);
        return;
    }
    if (drvData->ops.ReadData(drvData->alsCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: Als read data failed", __func__);
    }
}
  • 实现Release函数——AlsReleaseDriver、AlsReleaseCfgData
/* Release函数 */
void AlsReleaseDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN(device);
    struct AlsDrvData *drvData = (struct AlsDrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);

    if (drvData->detectFlag && drvData->alsCfg != NULL) {
        AlsReleaseCfgData(drvData->alsCfg);
    }

    OsalMemFree(drvData->alsCfg);
    drvData->alsCfg = NULL;

    HdfWorkDestroy(&drvData->alsWork);
    HdfWorkQueueDestroy(&drvData->alsWorkQueue);
    OsalMemFree(drvData);
}

void AlsReleaseCfgData(struct SensorCfgData *alsCfg)
{
    CHECK_NULL_PTR_RETURN(alsCfg);
    (void)DeleteSensorDevice(&alsCfg->sensorInfo);
    ReleaseSensorAllRegConfig(alsCfg);
    ReleaseExtendedAlsRegConfig(alsCfg);
    (void)ReleaseSensorBusHandle(&alsCfg->busCfg);

    alsCfg->root = NULL;
    (void)memset_s(&alsCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0,sizeof(struct SensorBasicInfo));
    (void)memset_s(&alsCfg->busCfg, sizeof(struct SensorBusCfg), 0,sizeof(struct SensorBusCfg));
    (void)memset_s(&alsCfg->sensorAttr, sizeof(struct SensorAttr), 0,sizeof(struct SensorAttr));
}
  • 实现Als传感器配置信息获取函数——AlsCreateCfgData、InitAlsAfterDetected、InitAlsOps
/* 提供给差异化驱动的初始化接口,完成器件基本配置信息解析(光信息,总线配置,器件探测寄存器配置),器件探测,器件寄存器解析 */
struct SensorCfgData *AlsCreateCfgData(const struct DeviceResourceNode *node)
{
    struct AlsDrvData *drvData = AlsGetDrvData();

    if (drvData == NULL || node == NULL) {
        HDF_LOGE("%s: Als node pointer NULL", __func__);
        return NULL;
    }

    if (drvData->detectFlag) {
        HDF_LOGE("%s: Als sensor have detected", __func__);
        return NULL;
    }

    if (drvData->alsCfg == NULL) {
        HDF_LOGE("%s: Als alsCfg pointer NULL", __func__);
        return NULL;
    }

// 设备基本配置信息解析
    if (GetSensorBaseConfigData(node, drvData->alsCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: Get sensor base config failed", __func__);
        goto BASE_CONFIG_EXIT;
    }

/* 如果探测不到器件在位,返回进行下个器件探测 */
// if (DetectSensorDevice(drvData->alsCfg) != HDF_SUCCESS) {
//     HDF_LOGI("%s: Als sensor detect device no exist", __func__);
//     drvData->detectFlag = false;
//     goto BASE_CONFIG_EXIT;
// }

drvData->detectFlag = true;

// 器件探测成功后的初始化操作
    if (InitAlsAfterDetected(drvData->alsCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: Als sensor detect device no exist", __func__);
        goto INIT_EXIT;
    }

    return drvData->alsCfg;

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

static int32_t InitAlsAfterDetected(struct SensorCfgData *config)
{
    struct SensorDeviceInfo deviceInfo;
    CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);

    /* 初始化接口函数 */
    if (InitAlsOps(config, &deviceInfo) != HDF_SUCCESS) {
        HDF_LOGE("%s: Init als ops failed", __func__);
        return HDF_FAILURE;
    }
    /* 注册设备到传感器管理模块 */
    if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) {
        HDF_LOGE("%s: Add als device failed", __func__);
        return HDF_FAILURE;
    }
    /* 器件寄存器解析 */
    // if (ParseSensorRegConfig(config) != HDF_SUCCESS) {
    //     HDF_LOGE("%s: Parse sensor register failed", __func__);
    //     goto SENSOR_REG_CONFIG_EXIT;
    // }
    // if (ParseExtendedAlsRegConfig(config) != HDF_SUCCESS) {
    //     HDF_LOGE("%s: Parse sensor extendedRegCfgGroup register failed",__func__);
    //     goto EXTENDED_ALS_REG_CONFIG_EXIT;
    // }

    return HDF_SUCCESS;

// EXTENDED_ALS_REG_CONFIG_EXIT:
//     ReleaseSensorAllRegConfig(config);
// SENSOR_REG_CONFIG_EXIT:
//     (void)DeleteSensorDevice(&config->sensorInfo);

    // return HDF_FAILURE;
}

/* 注册传感器驱动归一化的接口函数 */
static int32_t InitAlsOps(struct SensorCfgData *config, struct SensorDeviceInfo *deviceInfo)
{
    CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);

    deviceInfo->ops.Enable = SetAlsEnable;
    deviceInfo->ops.Disable = SetAlsDisable;
    deviceInfo->ops.SetBatch = SetAlsBatch;
    deviceInfo->ops.SetMode = SetAlsMode;
    deviceInfo->ops.SetOption = SetAlsOption;

    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;
}
  • 接口函数实现—SetAlsEnable、SetAlsDisable、SetAlsBatch、SetAlsMode、SetAlsOption

       SetAlsEnable、SetAlsDisable

/* 下发使能寄存器组的配置 */
static int32_t SetAlsEnable(void)
{
    int32_t ret;
    struct AlsDrvData *drvData = AlsGetDrvData();

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

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

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

    // 创建定时器
    ret = OsalTimerCreate(&drvData->alsTimer, SENSOR_TIMER_MIN_TIME,
    AlsTimerEntry, (uintptr_t)drvData);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Als create timer failed[%d]", __func__, ret);
        return ret;
    }

    // 激活定时器周期循环
    ret = OsalTimerStartLoop(&drvData->alsTimer);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Als start timer failed[%d]", __func__, ret);
        return ret;
    }
    drvData->enable = true;

    return HDF_SUCCESS;
}

// 定时器执行的函数
static void AlsTimerEntry(uintptr_t arg)
{
    int64_t interval;
    int32_t ret;
    struct AlsDrvData *drvData = (struct AlsDrvData *)arg;
    CHECK_NULL_PTR_RETURN(drvData);

    if (!HdfAddWork(&drvData->alsWorkQueue, &drvData->alsWork)) {
        HDF_LOGE("%s: Als add work queue failed", __func__);
    }

    interval = OsalDivS64(drvData->interval, (SENSOR_CONVERT_UNIT *SENSOR_CONVERT_UNIT));
    interval = (interval < SENSOR_TIMER_MIN_TIME) ? SENSOR_TIMER_MIN_TIME : interval;
    ret = OsalTimerSetTimeout(&drvData->alsTimer, interval);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Als modify time failed", __func__);
    }
}

/* 下发去使能寄存器组的配置 */
static int32_t SetAlsDisable(void)
{
    int32_t ret;
    struct AlsDrvData *drvData = AlsGetDrvData();

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

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

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

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

    return HDF_SUCCESS;
}

       SetAlsBatch、SetAlsMode、SetAlsOption

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

    struct AlsDrvData *drvData = NULL;

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

    drvData->interval = samplingInterval;

    return HDF_SUCCESS;
}

/* 设置传感器工作模式 */
static int32_t SetAlsMode(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 SetAlsOption(uint32_t option)
{
    (void)option;
    return HDF_SUCCESS;
}
  • 注册差异化接口函数——AlsRegisterChipOps
/*在探测到器件在位后,需要调用AlsRegisterChipOps注册差异化适配函数*/
int32_t AlsRegisterChipOps(const struct AlsOpsCall *ops)
{
    struct AlsDrvData *drvData = AlsGetDrvData();

    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;
}

6.1.2 环境光传感器差异化驱动

在OpenHarmony/drivers/framework/model/sensor/driver/chipset/als下新建als_bh1750.h、als_bh1750.c文件;

als_bh1750.h文件:

#ifndef ALS_BH1750_H
#define ALS_BH1750_H

#include "sensor_als_driver.h"
#include "sensor_config_parser.h"

int32_t ReadBh1750Data(struct SensorCfgData *data); // 差异化接口ReadData函数

struct Bh1750DrvData { // Bh1750驱动数据结构体
    struct IDeviceIoService ioService;
    struct HdfDeviceObject *device;
    struct SensorCfgData *sensorCfg;
};

#endif

als_bh1750.c文件:

  • 定义并注册驱动入口对象HdfDriverEntry
struct HdfDriverEntry g_alsBh1750DevEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_SENSOR_ALS_BH1750",
    .Bind = Bh1750BindDriver,
    .Init = Bh1750InitDriver,
    .Release = Bh1750ReleaseDriver,
};

HDF_INIT(g_alsBh1750DevEntry);
  • 实现Bind函数、Dispatch函数、Release函数
/* Dispatch函数 */
static int32_t DispatchBH1750(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    (void)client;
    (void)cmd;
    (void)data;
    (void)reply;
    return HDF_SUCCESS;
}

/* Bind函数 */
int32_t Bh1750BindDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

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

    drvData->ioService.Dispatch = DispatchBH1750;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_bh1750DrvData = drvData;

    return HDF_SUCCESS;
}

/* Release函数 */
void Bh1750ReleaseDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN(device);
    struct Bh1750DrvData *drvData = (struct Bh1750DrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);

    if (drvData->sensorCfg != NULL) {
        AlsReleaseCfgData(drvData->sensorCfg);
        drvData->sensorCfg = NULL;
    }
    OsalMemFree(drvData);
}
  • 实现Init函数
/* Init函数 */
int32_t Bh1750InitDriver(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct AlsOpsCall ops; // 差异化接口对象

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

    drvData->sensorCfg = AlsCreateCfgData(device->property); // 获取传感器配置信息,初始化接口
    if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
        HDF_LOGD("%s: Creating alscfg failed because detection failed",__func__);
        return HDF_ERR_NOT_SUPPORT;
    }

    ops.Init = NULL;
    ops.ReadData = ReadBh1750Data; // 绑定差异化接口ReadData函数
    ret = AlsRegisterChipOps(&ops); // 注册差异化适配函数
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Register BH1750 als failed", __func__);
        return HDF_FAILURE;
    }

    ret = InitBh1750(drvData->sensorCfg); // 初始化通信
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Init BH1750 als failed", __func__);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t InitBh1750(struct SensorCfgData *data)
{
    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);

    uint8_t wbuff[2] = { 0x01, 0x10 };
    struct I2cMsg msgs[2]; /* 自定义传输的消息结构体数组 */

    msgs[0].buf = &wbuff[0]; /* 写入的数据 */
    msgs[0].len = 1; /* 写入数据长度 */
    msgs[0].addr = 0x23; /* 写入设备地址 */
    msgs[0].flags = 0; /* 传输标记为0,默认为写 */
    msgs[1].buf = &wbuff[1];
    msgs[1].len = 1;
    msgs[1].addr = 0x23;
    msgs[1].flags = 0;

    i2cHandle = I2cOpen(3); // 开启I2C控制器
    if (i2cHandle == NULL) {
        HDF_LOGE("I2cOpen: failed\n");
        return HDF_FAILURE;
    }

    int32_t ret = -1;
    ret = I2cTransfer(i2cHandle, &msgs[0], 2); // 写入指令至传感器
    if (ret != 2) {
        HDF_LOGE("I2cTransfer: write failed, ret %d\n", ret);
        HDF_LOGE("I2cTransfer: write failed, busNum %d\n", 3);
        HDF_LOGE("I2cTransfer: write failed, addr %x\n", msgs[0].addr);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}
  • 实现差异化接口ReadData函数
int32_t ReadBh1750Data(struct SensorCfgData *data)
{
    int32_t ret;

    uint8_t rbuff[2] = { 0 };
    struct I2cMsg msgs[1]; /* 自定义传输的消息结构体数组 */

    msgs[0].buf = rbuff; /* 要读取的数据 */
    msgs[0].len = 2; /* 读取数据长度为2 */
    msgs[0].addr = 0x23; /* 读取设备地址 */
    msgs[0].flags = I2C_FLAG_READ ; /* 标记为读 */

    // 阻塞180ms,等待传感器获取光照强度数据
    OsalMSleep(180);

    // 读取传感器光照强度数据
    ret = I2cTransfer(i2cHandle, &msgs[0], 1);
    if (ret != 1) {
        HDF_LOGE("I2cTransfer: read failed, ret %d\n", ret);
        HDF_LOGE("I2cTransfer: read failed, busNum %d\n", 3);
        HDF_LOGE("I2cTransfer: read failed, addr %x\n", msgs[2].addr);
        return HDF_FAILURE;
    }

    // 数据转换
    uint16_t temp = (rbuff[0]<<8) | rbuff[1];
    static uint32_t alsData = 0;
    alsData = temp / 1.2;

    struct SensorReportEvent event; // 创建报告事件对象
    (void)memset_s(&event, sizeof(event), 0, sizeof(event));
    event.sensorId = SENSOR_TAG_AMBIENT_LIGHT;
    event.option = alsData;
    event.mode = SENSOR_WORK_MODE_REALTIME;
    event.timestamp = 180 * SENSOR_CONVERT_UNIT * SENSOR_CONVERT_UNIT;
    event.dataLen = sizeof(alsData);
    event.data = (uint8_t *)&alsData;

    ret = ReportSensorEvent(&event); // 通过event上报数据
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: BH1750 report data failed", __func__);
    }
    return ret;
}

6.2 驱动编译文件编写

基于HDF驱动框架的Sensor驱动模型进行驱动开发,所有的编译文件都写在以下两个文件中:

OpenHarmony/drivers/adapter/khdf/linux/model/sensor
                                                ├──Kconfig
                                                └──Makefile

在OpenHarmony/drivers/adapter/khdf/linux/model/sensor/Kconfig中添加以下模块控制宏,默认为开启:

......
config DRIVERS_HDF_SENSOR_ALS
    bool "Enable HDF als sensor driver"
    default y
    depends on DRIVERS_HDF_SENSOR
    help
        Answer Y to enable HDF als sensor driver.

config DRIVERS_HDF_SENSOR_ALS_BH1750
    bool "Enable HDF als bh1745 sensor driver"
    default y
    depends on DRIVERS_HDF_SENSOR_ALS
    help
        Answer Y to enable HDF als bh1745 sensor driver.
......

在OpenHarmony/drivers/adapter/khdf/linux/model/sensor/Makefile下添加以下语句:

......
obj-$(CONFIG_DRIVERS_HDF_SENSOR_ALS) +=
$(SENSOR_ROOT_DIR)/als/sensor_als_driver.o
obj-$(CONFIG_DRIVERS_HDF_SENSOR_ALS_BH1750) +=
$(SENSOR_ROOT_DIR)/chipset/als/als_bh1750.o
......

6.3 驱动配置文件编写

相关配置文件的路径如下所示:

OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf
                                            ├──device_info
                                            │    └──device_info.hcs
                                            └──sensor
                                                 ├──als
                                                 │ └──bh1750_config.hcs
                                                 └──sensor_config.hcs

6.3.1 驱动设备描述

在OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs文件中配置驱动设备描述信息:

root {
    device_info {
        ......
        sensor :: host {
            ......
            device_sensor_als :: device {
                device0 :: deviceNode {
                    policy = 1;
                    priority = 110;
                    preload = 0;
                    permission = 0664;
                    moduleName = "HDF_SENSOR_ALS";
                    serviceName = "sensor_als";
                    deviceMatchAttr = "hdf_sensor_als_driver";
                }
            }
            device_sensor_bh1750 :: device {
                device0 :: deviceNode {
                    policy = 1;
                    priority = 120;
                    preload = 0;
                    permission = 0664;
                    moduleName = "HDF_SENSOR_ALS_BH1750";
                    serviceName = "hdf_als_bh1750";
                    deviceMatchAttr = "hdf_sensor_als_bh1750_driver";
                }
            }
            ......
        }
        ......
    }
}

6.3.2 驱动私有配置信息

在OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf/sensor文件夹下新建立als文件夹;

在als文件夹下新建立bh1750_config.hcs文件;

在bh1750_config.hcs文件中配置差异化驱动私有信息:

#include "../sensor_common.hcs"
root {
    als_bh1750_chip_config : sensorConfig {
        match_attr = "hdf_sensor_als_bh1750_driver";
        sensorInfo :: sensorDeviceInfo {
            sensorName = "als";
            vendorName = "rohm_bh1750"; // max string length is 16 bytes
            sensorTypeId = 5; // enum SensorTypeTag
            sensorId = 5; // user define sensor id
            power = 260;
        }
        sensorBusConfig :: sensorBusInfo {
            busType = 0; // 0:i2c 1:spi
            busNum = 3;
            busAddr = 0x23;
        }
        sensorIdAttr :: sensorIdInfo {
            chipName = "bh1750";
            chipIdRegister = 0x00;
            chipIdValue = 0x00;
        }
        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_check4-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 = [

            ];
            enableSeqConfig = [

            ];
            disableSeqConfig = [

            ];
        }
    }
}

在OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf/sensor/sensor_config.hcs文件中添加以下语句:

#include "als/bh1750_config.hcs"

7.编译

进入vendor/hihope/rk3568/hdf_config/khdf/hdf_test目录,删除编译hdf.hcs所产生的相关文件:

cd vendor/hihope/rk3568/hdf_config/khdf/hdf_test
rm .*.cmd .*.d *.a *.o *.hcb *.order

具体删除文件如下:

.built-in.a.cmd
.hcs_macro_cases.o.d
.hdf_hcs_hex.o.d
.modules.order.cmd
built-in.a
hcs_macro_cases.o
hdf_hcs.hcb
hdf_hcs_hex.o
modules.order

然后进入out/kernel/src_tmp/linux-5.10目录,执行命令重新编译内核:

cd out/kernel/src_tmp/linux-5.10
./make-ohos.sh TB-RK3568X0 enable_ramdisk

最后回到源码根目录,执行如下命令进行版本编译:

cd -
./build.sh --product-name rk3568 --ccache

8.补充

BH1750FVI是一款用于I2C总线接口的数字环境光传感器,获取的光照强度数据长度为2字节,常用指令如下:


BH1750FV I2C器件地址如下:

  • ADDR引脚接高电平:0X5C
  • ADDR引脚接低电平:0X23

二、外接环境光传感器应用程序

1.目标

   开发实现一个环境光传感器应用程序,通过调用Sensor HDI能力接口来获取光照强度数据。

2.开发环境

  硬件平台:润和DAYU200开发板

  软件版本:OpenHarmony v3.1 Release

3.目录结构

OpenHarmony
    ├──applications/sample/als/src
    │                       │   └──als.c
    │                       │
    │                       ├──BUILD.gn
    │                       └──bundle.json
    │
    ├──build
    │     └──subsystem_config.json
    │
    └──productdefine/common/products
                               └──rk3568.json

4.开发步骤

4.1 应用程序源文件编写

在OpenHarmony/applications/sample/下新建文件夹目录als/src;

在als/src/下新建als.c文件;

编写als.c文件,通过调用Sensor HDI能力接口来获取光照强度数据。

#include <stdio.h>
#include "stdlib.h"
#include "hdf_base.h"
#include "hdf_io_service_if.h"
#include "sensor_if.h"
#include "sensor_type.h"
#include "osal_time.h"

#define ALS_SERVICE_NAME "als_service"

static const struct SensorInterface *g_sensorDev = NULL; // 保持获取的传感器接口实例地址

/* 订阅者注册数据上报函数 */
static int SensorTestDataCallback(const struct SensorEvents *event)
{
    if (event == NULL) {
        return -1;
    }
    printf("ALS Data: [%d lx] \n\r", event->option);
    return 0;
}

int main(int argc, char* argv[])
{
    int ret = HDF_SUCCESS;

    g_sensorDev = NewSensorInterfaceInstance(); // 初始化传感器接口实例
    if (g_sensorDev == NULL) {
        printf("sensorHdi get Module instace failed\n\r");
    }

    int32_t count = 0;
    struct SensorInformation *sensorInfo = NULL;
    ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); // 获取传感器信息
    if(ret == HDF_FAILURE){
        printf("GetAllSensors failed\n\r");
    }
    // for (int i = 0; i < count; i++) {
    //     printf("get sensoriId[%d], info name[%s]\n\r",sensorInfo[i].sensorId, sensorInfo[i].sensorName);
    // }

    ret = g_sensorDev->Register(0, SensorTestDataCallback); // 注册数据上报回调函数
    if(ret == HDF_FAILURE){
        printf("Als Register failed\n\r");
    }

    int32_t sensorInterval = 1000000000; // 数据采样率单位纳秒
    ret = g_sensorDev->SetBatch(5, sensorInterval, 1); // 设置数据采样间隔与上报间隔
    if(ret == HDF_FAILURE){
        printf("Als SetBatch failed\n\r");
    }

    ret = g_sensorDev->Enable(5); // 使能指定传感器设备
    if(ret == HDF_FAILURE){
        printf("Als Enable failed\n\r");
    }

    OsalSleep(10); /* 10s内,观察输出数据 */

    ret = g_sensorDev->Disable(5); // 去使能指定传感器设备
    if(ret == HDF_FAILURE){
        printf("Als Disable failed\n\r");
    }

    ret = g_sensorDev->Unregister(0, SensorTestDataCallback); // 注销回调函数
    if(ret == HDF_FAILURE){
        printf("Als Unregister failed\n\r");
    }

    return ret;
}

4.2 编译组织文件编写

在OpenHarmony/applications/sample/als/下新建BUILD.gn文件,内容如下:

HDF_FRAMEWORKS = "//drivers/framework"

# compile 'als' for ohos_standard(linux)
import("//build/ohos.gni")
import("//drivers/adapter/uhdf2/uhdf.gni")

print("als:: compile 'als' for ohos_standard(linux)")
ohos_executable("als") {
    defines = [ "__USER__" ]

    sources = [
        "src/als.c"
    ]

    include_dirs = [
        "$HDF_FRAMEWORKS/include",
        "$HDF_FRAMEWORKS/include/core",
        "$HDF_FRAMEWORKS/include/osal",
        "$HDF_FRAMEWORKS/include/platform",
        "$HDF_FRAMEWORKS/include/utils",
        "//third_party/bounds_checking_function/include",
        "//drivers/adapter/uhdf2/ipc/include",
        "//drivers/adapter/uhdf2/osal/include",
        "//base/hiviewdfx/hilog/interfaces/native/innerkits/include",
        "//drivers/peripheral/sensor/interfaces/include",
    ]

    deps = [
        "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog",                  
        "//drivers/adapter/uhdf2/utils:libhdf_utils",
        "//drivers/peripheral/sensor/hal:hdi_sensor",
    ]

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

    subsystem_name = "als"
    part_name = "als"
}

在OpenHarmony/applications/sample/als/下新建bundle.json文件,内容如下:

{
    "name": "@ohos/als",
    "description": "als.",
    "version": "3.1",
    "license": "Apache License 2.0",
    "publishAs": "code-segment",
    "segment": {
        "destPath": "applications/sample/als"
    },
    "dirs": {},
    "scripts": {},
    "component": {
        "name": "als",
        "subsystem": "als",
        "syscap": [],
        "features": [],
        "adapted_system_type": [ "mini", "small", "standard" ],
        "rom": "10KB",
        "ram": "10KB",
        "deps": {
            "components": [],
            "third_party": []
        },
        "build": {
            "sub_component": [
                "//applications/sample/als:als"
            ],
            "inner_kits": [],
            "test": []
        }
    }
}

4.3 相关配置文件修改

在OpenHarmony/build/subsystem_config.json中添加新建的子系统的配置:

"als": {
    "path": "applications/sample/als",
    "name": "als"
},

在OpenHarmony/productdefine/common/products/rk3568.json中添加对应的部件:

"als:als":{},

5.编译验证

进入源码根目录,执行如下命令进行版本编译:

./build.sh --product-name rk3568 --ccache

编译完成后,通过工具RKDevTool将镜像烧录到单板;

烧录完成后,通过串口调试执行als程序,示例如下:

# als
ALS Data: [225 lx]
ALS Data: [226 lx]
ALS Data: [222 lx]
ALS Data: [225 lx]
ALS Data: [226 lx]
ALS Data: [226 lx]
ALS Data: [65 lx]
ALS Data: [75 lx]
ALS Data: [60 lx]
ALS Data: [18 lx]

 

Logo

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

更多推荐