OpenHarmony 传感器的生态目前还不完善,体现在

  1. hdf_unittest_sensor 功能缺失,只支持 als 读取数据。
  2. hdf_unittest_sensor enable 并未真正执行读取动作,只是读取了旧值。
  3. hdf_unittest_sensor 在设备没有传感器的情况下必失败,影响 xts 验证。
  4. hdi_unittest_sensor 同样功能缺失,甚至不支持数据验证。
  5. 除 als 外,其他数据在 hdf_core 中的上报通路都没打通。
  6. 实际测试中有发现 hcs 配置中,掩码不生效的问题。
  7. chipset raw 数据读取存在重入 bug。

鉴于很多都是一些低级错误,甚至基础不牢的问题。

我开发了一个测试工具,用来检测传感器是否能正常上报数据。

功能及用法

用法如下

>hdc shell sensor_tool   
Usage: sensor_tool [options] <command> [sensor_id]
       sensor_tool (help | -h | --help)

Note: Commands without sensor_id will apply to all sensors

Commands:
  list                    List all sensors
  enable [sensor_id]      Enable specified sensor
  disable [sensor_id]     Disable specified sensor
  read [sensor_id]        Read sensor data once
  monitor [sensor_id]     Monitor sensor data continuously

Monitor Options:
  -i, --interval <ms>    Set sampling interval (default: 1000ms)
  -c, --count <num>      Set number of readings (default: infinite)
  -t, --time <sec>       Set monitoring duration in seconds (default: infinite)

你可以

使用 enable,read,disable 配合 i2cget,i2cset,
单独调试 hcs 中的 init,enable,disable 序列是否有问题,
or 掩码是否生效(用来排除 OH 代码问题)。

使用 monitor 检查传感器能否正常上报读数,
传感器读数是否会随环境变化而变化。

效果

效果如下

列出所有 sensor

C:\Users\chao>hdc shell sensor_tool list    
Available sensors (5):
----------------------------------------
Sensor[0]: ID=6, Name=magnetometer
Sensor[1]: ID=12, Name=proximity
Sensor[2]: ID=5, Name=als
Sensor[3]: ID=2, Name=gyroscope
Sensor[4]: ID=1, Name=accelerometer
----------------------------------------

enable 所有 sensor

C:\Users\chao>hdc shell sensor_tool enable
Sensor 6 (magnetometer) enabled successfully
Sensor 12 (proximity) enabled successfully
Sensor 5 (als) enabled successfully
Sensor 2 (gyroscope) enabled successfully
Sensor 1 (accelerometer) enabled successfully
All sensors enabled successfully

读取所有 sensor

C:\Users\chao>hdc shell sensor_tool read  

Reading data:
----------------------------------------
Sensor[6] magnetometer data: -22.50 -45.15 86.85
Failed to read sensor 12 (proximity) data
Sensor[5] als data: 0.60
Sensor[2] gyroscope data: -6.38 3.19 6.38
Sensor[1] accelerometer data: 0.01 1.76 -10.01
----------------------------------------

自动 enable 并监控读数

C:\Users\chao>hdc shell sensor_tool monitor
Sensor 6 (magnetometer) enabled successfully
Sensor 12 (proximity) enabled successfully
Sensor 5 (als) enabled successfully
Sensor 2 (gyroscope) enabled successfully
Sensor 1 (accelerometer) enabled successfully
All sensors enabled successfully

Reading data (count: 1):
----------------------------------------

Trying to read data from sensor 6 (magnetometer):
Sensor[6] magnetometer data: -22.65 -45.60 89.25

Trying to read data from sensor 12 (proximity):
Failed to read sensor 12 (proximity) data, ret=-1

Trying to read data from sensor 5 (als):
Sensor[5] als data: 0.60

Trying to read data from sensor 2 (gyroscope):
Sensor[2] gyroscope data: -3.19 4.25 5.32

Trying to read data from sensor 1 (accelerometer):
Sensor[1] accelerometer data: 0.00 1.75 -9.98
----------------------------------------

Reading data (count: 2):
----------------------------------------

Trying to read data from sensor 6 (magnetometer):
Sensor[6] magnetometer data: -22.05 -44.70 87.60

