当前位置: 首页 > news >正文

OpenHarmony外设驱动使用 (十),Sensor

OpenHarmony外设驱动使用 (十)


Sensor

概述

功能简介

Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供稳定的Sensor基础能力接口,包括Sensor列表查询、Sensor启停、Sensor订阅及取消订阅,Sensor参数配置等功能。Sensor设备驱动的开发是基于HDF驱动框架基础上,结合操作系统适配层(OSAL)和平台驱动接口(比如I2C/SPI/UART总线等平台资源)能力,屏蔽不同操作系统和平台总线资源差异,实现Sensor驱动“一次开发,多系统部署”的目标。Sensor驱动模型如图1所示。

图 1 Sensor驱动模型图

Sensor驱动模型图

基本概念

目前根据sensorId将Sensor分为医学类Sensor、传统类Sensor两种。

  • 医学类Sensor:已订阅的sensorId枚举值在128-160范围的为医学类Sensor。

  • 传统类Sensor:已订阅的sensorId枚举值不在128-160范围的为传统类Sensor。

运作机制

通过介绍Sensor驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示:

图 2 Sensor驱动运行图

Sensor驱动运行图

Sensor驱动模型以标准系统RK3568产品中的加速度传感器驱动为例,介绍整个驱动加载及运行流程:

  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驱动模型对外开放的API接口能力如下:

  • 提供Sensor HDI(Hardware Device Interface)能力接口,简化服务开发。
  • 提供Sensor驱动模型能力接口:
    • 依赖HDF驱动框架实现Sensor器件驱动的加载、器件探测、注册和去注册等能力。
    • 提供同一类型Sensor器件驱动归一接口、寄存器配置解析操作接口、总线访问抽象接口和平台抽象接口。
  • 提供开发者实现的能力接口:依赖HDF驱动框架的HCS(HDF Configuration Source)配置管理,根据同类型Sensor差异化配置,实现Sensor器件参数序列化配置和器件部分操作接口,简化Sensor器件驱动开发。

Sensor驱动模型对外开放的API接口能力的具体实现请参考:

表 1 Sensor驱动模型对外API接口功能介绍

注:以下接口列举的为C接口,接口声明见文件/drivers/peripheral/sensor/interfaces/include。

