跳转至

代码

Warning

以下代码应基于发布代码中的代码,可能已更新。

sensing_command.h

/**
 * @file sensing_command.h
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief MQTT远程控制命令处理器,用于传感模块
 * @version 1.0
 * @date 2025-01-XX
 * @copyright Copyright (c) 2025
 *
 * @details
 * 该模块处理用于控制在线和离线传感的MQTT命令。
 * 命令格式:SENSE,ONLINE 或 SENSE,OFFLINE,带参数
 *
 * 支持的命令:
 * - SENSE,ONLINE,F=频率,D=持续时间
 * - SENSE,ONLINE,STOP
 * - SENSE,ONLINE,STATUS
 * - SENSE,OFFLINE,F=频率,D=采样时长
 * - SENSE,OFFLINE,F=频率,D=采样时长,DL=延迟秒
 * - SENSE,OFFLINE,F=频率,D=采样时长,TIME=YYMMDDHHMMSS
 * - SENSE,OFFLINE,STOP
 * - SENSE,OFFLINE,STATUS
 */

#pragma once

#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "node_acc_adxl355.h"

#ifdef __cplusplus
extern "C"
{
#endif

/* ============================================================================
 * FUNCTION DECLARATIONS
 * ============================================================================ */

/**
 * @brief 处理MQTT传感命令
 * @param command 命令字符串(例如:"SENSE,ONLINE,F=20,D=60")
 * @param command_len 命令字符串长度
 * @return 成功返回ESP_OK,失败返回错误码
 * @note 此函数解析并执行命令,然后通过MQTT发布响应
 */
esp_err_t sensing_command_process(const char *command, int command_len);

/**
 * @brief 初始化传感命令处理器
 * @return 成功返回ESP_OK,失败返回错误码
 * @note 必须在MQTT初始化后调用
 */
esp_err_t sensing_command_init(void);

/**
 * @brief 为命令处理器设置传感器句柄
 * @param handle ADXL355传感器句柄
 * @return 成功返回ESP_OK,失败返回错误码
 * @note 必须在处理命令之前调用
 */
esp_err_t sensing_command_set_sensor_handle(adxl355_handle_t *handle);

#ifdef __cplusplus
}
#endif

sensing_command.c

实现包括:

关键函数

  1. 命令处理
  2. sensing_command_process(): 命令处理的主入口点
  3. command_processing_task(): 从队列处理命令的FreeRTOS任务
  4. handle_online_command(): 处理在线传感命令
  5. handle_offline_command(): 处理离线传感命令

  6. 参数解析

  7. parse_float_param(): 从命令字符串中提取浮点参数
  8. parse_int_param(): 从命令字符串中提取整数参数
  9. parse_time_param(): 解析YYMMDDHHMMSS格式的TIME参数

  10. 任务管理

  11. offline_sensing_task_wrapper(): 支持延迟的离线传感包装任务
  12. online_sensing_stop_task(): 在持续时间后自动停止在线传感的任务

  13. 响应处理

  14. send_mqtt_response(): 通过MQTT发布命令响应

命令队列结构

#define COMMAND_QUEUE_SIZE 5
#define MAX_COMMAND_LENGTH 256

typedef struct
{
    char command[MAX_COMMAND_LENGTH];
    int command_len;
} command_queue_item_t;

初始化流程

esp_err_t sensing_command_init(void)
{
    // 创建命令队列
    s_command_queue = xQueueCreate(COMMAND_QUEUE_SIZE, sizeof(command_queue_item_t));

    // 创建命令处理任务
    BaseType_t ret = xTaskCreate(
        command_processing_task,
        "cmd_processor",
        4096, // 栈大小
        NULL,
        5, // 优先级
        &s_command_task_handle);

    return ret == pdPASS ? ESP_OK : ESP_FAIL;
}

命令处理流程

  1. 通过MQTT回调接收命令
  2. 命令排队等待处理
  3. 命令处理任务出队并验证
  4. 命令解析并路由到相应的处理器
  5. 通过MQTT发布响应