Trying to read data from sensor 12 (proximity):
Failed to read sensor 12 (proximity) data, ret=-1

Trying to read data from sensor 5 (als):
Sensor[5] als data: 0.60

Trying to read data from sensor 2 (gyroscope):
Sensor[2] gyroscope data: -5.32 2.13 3.19

Trying to read data from sensor 1 (accelerometer):
Sensor[1] accelerometer data: 0.02 1.73 -9.99
----------------------------------------

源码及编译

把下面文件放到 unittest 下面,
仿照 BUILD.gn 里的 hdf_unittest_sensor 改改
重新设置一个编译目标,比如 sensor_tool,然后单编即可

源码

#include <cmath>
#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <gtest/gtest.h>
#include <securec.h>
#include <string.h>
#include <getopt.h>
#include "hdf_base.h"
#include "osal_mem.h"
#include "osal_time.h"
#include "sensor_if.h"
#include "sensor_type.h"

// 全局变量
static const struct SensorInterface *g_sensorDev = nullptr;
static struct SensorInformation *g_sensorInfo = nullptr;
static int32_t g_sensorCount = 0;
static uint32_t g_interval = 1000;  // 默认采样间隔1秒
static int32_t g_count = -1;        // 默认持续读取
static int32_t g_duration = -1;     // 默认持续运行
static bool g_running = true;       // 运行状态标志

// 命令类型枚举
enum CommandType {
    CMD_NONE = 0,
    CMD_LIST,
    CMD_ENABLE,
    CMD_DISABLE,
    CMD_READ,
    CMD_MONITOR
};

// 命令参数结构
struct CommandArgs {
    enum CommandType cmd;
    int32_t sensorId;
};

// 函数声明
static void PrintUsage(void);
static int32_t ParseCommandLine(int argc, char *argv[], struct CommandArgs *args);
static int32_t InitSensorDev(void);
static void DeinitSensorDev(void);
static int32_t ListSensors(void);
static int32_t EnableSensor(int32_t sensorId);
static int32_t EnableAllSensors(void);
static int32_t DisableSensor(int32_t sensorId);
static int32_t DisableAllSensors(void);
static int32_t ReadSensorData(int32_t sensorId, bool autoEnable, bool readAll);
static const char* GetSensorName(int32_t sensorId);
static int32_t ReadAndPrintSensorData(struct SensorEvents **events, int32_t numSensors,
                                     int32_t sensorId, bool readAll, int32_t readCount = -1);

// 信号处理函数
static void SignalHandler(int signo)
{
    if (signo == SIGINT) {
        printf("\nReceived Ctrl+C, stopping...\n");
        g_running = false;
    }
}

// 主函数
int main(int argc, char *argv[])
{
    struct CommandArgs args = {CMD_NONE, 0};  // 修复结构体初始化
    int32_t ret;

    // 设置信号处理
    signal(SIGINT, SignalHandler);

    // 解析命令行参数
    ret = ParseCommandLine(argc, argv, &args);
    if (ret != 0) {
        PrintUsage();
        return -1;
    }

    // 初始化传感器设备
    ret = InitSensorDev();
    if (ret != 0) {
        printf("Failed to init sensor device\n");
        return -1;
    }

    // 执行命令
    switch (args.cmd) {
        case CMD_LIST:
            ret = ListSensors();
            break;
        case CMD_ENABLE:
            ret = (args.sensorId == -1) ? EnableAllSensors() : EnableSensor(args.sensorId);
            break;
        case CMD_DISABLE:
            ret = (args.sensorId == -1) ? DisableAllSensors() : DisableSensor(args.sensorId);
            break;
        case CMD_READ:
            ret = (args.sensorId == -1) ? ReadSensorData(0, false, true) : ReadSensorData(args.sensorId, false, false);
            break;
        case CMD_MONITOR:
            ret = (args.sensorId == -1) ? ReadSensorData(0, true, true) : ReadSensorData(args.sensorId, true, false);
            break;
        default:
            PrintUsage();
            ret = -1;
            break;
    }

    // 释放传感器设备
    DeinitSensorDev();
    return ret;
}