接口名功能描述
int32_t GetAllSensors(struct SensorInformation **sensorInfo, int32_t *count)获取系统中注册的所有传感器信息,一组完整传感器信息包括传感器名字、设备厂商、固件版本号、硬件版本号、传感器类型编号、传感器标识、最大量程、精度、功耗。
int32_t Enable(int32_t sensorId)使能指定传感器设备,只有数据订阅者使能传感器后,才能获取订阅的传感器数据。
int32_t Disable(int32_t sensorId)去使能指定传感器设备。
int32_t SetBatch(int32_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驱动模型对驱动开发者开放的功能接口,驱动开发者无需实现,直接使用,请参考:

表2 Sensor驱动模型对驱动开发者开放的功能接口列表

接口名功能描述
int32_t AddSensorDevice(const struct SensorDeviceInfo *deviceInfo)添加当前类型的传感器设备到传感器设备管理。
int32_t DeleteSensorDevice(const struct SensorBasicInfo *sensorBaseInfo)删除传感器设备管理里指定的传感器设备。
int32_t ReportSensorEvent(const struct SensorReportEvent *events)上报指定类型传感器的数据到用户侧。
int32_t ReadSensor(struct SensorBusCfg *busCfg, uint16_t regAddr, uint8_t *data, uint16_t dataLen)按照配置的总线方式,读取传感器寄存器配置数据。
int32_t WriteSensor(struct SensorBusCfg *busCfg, uint8_t *writeData, uint16_t len)按照配置的总线方式,将传感器配置数据写入寄存器。
int32_t SetSensorRegCfgArray(struct SensorBusCfg *busCfg, const struct SensorRegCfgGroupNode *group);根据传感器总线类型信息,下发寄存器分组配置。
int32_t GetSensorBaseConfigData(const struct DeviceResourceNode *node, struct SensorCfgData *config)根据传感器设备HCS资源配置,获取传感器信息,总线配置信息,属性配置等基本配置信息,并初始化对应的基本配置数据结构体。
int32_t ParseSensorRegConfig(struct SensorCfgData *config)根据传感器设备HCS资源配置,解析寄存器分组信息,并初始化配置数据结构体。
void ReleaseSensorAllRegConfig(struct SensorCfgData *config)释放传感器配置数据结构体里分配的资源。
int32_t GetSensorBusHandle(struct SensorBusCfg *busCfg)获取传感器总线句柄信息。
int32_t ReleaseSensorBusHandle(struct SensorBusCfg *busCfg)释放传感器句柄信息。

Sensor驱动模型要求驱动开发者实现的接口功能,请参考:

表 3 Sensor驱动模型要求驱动开发者实现的接口列表

接口名功能描述
int32_t init(void)传感器设备探测成功后,需要对传感器设备初始化配置。
int32_t Enable(void)根据当前传感器设备的HCS配置,下发传感器设备使能操作组的寄存器配置。
int32_t Disable(void)根据当前传感器设备的HCS配置,下发传感器设备去使能操作组的寄存器配置。
int32_t SetBatch(int64_t samplingInterval, int64_t reportInterval)根据数据采样率和数据上报间隔,配置当前传感器设备的数据上报线程处理时间。
int32_t SetMode(int32_t mode)配置当前传感器设备数据上报方式。
int32_t SetOption(uint32_t option)根据可选配置、下发量程和精度等寄存器配置。
void ReadSensorData(void)读取传感器数据。

接口实现参考开发步骤章节。

开发步骤

基于HDF驱动框架,按照驱动Driver Entry程序,以加速度传感器驱动为例,介绍传感器驱动的开发。传感器的驱动开发包括抽象驱动开发和差异化驱动开发两部分。传感器的抽象驱动开发包括同一个传感器id中不同器件的公共接口实现;传感器的差异化驱动开发包括不同器件差异化接口的实现。

  1. 开发加速度传感器抽象驱动。

    • 加速度传感器抽象驱动在Sensor Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。

      具体代码实现如下:

      /* 加速度计传感器设备HCS配置 */
      device_sensor_accel :: device {device0 :: deviceNode {policy = 1;                                  // 驱动服务发布的策略priority = 110;                              // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序preload = 0;                                 // 驱动按需加载字段,0表示加载,2表示不加载permission = 0664;                           // 驱动创建设备节点权限moduleName = "HDF_SENSOR_ACCEL";             // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致serviceName = "sensor_accel";                // 驱动对外发布服务的名称,必须唯一deviceMatchAttr = "hdf_sensor_accel_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等}
      } 
      
    • 加速度传感器抽象驱动代码实现路径为:drivers\hdf_core\framework\model\sensor\driver\accel\sensor_accel_driver.c。

      • 加速度传感器抽象驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:

        struct HdfDriverEntry g_sensorAccelDevEntry = {.moduleVersion = 1,                // 加速度计传感器模块版本号.moduleName = "HDF_SENSOR_ACCEL",  // 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样.Bind = BindAccelDriver,           // 加速度计传感器绑定函数.Init = InitAccelDriver,           // 加速度计传感器初始化函数.Release = ReleaseAccelDriver,     // 加速度计传感器资源释放函数
        };/* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
        HDF_INIT(g_sensorAccelDevEntry);
        
      • 加速度传感器抽象驱动Bind接口实现如下:

        int32_t AccelBindDriver(struct HdfDeviceObject *device)
        {CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);struct AccelDrvData *drvData = (struct AccelDrvData *)OsalMemCalloc(sizeof(*drvData));if (drvData == NULL) {HDF_LOGE("%s: Malloc accel drv data fail!", __func__);return HDF_ERR_MALLOC_FAIL;}drvData->ioService.Dispatch = DispatchAccel;drvData->device = device;device->service = &drvData->ioService;g_accelDrvData = drvData;return HDF_SUCCESS;
        }
        
      • 加速度传感器抽象驱动Init接口实现如下:

        int32_t AccelInitDriver(struct HdfDeviceObject *device)
        {CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);struct AccelDrvData *drvData = (struct AccelDrvData *)device->service;CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);/* 工作队列资源初始化 */if (InitAccelData(drvData) != HDF_SUCCESS) {HDF_LOGE("%s: Init accel config failed", __func__);return HDF_FAILURE;}/* 分配加速度配置信息资源 */drvData->accelCfg = (struct SensorCfgData            *)OsalMemCalloc(sizeof(*drvData->accelCfg));if (drvData->accelCfg == NULL) {HDF_LOGE("%s: Malloc accel config data failed", __func__);return HDF_FAILURE;}/* 注册寄存器分组信息 */drvData->accelCfg->regCfgGroup = &g_regCfgGroup[0];drvData->cb = NULL;HDF_LOGI("%s: Init accel driver success", __func__);return HDF_SUCCESS;
        }
        
      • 加速度抽象传感器驱动Release接口在驱动卸载或者Init执行失败时,会调用此接口释放资源,具体实现如下:

        void AccelReleaseDriver(struct HdfDeviceObject *device)
        {CHECK_NULL_PTR_RETURN(device);struct AccelDrvData *drvData = (struct AccelDrvData *)device->service;CHECK_NULL_PTR_RETURN(drvData);/* 器件在位,释放已分配资源 */if (drvData->detectFlag && drvData->accelCfg != NULL) {AccelReleaseCfgData(drvData->accelCfg);}OsalMemFree(drvData->accelCfg);drvData->accelCfg = NULL;/* 器件在位,销毁工作队列资源 */HdfWorkDestroy(&drvData->accelWork);HdfWorkQueueDestroy(&drvData->accelWorkQueue);OsalMemFree(drvData);
        }
        
      • 加速度传感器抽象驱动内部接口代码实现如下:

        • 提供给差异化驱动的初始化接口,完成加速度传感器器件的基本配置信息解析(加速度传感器信息,加速度传感器总线配置,加速度传感器器件探测寄存器配置),器件探测,器件寄存器解析,具体实现如下:

          static int32_t InitAccelAfterDetected(struct SensorCfgData *config)
          {struct SensorDeviceInfo deviceInfo;CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);/* 初始化加速度计接口函数 */if (InitAccelOps(config, &deviceInfo) != HDF_SUCCESS) {HDF_LOGE("%s: Init accel ops failed", __func__);return HDF_FAILURE;}/* 注册加速度计器件到传感器设备管理模块 */if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) {HDF_LOGE("%s: Add accel device failed", __func__);return HDF_FAILURE;}/* 器件寄存器解析 */if (ParseSensorDirection(config) != HDF_SUCCESS) {HDF_LOGE("%s: Parse accel direction failed", __func__);(void)DeleteSensorDevice(&config->sensorInfo);return HDF_FAILURE;}if (ParseSensorRegConfig(config) != HDF_SUCCESS) {HDF_LOGE("%s: Parse sensor register failed", __func__);(void)DeleteSensorDevice(&config->sensorInfo);ReleaseSensorAllRegConfig(config);ReleaseSensorDirectionConfig(config);return HDF_FAILURE;}return HDF_SUCCESS;
          }struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node)
          {struct AccelDrvData *drvData = AccelGetDrvData();/* 如果器件不在位,返回进行下个器件探测 */if (drvData == NULL || node == NULL) {HDF_LOGE("%s: Accel node pointer NULL", __func__);return NULL;}if (drvData->detectFlag) {HDF_LOGE("%s: Accel sensor have detected", __func__);return NULL;}if (drvData->accelCfg == NULL) {HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__);return NULL;}/* 设备基本配置信息解析 */if (GetSensorBaseConfigData(node, drvData->accelCfg) != HDF_SUCCESS) {HDF_LOGE("%s: Get sensor base config failed", __func__);goto BASE_CONFIG_EXIT;}/* 如果器件不在位(存在器件ID的情况),返回进行下个器件探测 */if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) {HDF_LOGI("%s: Accel sensor detect device no exist", __func__);drvData->detectFlag = false;goto BASE_CONFIG_EXIT;}/* 器件寄存器解析 */drvData->detectFlag = true;if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) {HDF_LOGE("%s: Accel sensor detect device no exist", __func__);goto INIT_EXIT;}return drvData->accelCfg;INIT_EXIT:(void)ReleaseSensorBusHandle(&drvData->accelCfg->busCfg);
          BASE_CONFIG_EXIT:drvData->accelCfg->root = NULL;(void)memset_s(&drvData->accelCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo));(void)memset_s(&drvData->accelCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));(void)memset_s(&drvData->accelCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));return drvData->accelCfg;
          }
          
        • Enable接口的代码实现如下:

          static int32_t SetAccelEnable(void)
          {int32_t ret;struct AccelDrvData *drvData = AccelGetDrvData();CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM);if (drvData->enable) {HDF_LOGE("%s: Accel sensor is enabled", __func__);return HDF_SUCCESS;}/* 设置寄存器 */ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Accel sensor enable config failed", __func__);return ret;}/* 创建定时器 */ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret);return ret;}/* 开启定时器进行数据上报 */ret = OsalTimerStartLoop(&drvData->accelTimer);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret);return ret;}drvData->enable = true;return HDF_SUCCESS;
          }
          
        • Disable接口的代码实现如下:

          static int32_t SetAccelDisable(void)
          {int32_t ret;struct AccelDrvData *drvData = AccelGetDrvData();CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM);if (!drvData->enable) {HDF_LOGE("%s: Accel sensor had disable", __func__);return HDF_SUCCESS;}/* 设置寄存器 */ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Accel sensor disable config failed", __func__);return ret;}/* 删除定时器 */ret = OsalTimerDelete(&drvData->accelTimer);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Accel delete timer failed", __func__);return ret;}drvData->enable = false;return HDF_SUCCESS;
          }
          
        • SetBatch接口的代码实现如下:

          static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval)
          {(void)interval;struct AccelDrvData *drvData = NULL;drvData = AccelGetDrvData();CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);/* 给定时器设置采样率 */drvData->interval = samplingInterval;return HDF_SUCCESS;
          }
          
        • SetMode接口的代码实现如下:

          static int32_t SetAccelMode(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;
          }
          
        • SetOption接口的代码实现如下:

          static int32_t SetAccelOption(uint32_t option)
          {(void)option;return HDF_SUCCESS;
          }
          
  2. 开发加速度传感器差异化驱动。

    • 加速度传感器差异化驱动在Sensor Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。

      具体代码实现如下:

      device_sensor_mxc6655xa :: device {device0 :: deviceNode {policy = 1;		// policy字段是驱动服务发布的策略priority = 120; // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 preload = 0;    // 驱动按需加载字段,0表示加载,2表示不加载permission = 0664; // 驱动创建设备节点权限moduleName = "HDF_SENSOR_ACCEL_MXC6655XA"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致serviceName = "hdf_accel_mxc6655xa"; // 加速度mxc6655xa对外发布服务的名称,必须唯一deviceMatchAttr = "hdf_sensor_accel_mxc6655xa_driver"; // 加速度差异化驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等}
      }
      
    • 加速度传感器差异化驱动私有HCS配置:

      • 代码实现路径:vendor\hihope\rk3568\hdf_config\khdf\sensor\accel\mxc6655xa_config.hcs。

      • 具体代码实现如下:

        #include "../sensor_common.hcs"
        root {accel_mxc6655xa_chip_config : sensorConfig {match_attr = "hdf_sensor_accel_mxc6655xa_driver";sensorInfo :: sensorDeviceInfo {sensorName = "accelerometer";vendorName = "memsi_mxc6655xa"; // max string length is 16 bytessensorTypeId = 1; // enum SensorTypeTagsensorId = 1; // user define sensor idpower = 230;minDelay = 5000000; // nanosecondmaxDelay = 200000000; // nanosecond}sensorBusConfig :: sensorBusInfo {busType = 0; // 0:i2c 1:spibusNum = 5;busAddr = 0x15;regWidth = 1; // 1byte}sensorIdAttr :: sensorIdInfo {chipName = "mxc6655xa";chipIdRegister = 0x0f;chipIdValue = 0x05; // 根据器件ID寄存器,读取的值,或查看相关芯片datasheet手册确认该值}sensorDirection {direction = 1; // chip direction range of value:0-7/* <sign> 1:negative  0:positive<map> 0:AXIS_X  1:AXIS_Y  2:AXIS_Z*//* sign[AXIS_X], sign[AXIS_Y], sign[AXIS_Z], map[AXIS_X], map[AXIS_Y], map[AXIS_Z] */convert = [0, 0, 0, 0, 1, 2,1, 0, 0, 1, 0, 2,0, 0, 1, 0, 1, 2,0, 1, 0, 1, 0, 2,1, 0, 1, 0, 1, 2,0, 0, 1, 1, 0, 2,0, 1, 1, 0, 1, 2,1, 1, 1, 1, 0, 2];}sensorRegConfig {/*  regAddr: register addressvalue: config register valuelen: size of valuemask: mask of valuedelay: config register delay time (ms)opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check 4-update_bitcalType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shiftshiftNum: shift bitsdebug: 0-no debug 1-debugsave: 0-no save 1-save*//* regAddr, value, mask, len, delay, opsType, calType, shiftNum, debug, save */initSeqConfig = [0x7e,    0xb6, 0xff,   1,     5,       2,       0,        0,     0,    0,0x7e,    0x10, 0xff,   1,     5,       2,       0,        0,     0,    0];enableSeqConfig = [0x7e,    0x11, 0xff,   1,     5,       2,       0,        0,     0,    0,0x41,    0x03, 0xff,   1,     0,       2,       0,        0,     0,    0,0x40,    0x08, 0xff,   1,     0,       2,       0,        0,     0,    0];disableSeqConfig = [0x7e,    0x10, 0xff,   1,     5,       2,       0,        0,     0,    0];}}
        }
        
    • 加速度差异化驱动的代码实现路径:drivers\peripheral\sensor\chipset\accel\accel_mxc6655xa.c

      • 加速度传感器差异化驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:

        /* 注册加速度mxc6655xa传感器入口数据结构体对象 */
        struct HdfDriverEntry g_accelMxc6655xaDevEntry = {.moduleVersion = 1, // 加速度mxc6655xa传感器模块版本号.moduleName = "HDF_SENSOR_ACCEL_MXC6655XA", // 加速度mxc6655xa传感器模块名,要与device_info.hcs文件里加速度mxc6655xa传感器moduleName字段值一致.Bind = Mxc6655xaBindDriver, // 加速度mxc6655xa传感器的绑定函数.Init = Mxc6655xaInitDriver, // 加速度mxc6655xa传感器的初始化函数.Release = Mxc6655xaReleaseDriver, // 加速度mxc6655xa传感器资源释放函数
        };
        /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
        HDF_INIT(g_accelMxc6655xaDevEntry);
        
      • 加速度传感器差异化驱动Bind接口实现如下:

        int32_t Mxc6655xaBindDriver(struct HdfDeviceObject *device)
        {CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)OsalMemCalloc(sizeof(*drvData));if (drvData == NULL) {HDF_LOGE("%s: Malloc MXC6655XA drv data fail", __func__);return HDF_ERR_MALLOC_FAIL;}drvData->ioService.Dispatch = DispatchMXC6655xa;drvData->device = device;device->service = &drvData->ioService;g_mxc6655xaDrvData = drvData;return HDF_SUCCESS;
        }
        
      • 加速度传感器差异化驱动Init接口实现如下:

        int32_t Mxc6655xaInitDriver(struct HdfDeviceObject *device)
        {int32_t ret;struct AccelOpsCall ops;CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service;CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);drvData->sensorCfg = AccelCreateCfgData(device->property);if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__);return HDF_ERR_NOT_SUPPORT;}ops.Init = NULL;ops.ReadData = ReadMxc6655xaData;ret = AccelRegisterChipOps(&ops);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Register MXC6655XA accel failed", __func__);return HDF_FAILURE;}ret = InitMxc6655xa(drvData->sensorCfg);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: Init MXC6655XA accel failed", __func__);return HDF_FAILURE;}return HDF_SUCCESS;
        }
        
      • 加速度传感器差异化驱动Release接口实现如下:

        void Mxc6655xaReleaseDriver(struct HdfDeviceObject *device)
        {CHECK_NULL_PTR_RETURN(device);struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service;CHECK_NULL_PTR_RETURN(drvData);if (drvData->sensorCfg != NULL) {AccelReleaseCfgData(drvData->sensorCfg);drvData->sensorCfg = NULL;}OsalMemFree(drvData);
        }
        
      • 加速度传感器差异化驱动内部接口实现。

        需要开发者实现的ReadMxc6655xaData接口函数,在 Mxc6655xaInitDriver函数里面注册此函数,具体实现如下:

        static int32_t ReadMxc6655xaRawData(struct SensorCfgData *data, struct AccelData *rawData, uint64_t *timestamp)
        {uint8_t status = 0;uint8_t reg[ACCEL_AXIS_BUTT];OsalTimespec time;int32_t x;int32_t y;int32_t z;(void)memset_s(&time, sizeof(time), 0, sizeof(time));(void)memset_s(reg, sizeof(reg), 0, sizeof(reg));CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);if (OsalGetTime(&time) != HDF_SUCCESS) {HDF_LOGE("%s: Get time failed", __func__);return HDF_FAILURE;}*timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT; /* unit nanosecond */int32_t ret = ReadSensor(&data->busCfg, MXC6655XA_STATUS_ADDR, &status, sizeof(uint8_t));if (ret != HDF_SUCCESS) {HDF_LOGE("%s: data status [%u] ret [%d]", __func__, status, ret);return HDF_FAILURE;}ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_LSB_ADDR, &reg[ACCEL_X_AXIS_LSB], sizeof(uint8_t));CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_MSB_ADDR, &reg[ACCEL_X_AXIS_MSB], sizeof(uint8_t));CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_LSB_ADDR, &reg[ACCEL_Y_AXIS_LSB], sizeof(uint8_t));CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_MSB_ADDR, &reg[ACCEL_Y_AXIS_MSB], sizeof(uint8_t));CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_LSB_ADDR, &reg[ACCEL_Z_AXIS_LSB], sizeof(uint8_t));CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_MSB_ADDR, &reg[ACCEL_Z_AXIS_MSB], sizeof(uint8_t));CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");x = SensorConvertData(reg[ACCEL_X_AXIS_MSB], reg[ACCEL_X_AXIS_LSB]);y = SensorConvertData(reg[ACCEL_Y_AXIS_MSB], reg[ACCEL_Y_AXIS_LSB]);z = SensorConvertData(reg[ACCEL_Z_AXIS_MSB], reg[ACCEL_Z_AXIS_LSB]);rawData->x = x;rawData->y = y;rawData->z = z;return HDF_SUCCESS;
        }
        /* 读取加速度的event数据,在 Mxc6655xaInitDriver函数里面注册此函数,将数据传给加速度抽象驱动 */
        int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event)
        {int32_t ret;struct AccelData rawData = { 0, 0, 0 };static int32_t tmp[ACCEL_AXIS_NUM];CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM);CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM);ret = ReadMxc6655xaRawData(cfg, &rawData, &event->timestamp);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: MXC6655XA read raw data failed", __func__);return HDF_FAILURE;}event->sensorId = SENSOR_TAG_ACCELEROMETER;event->option = 0;event->mode = SENSOR_WORK_MODE_REALTIME;rawData.x = rawData.x * MXC6655XA_ACC_SENSITIVITY_2G;rawData.y = rawData.y * MXC6655XA_ACC_SENSITIVITY_2G;rawData.z = rawData.z * MXC6655XA_ACC_SENSITIVITY_2G;tmp[ACCEL_X_AXIS] = (rawData.x * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;tmp[ACCEL_Y_AXIS] = (rawData.y * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;tmp[ACCEL_Z_AXIS] = (rawData.z * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;ret = SensorRawDataToRemapData(cfg->direction, tmp, sizeof(tmp) / sizeof(tmp[0]));if (ret != HDF_SUCCESS) {HDF_LOGE("%s: MXC6655XA convert raw data failed", __func__);return HDF_FAILURE;}event->dataLen = sizeof(tmp);event->data = (uint8_t *)&tmp;return ret;
        }
        