参数解析示例

static esp_err_t parse_float_param(const char *str, const char *prefix, float *value)
{
    char search_str[32];
    snprintf(search_str, sizeof(search_str), "%s=", prefix);
    const char *pos = strstr(str, search_str);
    if (pos == NULL)
    {
        return ESP_ERR_NOT_FOUND;
    }

    pos += strlen(search_str);
    const char *end = strchr(pos, ',');
    if (end == NULL)
    {
        end = pos + strlen(pos);
    }

    char value_str[64];
    size_t len = end - pos;
    if (len >= sizeof(value_str))
    {
        len = sizeof(value_str) - 1;
    }
    strncpy(value_str, pos, len);
    value_str[len] = '\0';

    char *parse_end;
    *value = strtof(value_str, &parse_end);

    if (parse_end == value_str || *parse_end != '\0')
    {
        return ESP_ERR_INVALID_ARG;
    }

    return ESP_OK;
}

在线命令处理器

static esp_err_t handle_online_command(const char *cmd)
{
    // 检查STOP命令
    if (strstr(cmd, "STOP") != NULL)
    {
        esp_err_t ret = online_sensing_stop();
        send_mqtt_response(ret == ESP_OK ? 
            "SENSE,OK,ONLINE,STOPPED" : 
            "SENSE,ERROR,ONLINE,STOP_FAILED");
        return ret;
    }

    // 检查STATUS命令
    if (strstr(cmd, "STATUS") != NULL)
    {
        bool is_running = false;
        online_sensing_is_running(&is_running);
        online_sensing_config_t config;
        online_sensing_get_config(&config);

        char resp[128];
        snprintf(resp, sizeof(resp), "SENSE,STATUS,ONLINE,RUNNING=%s,F=%.2f",
                 is_running ? "YES" : "NO", config.sampling_frequency_hz);
        send_mqtt_response(resp);
        return ESP_OK;
    }

    // 解析F和D参数
    float freq = 0.0f;
    float duration = 0.0f;

    if (parse_float_param(cmd, "F", &freq) != ESP_OK)
    {
        send_mqtt_response("SENSE,ERROR,ONLINE,INVALID_FREQ");
        return ESP_ERR_INVALID_ARG;
    }

    if (parse_float_param(cmd, "D", &duration) != ESP_OK)
    {
        duration = 0.0f; // 默认:持续运行
    }

    // 验证并启动在线传感
    // ... (实现细节)
}

离线命令处理器

static esp_err_t handle_offline_command(const char *cmd)
{
    // 检查STOP命令
    if (strstr(cmd, "STOP") != NULL)
    {
        bool is_running = false;
        offline_sensing_is_running(&is_running);
        if (is_running)
        {
            esp_err_t ret = offline_sensing_stop();
            send_mqtt_response(ret == ESP_OK ? 
                "SENSE,OK,OFFLINE,STOPPED" : 
                "SENSE,ERROR,OFFLINE,STOP_FAILED");
            return ret;
        }
        // ... (错误处理)
    }

    // 解析参数(F, D, DL, TIME)
    // ... (实现细节)

    // 创建支持延迟的离线传感任务
    // ... (任务创建)
}

使用示例

// 初始化命令处理器
esp_err_t ret = sensing_command_init();
if (ret != ESP_OK)
{
    ESP_LOGE(TAG, "初始化命令处理器失败");
    return;
}

// 设置传感器句柄
ret = sensing_command_set_sensor_handle(&adxl355_handle);
if (ret != ESP_OK)
{
    ESP_LOGE(TAG, "设置传感器句柄失败");
    return;
}

// 在MQTT消息回调中
void mqtt_message_callback(esp_mqtt_event_handle_t event)
{
    if (strncmp(event->data, "SENSE,", 6) == 0)
    {
        sensing_command_process(event->data, event->data_len);
    }
}