// 打印使用说明
static void PrintUsage(void)
{
    printf("Usage: sensor_tool [options] <command> [sensor_id]\n");
    printf("       sensor_tool (help | -h | --help)\n");
    printf("\nNote: Commands without sensor_id will apply to all sensors\n");
    printf("\nCommands:\n");
    printf("  list                    List all sensors\n");
    printf("  enable [sensor_id]      Enable specified sensor\n");
    printf("  disable [sensor_id]     Disable specified sensor\n");
    printf("  read [sensor_id]        Read sensor data once\n");
    printf("  monitor [sensor_id]     Monitor sensor data continuously\n");
    printf("\nMonitor Options:\n");
    printf("  -i, --interval <ms>    Set sampling interval (default: 1000ms)\n");
    printf("  -c, --count <num>      Set number of readings (default: infinite)\n");
    printf("  -t, --time <sec>       Set monitoring duration in seconds (default: infinite)\n");
}

// 解析命令行参数
static int32_t ParseCommandLine(int argc, char *argv[], struct CommandArgs *args)
{
    int opt;
    int option_index = 0;
    struct option long_options[] = {
        {"interval", required_argument, nullptr, 'i'},
        {"count", required_argument, nullptr, 'c'},
        {"time", required_argument, nullptr, 't'},
        {"help", no_argument, nullptr, 'h'},
        {nullptr, 0, nullptr, 0}
    };

    // 默认设置为-1表示所有传感器
    args->sensorId = -1;

    // 解析选项
    while ((opt = getopt_long(argc, argv, "i:c:t:h", long_options, &option_index)) != -1) {
        switch (opt) {
            case 'i':
                g_interval = atoi(optarg);
                break;
            case 'c':
                g_count = atoi(optarg);
                break;
            case 't':
                g_duration = atoi(optarg);
                break;
            case 'h':
                PrintUsage();
                exit(0);
            default:
                return -1;
        }
    }

    // 解析命令
    if (optind >= argc) {
        return -1;
    }

    const char *cmd = argv[optind];
    struct {
        const char *name;
        enum CommandType type;
        bool needId;
    } cmdMap[] = {
        {"list", CMD_LIST, false},
        {"enable", CMD_ENABLE, true},
        {"disable", CMD_DISABLE, true},
        {"read", CMD_READ, true},
        {"monitor", CMD_MONITOR, true},
        {nullptr, CMD_NONE, false}
    };

    for (int i = 0; cmdMap[i].name != nullptr; i++) {
        if (strcmp(cmd, cmdMap[i].name) == 0) {
            args->cmd = cmdMap[i].type;
            if (cmdMap[i].needId && optind + 1 < argc && argv[optind + 1][0] != '-') {
                args->sensorId = atoi(argv[optind + 1]);
            }
            return 0;
        }
    }

    return -1;
}

// 初始化传感器设备
static int32_t InitSensorDev(void)
{
    g_sensorDev = NewSensorInterfaceInstance();
    if (g_sensorDev == nullptr) {
        printf("Failed to get sensor interface instance\n");
        return -1;
    }

    int32_t ret = g_sensorDev->GetAllSensors(&g_sensorInfo, &g_sensorCount);
    if (ret != 0) {
        printf("Failed to get sensor information\n");
        FreeSensorInterfaceInstance();
        g_sensorDev = nullptr;
        return -1;
    }

    return 0;
}

// 释放传感器设备
static void DeinitSensorDev(void)
{
    if (g_sensorDev != nullptr) {
        FreeSensorInterfaceInstance();
        g_sensorDev = nullptr;
    }
}

// 列出所有传感器
static int32_t ListSensors(void)
{
    if (g_sensorInfo == nullptr || g_sensorCount <= 0) {
        printf("No sensors available\n");
        return -1;
    }

    printf("Available sensors (%d):\n", g_sensorCount);
    printf("----------------------------------------\n");

    struct SensorInformation *info = g_sensorInfo;
    for (int32_t i = 0; i < g_sensorCount; i++) {
        printf("Sensor[%d]: ID=%d, Name=%s\n", i, info->sensorId, info->sensorName);
        info++;
    }
    printf("----------------------------------------\n");

    return 0;
}