调测验证

驱动开发完成后,在传感器单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。

  • 参考测试代码如下:

    #include <cmath>
    #include <cstdio>
    #include <unistd.h>
    #include <gtest/gtest.h>
    #include <securec.h>
    #include "hdf_base.h"
    #include "osal_mem.h"
    #include "osal_time.h"
    #include "sensor_if.h"
    #include "sensor_type.h"using namespace testing::ext;
    const struct SensorInterface *g_sensorDev = nullptr;
    /* 创建回调函数 */
    static int32_t SensorDataCallback(const struct SensorEvents *event)
    {if (event == NULL) {return HDF_FAILURE;}float *data = (float*)event->data;printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp,event->sensorId, (*data), *(data + 1), *(data + 2));return HDF_SUCCESS;
    }class HdfSensorTest : public testing::Test {
    public:static void SetUpTestCase();static void TearDownTestCase();void SetUp();void TearDown();
    };/* 用例执行前,初始化传感器接口实例 */
    void HdfSensorTest::SetUpTestCase()
    {g_sensorDev = NewSensorInterfaceInstance();if (g_sensorDev == nullptr) {printf("test sensor get module instance failed\n\r");}
    }
    /* 用例资源释放 */
    void HdfSensorTest::TearDownTestCase()
    {if (g_sensorDev != nullptr) {FreeSensorInterfaceInstance();g_sensorDev = nullptr;}
    }void HdfSensorTest::SetUp()
    {
    }void HdfSensorTest::TearDown()
    {
    }HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0)
    {int ret;struct SensorInformation *sensorInfo = NULL;int32_t count = 0;int32_t sensorInterval = 200000000; /* 数据采样率设置200毫秒,单位纳秒 */int32_t reportInterval = 400000000;/* 2.订阅者注册传感器数据回调处理函数 */ret = g_sensorDev->Register(TRADITIONAL_SENSOR_TYPE, SensorDataCallback);if (ret != 0) {return;}printf("Register success\n");/* 3.获取设备支持的Sensor列表 */ret = g_sensorDev->GetAllSensors(&sensorInfo, &count);if (ret != 0) {return;}printf("GetAllSensors count: %d\n", count);for (int i = 0; i < count; i++){printf("sensor [%d]: sensorName: %s, vendorName: %s, sensorTypeId: %d, sensorId: %d\n", i,sensorInfo[i].sensorName, sensorInfo[i].vendorName, sensorInfo[i].sensorTypeId, sensorInfo[i].sensorId);}for (int i = 0; i < count; i++){/* 4.设置传感器采样率 */ret = g_sensorDev->SetBatch(sensorInfo[i].sensorId, sensorInterval, reportInterval);if (ret != 0) {printf("SetBatch failed\n ,ret: %d",ret);continue;}printf("SetBatch success\n");/* 5.使能传感器 */ret = g_sensorDev->Enable(sensorInfo[i].sensorId);if (ret != 0) {continue;}printf("Enable success\n");usleep(1000 * 1000);/* 6.去使能传感器 */ret = g_sensorDev->Disable(sensorInfo[i].sensorId);if (ret != 0) {continue;}printf("Disable success\n");}/* 7.取消传感器数据订阅函数 */ret = g_sensorDev->Unregister(TRADITIONAL_SENSOR_TYPE, SensorDataCallback);if (ret != 0) {return;}printf("Unregister success\n");
    }
    
  • 编译文件gn参考代码如下:

    import("//build/ohos.gni")
    import("//build/test.gni")
    import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")module_output_path = "drivers_peripheral_sensor/sensor"
    ohos_unittest("sensor_test") {module_out_path = module_output_pathsources = [ "sensor_test.cpp" ]include_dirs = ["//drivers/peripheral/sensor/interfaces/include",]deps = [ "//drivers/peripheral/sensor/hal:hdi_sensor" ]external_deps = ["c_utils:utils","hdf_core:libhdf_utils","hiviewdfx_hilog_native:libhilog",]cflags = ["-Wall","-Wextra","-Werror","-Wno-format","-Wno-format-extra-args",]install_enable = trueinstall_images = [ "vendor" ]module_install_dir = "bin"part_name = "unionman_products"
    }
    

