• Lv1
    粉丝0

积分2 / 贡献0

提问0答案被采纳0文章1

作者动态

    [经验分享] OpenHarmony sensor test tool 传感器 测试 工具

    Chao 显示全部楼层 发表于 2025-3-26 11:33:58

    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)

    你可以

    1. 使用 enable,read,disable 配合 i2cget,i2cset,单独调试 hcs 中的 init,enable,disable 序列是否有问题,或者是掩码是否生效(用来排除 OH 代码问题)。
    2. 使用 monitor 检查传感器能否正常上报读数,传感器读数是否会随环境变化而变化。

    效果如下

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

    ©著作权归作者所有,转载或内容合作请联系作者

    您尚未登录,无法参与评论,登录后可以:
    参与开源共建问题交流
    认同或收藏高质量问答
    获取积分成为开源共建先驱

    Copyright   ©2025  OpenHarmony开发者论坛  京ICP备2020036654号-3 | 京公网安备11030102011662号 |技术支持 Discuz!

    返回顶部