// 通过传感器ID获取传感器名称
static const char* GetSensorName(int32_t sensorId)
{
    if (g_sensorInfo == nullptr || g_sensorCount <= 0) {
        return "Unknown";
    }

    for (int32_t i = 0; i < g_sensorCount; i++) {
        if (g_sensorInfo[i].sensorId == sensorId) {
            return g_sensorInfo[i].sensorName;
        }
    }
    return "Unknown";
}

// 使能指定传感器
static int32_t EnableSensor(int32_t sensorId)
{
    if (g_sensorDev == nullptr) {
        printf("Sensor device not initialized\n");
        return -1;
    }

    // 设置采样间隔
    int32_t ret = g_sensorDev->SetBatch(sensorId, g_interval * 1000000, 0);
    if (ret != 0) {
        printf("Failed to set batch for sensor %d\n", sensorId);
        return -1;
    }

    // 使能传感器
    ret = g_sensorDev->Enable(sensorId);
    if (ret != 0) {
        printf("Failed to enable sensor %d\n", sensorId);
        return -1;
    }

    printf("Sensor %d (%s) enabled successfully\n", sensorId, GetSensorName(sensorId));
    return 0;
}

// 使能所有传感器
static int32_t EnableAllSensors(void)
{
    if (g_sensorDev == nullptr || g_sensorInfo == nullptr || g_sensorCount <= 0) {
        printf("No sensors available\n");
        return -1;
    }

    struct SensorInformation *info = g_sensorInfo;
    for (int32_t i = 0; i < g_sensorCount; i++) {
        int32_t ret = EnableSensor(info->sensorId);
        if (ret != 0) {
            printf("Failed to enable sensor %d\n", info->sensorId);
            return -1;
        }
        info++;
    }

    printf("All sensors enabled successfully\n");
    return 0;
}

// 禁用指定传感器
static int32_t DisableSensor(int32_t sensorId)
{
    if (g_sensorDev == nullptr) {
        printf("Sensor device not initialized\n");
        return -1;
    }

    int32_t ret = g_sensorDev->Disable(sensorId);
    if (ret != 0) {
        printf("Failed to disable sensor %d\n", sensorId);
        return -1;
    }

    printf("Sensor %d (%s) disabled successfully\n", sensorId, GetSensorName(sensorId));
    return 0;
}

// 禁用所有传感器
static int32_t DisableAllSensors(void)
{
    if (g_sensorDev == nullptr || g_sensorInfo == nullptr || g_sensorCount <= 0) {
        printf("No sensors available\n");
        return -1;
    }

    struct SensorInformation *info = g_sensorInfo;
    for (int32_t i = 0; i < g_sensorCount; i++) {
        int32_t ret = DisableSensor(info->sensorId);
        if (ret != 0) {
            printf("Failed to disable sensor %d\n", info->sensorId);
            return -1;
        }
        info++;
    }

    printf("All sensors disabled successfully\n");
    return 0;
}

// 读取并打印传感器数据
static int32_t ReadAndPrintSensorData(struct SensorEvents **events, int32_t numSensors, 
                                    int32_t sensorId, bool readAll, int32_t readCount)
{
    if (readCount >= 0) {
        printf("\nReading data (count: %d):\n", readCount + 1);
    } else {
        printf("\nReading data:\n");
    }

    if (readAll) {
        printf("----------------------------------------\n");
    }

    for (int32_t i = 0; i < numSensors; i++) {
        int32_t currentSensorId = readAll ? g_sensorInfo[i].sensorId : sensorId;
        if (readCount >= 0) {
            printf("\nTrying to read data from sensor %d (%s):\n", currentSensorId, GetSensorName(currentSensorId));
        }

        int32_t ret = g_sensorDev->ReadData(currentSensorId, events[i]);
        if (ret != 0) {
            printf("Failed to read sensor %d (%s) data%s\n", 
                   currentSensorId, GetSensorName(currentSensorId),
                   readCount >= 0 ? (", ret=" + std::to_string(ret)).c_str() : "");
            if (readCount >= 0) {
                fflush(stdout);
            }
            continue;
        }

        // 打印数据
        float *data = reinterpret_cast<float*>(events[i]->data);
        printf("Sensor[%d] %s data: ", currentSensorId, GetSensorName(currentSensorId));
        for (int32_t j = 0; j < events[i]->dataLen / sizeof(float); j++) {
            printf("%.2f ", data[j]);
        }
        printf("\n");
    }

    if (readAll) {
        printf("----------------------------------------\n");
    }
    if (readCount >= 0) {
        fflush(stdout);
    }

    return 0;
}