相关文章:

OpenHarmony外设驱动使用 (十),Sensor

OpenHarmony外设驱动使用 &#xff08;十&#xff09; Sensor 概述 功能简介 Sensor驱动模型屏蔽硬件器件差异&#xff0c;为上层Sensor服务系统提供稳定的Sensor基础能力接口&#xff0c;包括Sensor列表查询、Sensor启停、Sensor订阅及取消订阅&#xff0c;Sensor参数配置等…...

(2025小白全踩坑版)【OpenHarmony】移植 3.1 版本系统到 STM32F407ZG开发板

在上stm32课程&#xff0c;有这样一道要求&#xff1a; 参考了大佬的文章之后&#xff0c;发现出现了liteos_m.mk文件找不到的情况&#xff0c;于是只能另寻他路 VSCode 搭建 STM32 开发环境_vscode stm32仿真-CSDN博客 【OpenHarmony】移植 3.1 版本系统到 STM32_openharm…...

【HTML-4】HTML段落标签:构建内容结构的基础

在网页开发中&#xff0c;段落标签<p>是最基础也是最重要的HTML元素之一。这篇博客将深入探讨段落标签的用法、最佳实践以及相关技术细节。 1. 段落标签的基本用法 HTML段落标签用于定义文本段落&#xff0c;浏览器会自动在段落前后添加一定的空白&#xff08;margin&a…...