// 读取传感器数据
static int32_t ReadSensorData(int32_t sensorId, bool autoEnable, bool readAll)
{
    if (g_sensorDev == nullptr) {
        printf("Sensor device not initialized\n");
        return -1;
    }

    // 如果是读取所有传感器,需要额外的检查
    if (readAll && (g_sensorInfo == nullptr || g_sensorCount <= 0)) {
        printf("No sensors available\n");
        return -1;
    }

    // 使能传感器(如果指定了auto)
    if (autoEnable) {
        if (readAll) {
            int32_t ret = EnableAllSensors();
            if (ret != 0) {
                return -1;
            }
        } else {
            int32_t ret = EnableSensor(sensorId);
            if (ret != 0) {
                return -1;
            }
        }
    }

    // 分配事件数据空间
    struct SensorEvents **events;
    int32_t numSensors = readAll ? g_sensorCount : 1;

    events = (struct SensorEvents**)OsalMemCalloc(sizeof(*events) * numSensors);
    if (events == nullptr) {
        printf("Failed to allocate sensor events array\n");
        if (autoEnable) {
            if (readAll) {
                DisableAllSensors();
            } else {
                DisableSensor(sensorId);
            }
        }
        return -1;
    }

    // 初始化所有事件数据空间
    for (int32_t i = 0; i < numSensors; i++) {
        events[i] = (struct SensorEvents*)OsalMemCalloc(sizeof(*events[i]));
        if (events[i] == nullptr) {
            printf("Failed to allocate sensor event %d\n", i);
            goto cleanup;
        }
        events[i]->data = (uint8_t *)OsalMemCalloc(sizeof(float) * 3);
        if (events[i]->data == nullptr) {
            printf("Failed to allocate sensor data %d\n", i);
            goto cleanup;
        }
        events[i]->dataLen = sizeof(float) * 3;
    }

    // 如果是自动读取模式,使用循环读取
    if (autoEnable) {
        // 计算读取次数
        int32_t readCount = 0;
        int32_t maxCount = (g_count > 0) ? g_count : INT32_MAX;
        int32_t maxTime = (g_duration > 0) ? g_duration : INT32_MAX;
        OsalTimespec startTime = {0};
        OsalGetTime(&startTime);

        // 循环读取数据
        while (readCount < maxCount && g_running) {
            // 检查是否超时
            OsalTimespec currentTime = {0};
            if (OsalGetTime(¤tTime) == HDF_SUCCESS) {
                uint64_t elapsedTime = (currentTime.sec - startTime.sec) * 1000 + 
                                     (currentTime.usec - startTime.usec) / 1000;
                if (elapsedTime >= maxTime * 1000) {
                    break;
                }
            }

            ReadAndPrintSensorData(events, numSensors, sensorId, readAll, readCount);
            readCount++;
            OsalMSleep(g_interval);
        }
    } else {
        // 一次性读取数据
        ReadAndPrintSensorData(events, numSensors, sensorId, readAll);
    }

    // 禁用传感器(如果指定了auto)
    if (autoEnable) {
        if (readAll) {
            DisableAllSensors();
        } else {
            DisableSensor(sensorId);
        }
    }

cleanup:
    // 释放资源
    if (events != nullptr) {
        for (int32_t i = 0; i < numSensors; i++) {
            if (events[i] != nullptr) {
                if (events[i]->data != nullptr) {
                    OsalMemFree(events[i]->data);
                }
                OsalMemFree(events[i]);
            }
        }
        OsalMemFree(events);
    }

    return 0;
}
Logo

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

更多推荐