深度学习+Flask 打包一个AI模型接口并部署上线

🚀 深度学习 + Flask 打包一个 AI 模型接口并部署上线(实战教程) 深度学习模型训练完毕后,我们该如何部署上线让它“动起来”?本篇带你手把手用 Flask 将训练好的 PyTorch 模型封装成 Web 接口,实现一个轻量、可访问的在线 AI 服务。 🧠 一、为什么要部署模型? 训练…...

C++类与对象(二):六个默认构造函数(二)

在上篇提到了构造函数、拷贝构造函数、析构函数&#xff0c;这篇将会分享剩下默认构造函数&#xff1a;赋值运算符重载、运算符重载。当学习了这些构造函数可以实现一个日期类。 目录 运算符重载 赋值运算符重载 前置 后置 运算符重载 函数名字为&#xff1a;关键字operat…...

HarmonyOS NEXT应用开发实战:玩鸿蒙App客户端开发

之前学习android时候&#xff0c;有一个玩android的客户端项目很火&#xff0c;不但能够学习知识&#xff0c;还能够动手实践&#xff0c;激发学习兴趣。这里作者通过一个完整的实战项目—玩鸿蒙客户端App&#xff0c;一块儿深入学习如何在HarmonyOS平台上开发一个功能丰富且完…...

十六、面向对象底层逻辑-BeanPostProcessor接口设计

一、引言&#xff1a;Bean生命周期的精密控制 在Spring容器的Bean实例化过程中&#xff0c;BeanPostProcessor接口是开发者介入对象初始化阶段的核心扩展点。作为Spring框架最强大的扩展机制之一&#xff0c;该接口提供了对Bean实例化过程的原子级控制能力&#xff0c;支撑了A…...

在线免费图片处理工具-传道软件图片工具

在线免费图片处理工具-传道软件图片工具 在线免费图片处理工具&#xff0c;无需注册与登录&#xff0c;用完即走。 官网链接&#xff1a; https://www.chdaoai.com/image.html 功能有&#xff1a; Favicon图标生成&#xff0c;图片颜色拾取器&#xff0c;屏幕颜色拾取&…...

JS进阶学习04

一、深浅拷贝 1.浅拷贝 首先浅拷贝和深拷贝只针对引用类型 浅拷贝&#xff1a;拷贝的是地址 常见方法&#xff1a; 1. 拷贝对象&#xff1a;Object.assgin() / 展开运算符 {...obj} 拷贝对象 2. 拷贝数组&#xff1a;Array.prototype.concat() 或者 [...arr] >如果是简…...

CSS、SCSS 和 SASS 的语法差异

CSS、SCSS 和 SASS 的语法差异 CSS (Cascading Style Sheets) 标准样式表语言&#xff0c;所有浏览器原生支持语法特点&#xff1a; 使用大括号 {} 包裹规则使用分号 ; 结束声明简单的选择器-属性-值结构 .container {width: 100%;margin: 0 auto; }SCSS (Sassy CSS) CSS的…...

ThreadPoolTaskExecutor 和 ThreadPoolExecutor 的使用场景

在Spring Boot项目中&#xff0c;ThreadPoolTaskExecutor 和 ThreadPoolExecutor 的使用场景不同&#xff0c;但大部分开发者会更倾向于用 ThreadPoolTaskExecutor。我来给你拆解清楚&#xff0c;面试时直接甩这个答案&#xff01; 1️⃣ 核心区别 ThreadPoolExecutor&#xf…...

打卡31天

文件的规范拆分和写法 知识点回顾 规范的文件命名 规范的文件夹管理 机器学习项目的拆分 编码格式和类型注解 作业&#xff1a;尝试针对之前的心脏病项目&#xff0c;准备拆分的项目文件&#xff0c;思考下哪些部分可以未来复用。 补充介绍&#xff1a; pyc文件的介绍 知识…...

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市分析 OBOO鸥柏品牌推出的AI数字人触摸屏查询触控人脸识别语音交互一体机&#xff0c;是其在智能交互设备领域的又一创新产品。该一体机整合了触摸屏查询、AI人脸识别、AI声源定位语音麦克风&#xff0c;触控交互以…...

基于大模型的闭合性尺桡骨干骨折全方位诊疗研究报告

目录 一、引言 1.1 研究背景与目的 1.2 研究意义 二、大模型技术原理与应用现状 2.1 大模型基本原理 2.2 在医疗领域的应用案例 三、闭合性尺桡骨干骨折概述 3.1 骨折定义与分类 3.2 流行病学特征 3.3 临床症状与诊断方法 四、大模型在术前风险预测中的应用 4.1 数…...

Win11上安装docker

Win11上安装docker 一、安装WSL&#xff08;Windows Subsystem for Linux&#xff09;二、安装docker到D盘三、启动docker四、测试启动容器 一、安装WSL&#xff08;Windows Subsystem for Linux&#xff09; 以管理员身份打开cmd 更新WSL wsl --update3. 安装WSL wsl --ins…...

Axure项目实战:智慧运输平台后台管理端-订单管理1(多级交互)

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!如有帮助请订阅专栏! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:订单管理 主要内容:条件组合、中继器筛选、表单跟随菜单拖动、审批数据互通等 应用场景…...

如何在 Android 手机和平板电脑上下载应用程序

对于Android用户来说&#xff0c;从Google Play Store下载应用程序并不陌生&#xff0c;对吧&#xff1f;但是&#xff0c;除了 Google Play 商店之外&#xff0c;您还可以在哪里为 Android 设备下载和安装应用程序呢&#xff1f;这就是我们今天要分享的内容。我们解释了 6 种下…...

C++23 新特性:允许 std::stack 与 std::queue 从迭代器对构造 (P1425R4)

文章目录 背景与动机提案内容与实现细节提案 P1425R4实现细节编译器支持 对开发者的影响提高灵活性简化代码向后兼容性 总结 C23标准带来了许多令人兴奋的新特性和改进&#xff0c;其中之一便是对标准容器的增强。提案P1425R4允许 std::stack 和 std::queue 直接从一对迭代器…...

在线OJ系统测试报告

在线OJ系统测试报告 项目背景项目功能管理员功能用户功能 测试计划功能测试自动化测试性能测试 项目背景 本项目为在线OJ系统&#xff0c;采用微服务架构以及前后端分离的方法来实现&#xff0c;包含用户管理、题目管理、竞赛管理、判题服务、网关服务、消息与任务调度等多个子…...

31-35【动手学深度学习】深度学习硬件

1. CPU和GPU 1.1 CPU CPU每秒钟计算的浮点运算数为0.15&#xff0c;GPU为12。GPU的显存很低&#xff0c;16GB&#xff08;可能32G封顶&#xff09;&#xff0c;CPU可以一直插内存。 左边是GPU&#xff08;只能做些很简单的游戏&#xff0c;视频处理&#xff09;&#xff0c;中…...

Dify的大语言模型(LLM) AI 应用开发平台-本地部署

前言 今天闲着&#xff0c;捣鼓一下 Dify 这个开源平台&#xff0c;在 mac 系统上&#xff0c;本地部署并运行 Dify 平台&#xff0c;下面记录个人在本地部署Dify 的过程。 Dify是什么&#xff1f; Dify是一个开源的大语言模型&#xff08;LLM&#xff09;应用开发平台&#…...

《MQTT 从 0 到 1:原理、实战与面试指南全解》

一、MQTT 是什么&#xff1f; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种 轻量级、基于发布/订阅&#xff08;Pub/Sub&#xff09;模式的消息传输协议&#xff0c;适用于物联网&#xff08;IoT&#xff09;、实时通信等对 低带宽、高延迟、不稳定…...

SpringMVC 通过ajax 实现文件的上传

使用form表单在springmvc 项目中上传文件&#xff0c;文件上传成功之后往往会跳转到其他的页面。但是有的时候&#xff0c;文件上传成功的同时&#xff0c;并不需要进行页面的跳转&#xff0c;可以通过ajax来实现文件的上传 下面我们来看看如何来实现&#xff1a; 方式1&…...

图片识别(TransFormerCNNMLP)

目录 一、Transformer &#xff08;一&#xff09;ViT&#xff1a;Transformer 引入计算机视觉的里程碑 &#xff08;二&#xff09;Swin-Transformer&#xff1a;借鉴卷积改进 ViT &#xff08;三&#xff09;VAN&#xff1a;使用卷积模仿 ViT &#xff08;四&#xff09;…...

手术机器人行业新趋势:Kinova多机械臂协同系统如何突破复杂场景适应性瓶颈?

机器人手术历经多阶段技术演进&#xff0c;已成为现代医疗重要方向。其需求增长源于医疗机构对高精度低风险手术方案的需求、微创手术普及及技术进步带来的复杂场景适应性提升。Kinova 轻型机械臂凭借模块化设计与即插即用功能&#xff0c;可快速适配不同手术环境&#xff0c;为…...

国酒华夏实业酒水供应链:全品类覆盖打造一站式购销平台

在消费升级与供应链效率双重驱动的酒水行业变革中&#xff0c;国酒华夏实业凭借全品类覆盖与数字化赋能&#xff0c;构建起集采购、品鉴、文化传播于一体的新型酒水供应链体系。其“一站式购销平台”模式不仅重塑了传统酒水流通链路&#xff0c;更通过精准服务与品质保障&#…...

【Qt】:设置hover属性,没有适应到子控件中

#ButtonStyle:hover 是一个 ID 选择器&#xff0c;仅对设置了 objectName"ButtonStyle" 的控件本身生效&#xff0c;不会自动应用到其子控件&#xff08;如 QLabel 和 QWidget&#xff09;。 在ButtonForm中&#xff0c;有一个Qwidget控件&#xff0c;在这个Qwidget中…...

缺乏经验的 PCB 过孔建模方法

您是一名背板设计人员,被指派设计一种新的高速、多千兆位串行链路架构,从多个线卡到背板上的多个交换矩阵交换卡。这些链路必须在第一天以 6GB/s 的速度运行,并且为 10GB/s (IEEE 802.3KR) 做好产品演进的准备。时间表很紧,您需要提出一个背板架构,以允许程序的其余部分…...

搭建人工智能RAG知识库的主流平台与特点概述

在2022年末chatgpt和2024年末deepseek的推动下&#xff0c;人工智能应用如雨后春笋&#xff0c;层出不穷&#xff0c;日新月异。现推荐一些截至目前比较主流的用来搭建RAG的平台。 1. Haystack 特点&#xff1a; 模块化架构&#xff1a;支持端到端问答系统构建&#xff0c;集…...

【QT】在界面A打开界面B时,界面A隐藏,界面B关闭时,界面A复现

在Qt6中&#xff0c;可以通过信号与槽机制实现界面A在关闭界面B时重新显示。以下是具体的实现步骤&#xff1a; 方法一&#xff1a;使用自定义关闭信号 在界面B中定义关闭信号&#xff1a;当界面B关闭时发射该信号。连接信号到界面A的显示槽&#xff1a;在界面A中创建界面B时…...

捡漏岗位:国考报名数据和岗位特征分析

2025 年国考官方数据及权威分析&#xff0c;报录比低于 10:1 的岗位主要集中在中西部艰苦边远地区、特殊专业技术岗位及定向招录岗位。 岗位名称招录机关地区招录人数报名人数报录比报考条件示例一级警长及以下&#xff08;三&#xff09;新疆出入境边防检查总站新疆3124:1男性…...

qt---命名规范

1、命名规范 1) 类名&#xff1a;单词首字母大写&#xff0c;单词和单词之间直接连接&#xff0c;无需连接字符 如&#xff1a;MyClass&#xff0c;QPushButton class MainWindow { };2) Qt中内置的类型&#xff0c;头文件和类命名同名。 如&#xff1a; #include <QStri…...

信息系统项目管理师考前练习3

项目组合管理 企业战略调整后,项目组合经理应优先: A. 终止所有不符合新战略的项目 B. 重新评估项目优先级与资源分配 C. 要求所有项目加快交付进度 D. 合并相似项目以减少成本 答案:B 解析:项目组合管理的核心是动态对齐战略,优先重新评估项目价值与资源匹配(第5版强调…...

【算法创新+设计】灰狼算法GWO+扰动算子,求解大规模TSP问题利器

目录 1.灰狼算法GWO原理2.连续空间到离散空间3.核心公式处理4.结果展示5.代码获取6.读者交流 1.灰狼算法GWO原理 【智能算法】灰狼算法&#xff08;GWO&#xff09;原理及实现 2.连续空间到离散空间 GWO算法是针对连续空间问题设计的优化方法&#xff0c;而旅行商问题&#…...

GPU P-State 模式说明

在 NVIDIA GPU 上&#xff0c;“P-State”&#xff08;Performance State&#xff09;用来表示显卡当前的性能&#xff0f;功耗等级&#xff0c;P0 代表最高性能&#xff08;最高核心频率、最大功耗&#xff09;&#xff0c;数字越大性能越低、功耗越小。不同 P-State 的主要区…...

真实世界中的贝叶斯网络:Bootstrap、模型平均与非齐次动态的科研应用

在生态与环境科学领域&#xff0c;揭示变量间因果机制是理解复杂系统运行规律的核心挑战。传统实验方法受限于高昂成本与生态扰动风险&#xff0c;而经典统计模型仅能刻画变量相关性&#xff0c;难以突破"相关非因果"的认知瓶颈。贝叶斯网络作为融合图论与概率论的前…...

.NET外挂系列:4. harmony 中补丁参数的有趣玩法(上)

一&#xff1a;背景 1. 讲故事 前面几篇我们说完了 harmony 的几个注入点&#xff0c;这篇我们聚焦注入点可接收的几类参数的解读&#xff0c;非常有意思&#xff0c;在.NET高级调试 视角下也是非常重要的&#xff0c;到底是哪些参数&#xff0c;用一张表格整理如下&#xff…...

【VLNs篇】03:VLMnav-端到端导航与视觉语言模型:将空间推理转化为问答

栏目内容论文标题End-to-End Navigation with Vision-Language Models: Transforming Spatial Reasoning into Question-Answering (端到端导航与视觉语言模型&#xff1a;将空间推理转化为问答)核心问题如何利用大型视觉语言模型&#xff08;VLM&#xff09;实现端到端的机器人…...

云原生攻防4(Kubernetes基础补充)

什么是K8S? Kubernetes 是做什么的? 什么是 Docker? 什么是容器编排? Kubernetes 一词来自希腊语,意思是“飞行员”或“舵手”。这个名字很贴切,Kubernetes 可以帮助你在波涛汹涌的容器海洋中航行。 Kubernetes 是 Google 基于 Borg 开源的容器编排调度引擎,作为 CNCF最…...

redis--redisJava客户端:Jedis详解

在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a; https://redis.io/docs/latest/develop/clients/ Jedis 以Redis命令做方法名称&#xff0c;学习成本低&#xff0c;简单实用&#xff0c;但是对于Jedis实例是线程不安全的&#xff08;即创建一个Jedis实例&a…...

SpringBoot-SpringBoot源码解读

SpringBoot-SpringBoot源码解读 一、Spring Boot启动过程概述 Spring Boot通过一系列的类和机制&#xff0c;简化了Spring应用的启动流程。当你执行SpringApplication.run()时&#xff0c;Spring Boot会自动完成应用的初始化、环境配置、组件加载、自动配置等任务&#xff0c…...

黑马程序员C++2024新版笔记 第4章 函数和结构体

1.结构体的基本应用 结构体struct是一种用户自定义的复合数据类型&#xff0c;可以包含不同类型的成员。例如&#xff1a; struct Studet {string name;int age;string gender; } 结构体的声明定义和使用的基本语法&#xff1a; struct 结构体类型 {成员1类型 成员1名称;成…...

【沉浸式求职学习day46】【华为5.7暑期机试题目讲解】

沉浸式求职学习 题目1题目2 题目1 一个超大智能汽车测试场有多个充电桩&#xff0c;每个充电桩的位置由其在二维平面上的坐标(x,y)表示。给定一辆智能汽车的当前位置(car_x,car_y)&#xff0c;请设计一个高效的算法&#xff0c;找出给定智能汽车行驶到充电桩行驶距离最近的k个…...

PDF处理控件Aspose.PDF教程:以编程方式将PDF转换为Word

您是否正在寻找在线将 PDF 转换为 Word 的方法&#xff1f;在本指南中&#xff0c;我们将探索如何使用 C#、Java 和 Python 编码解决方案将 PDF 文档转换为可编辑的 Word 文件。开发人员通过代码将 PDF 文件转换为 Word 格式&#xff0c;从而获得显著优势。这种方法可以轻松实现…...

旋转位置RoPE编码详解

一. 旋转位置编码和正余弦位置编码比对 旋转位置编码&#xff08;RoPE&#xff09;和正余弦位置编码&#xff08;Sinusoidal Position Encoding&#xff09;是两种常用的位置编码方法&#xff0c;它们在处理序列数据时具有不同的数学形式和特性。以下是对两者优劣的详细说明及…...

canvas(二)-动画(2d)

<canvas> 动画是通过 JavaScript 动态更新画布内容来实现的。它利用 requestAnimationFrame 方法实现平滑的动画效果&#xff0c;适用于游戏、数据可视化、交互式图形等场景。真的需要数据可视化等场景使用&#xff0c;还是直接引入外部模型还原度比较高&#xff0c;但同…...

Dynamics 365 Business Central Azure application registration

本方法适用于 单租户服务器身份验证。 实现方法 在大多数组织里ERP Admin 不一定有权限 Azure Admin权限&#xff0c;在实施过程中你只需要把以下指引发给你的系统管理员。 请注意后面有系统管理员设置好后&#xff0c;你如何检查。 导航到 https://admin.microsoft.com 并登…...

选择合适的Azure数据库监控工具

Azure云为组织提供了众多服务&#xff0c;使其能够无缝运行应用程序、Web服务和服务器部署&#xff0c;其中包括云端数据库部署。Azure数据库能够与云应用程序实现无缝集成&#xff0c;具备可靠、易扩展和易管理的特性&#xff0c;不仅能提升数据库可用性与性能&#xff0c;同时…...

Access链接Azure SQL

Hi&#xff0c;大家好呀&#xff01; 最近在给大家分享了SQL Server方面的一些视频&#xff0c;那今天我们也来讲讲Azure SQL。 什么是Azure SQL&#xff0c;这里我们就不介绍了&#xff0c;如果你没有用这个数据库&#xff0c;那你可以简单的把它理解成&#xff0c;就是SQL …...

34、React Server Actions深度解析

一、灵魂契约协议&#xff08;核心机制&#xff09; 1. 次元融合架构 "use server";async function borrowBook(bookId: number, readerName: string) {// 模拟数据库操作const result await db.execute(UPDATE books SET available false WHERE id ?,[bookId]…...