ESP-ADF battery_service组件之voltage_monitor子模块创建与销毁函数详解

ESP-ADF battery_service组件之voltage_monitor子模块创建与销毁函数详解

版本信息: v2.7-65-gcf908721

本章节分析的源码位于 /components/battery_service/monitors/voltage_monitor.c 文件

内部数据结构

电压监控模块内部定义了关键的结构体,用于实现电压监控和事件报告机制:

typedef struct {
    SemaphoreHandle_t mutex;         // 互斥锁,保护共享数据访问
    vol_monitor_param_t *config;     // 电压监控配置参数
    vol_monitor_event_cb event_cb;   // 事件回调函数
    void *user_ctx;                  // 用户上下文数据

    esp_timer_handle_t check_timer;  // 定时器句柄,用于定期检查电压
    int read_cnt;                    // 读取计数器
    int report_start;                // 报告启动标志
    bool full_reported;              // 满电量已报告标志
    bool low_reported;               // 低电量已报告标志
} vol_monitor_ctx_t;

结构体关系图

下面的图表展示了电压监控模块的核心数据结构及其关系:

包含(config)
1
1
生成事件
1
vol_monitor_ctx_t
+SemaphoreHandle_t mutex
+vol_monitor_param_t* config
+vol_monitor_event_cb event_cb
+void* user_ctx
+esp_timer_handle_t check_timer
+int read_cnt
+int report_start
+bool full_reported
+bool low_reported
vol_monitor_param_t
+void* user_data
+int read_freq
+int report_freq
+int vol_full_threshold
+int vol_low_threshold
+bool(*init)(void*)
+bool(*deinit)(void*)
+int(*vol_get)(void*)
«enumeration»
vol_monitor_event_t
VOL_MONITOR_EVENT_FREQ_REPORT
VOL_MONITOR_EVENT_BAT_FULL
VOL_MONITOR_EVENT_BAT_LOW

这个图表展示了电压监控模块的核心数据结构及其关系:

  1. vol_monitor_ctx_t 是核心结构体,维护电压监控的状态和配置
  2. vol_monitor_param_t 存储用户提供的配置信息,包括回调函数和阈值设置
  3. vol_monitor_event_t 定义了事件类型,用于上报电压状态
  4. 监控模块使用定时器定期检查电压,并根据配置生成相应的事件

内部函数分析

vol_monitor_param_check

vol_monitor_param_check函数用于检查配置参数的有效性。下面是其源码实现:

/**
 * @brief 检查电压监控参数有效性
 * 
 * 该函数验证配置参数的合法性,检查以下几个方面:
 * 1. 必要的回调函数是否提供(init、deinit、vol_get)
 * 2. 频率设置是否合理(read_freq > 0, report_freq >= 0)
 * 3. 电压阈值设置是否合理(阈值非负,且低电量阈值小于满电量阈值)
 * 
 * @param config 要检查的配置参数
 * @return bool 参数有效返回true,否则返回false
 */
static bool vol_monitor_param_check(vol_monitor_param_t *config)
{
    // 检查必要的回调函数是否提供
    if (config->init == NULL) {
        ESP_LOGE(TAG, "init NULL");
        return false;
    }
    if (config->deinit == NULL) {
        ESP_LOGE(TAG, "deinit NULL");
        return false;
    }
    if (config->vol_get == NULL) {
        ESP_LOGE(TAG, "vol_get NULL");
        return false;
    }
    
    // 检查参数有效性
    if (config->read_freq <= 0) {
        ESP_LOGE(TAG, "Read freq <= 0");
        return false;
    }
    if (config->report_freq < 0) {
        ESP_LOGE(TAG, "report freq < 0");
        return false;
    }
    if (config->vol_full_threshold < 0 ) {
        ESP_LOGE(TAG, "vol_full_threshold < 0");
        return false;
    }
    if (config->vol_low_threshold < 0 ) {
        ESP_LOGE(TAG, "vol_low_threshold < 0");
        return false;
    }
    
    // 检查阈值逻辑
    if (config->vol_full_threshold != 0 && config->vol_low_threshold >= config->vol_full_threshold) {
        ESP_LOGE(TAG, "vol_low_threshold >= vol_full_threshold");
        return false;
    }
    return true;
}

这个函数虽然简短,但在电压监控模块中扮演着重要角色,它确保用户提供的配置参数符合预期,防止因参数错误导致的运行时异常。

vol_check_timer_hdlr

vol_check_timer_hdlr是电压监控的核心函数,作为定时器回调定期执行。下面是其源码实现:

/**
 * @brief 电压检查定时器回调函数
 * 
 * 该函数是电压监控的核心,由定时器定期调用,完成以下主要操作:
 * 1. 调用用户提供的电压读取函数获取当前电压
 * 2. 根据报告频率设置决定是否触发定期报告事件
 * 3. 检查电压是否低于低电量阈值,触发低电量事件
 * 4. 检查电压是否高于满电量阈值,触发满电量事件
 * 
 * 函数使用互斥锁保护共享数据访问,防止并发问题
 * 为避免重复报告,低电量和满电量状态会通过标志位记录
 * 
 * @param arg 回调函数参数,实际类型为vol_monitor_ctx_t指针
 */
static void vol_check_timer_hdlr(void *arg)
{
    vol_monitor_ctx_t *vol_monitor = (vol_monitor_ctx_t *)arg;

    if (vol_monitor == NULL || vol_monitor->event_cb == NULL || vol_monitor->config->user_data == NULL) {
        return;
    }

    mutex_lock(vol_monitor->mutex);

    // 获取当前电压
    int voltage = vol_monitor->config->vol_get(vol_monitor->config->user_data);

    // 处理定期报告
    if (vol_monitor->report_start != 0 && ++vol_monitor->read_cnt % vol_monitor->report_start == 0) {
        vol_monitor->read_cnt = 0;
        vol_monitor->event_cb(VOL_MONITOR_EVENT_FREQ_REPORT, (void *)voltage, vol_monitor->user_ctx);
    }

    // 处理低电量事件
    if (vol_monitor->config->vol_low_threshold != 0) {
        if (vol_monitor->low_reported == false && voltage <= vol_monitor->config->vol_low_threshold) {
            vol_monitor->event_cb(VOL_MONITOR_EVENT_BAT_LOW, (void *)voltage, vol_monitor->user_ctx);
            vol_monitor->low_reported = true;
        } else if (voltage > vol_monitor->config->vol_low_threshold) {
            vol_monitor->low_reported = false;
        }
    }

    // 处理满电量事件
    if (vol_monitor->config->vol_full_threshold != 0) {
        if (vol_monitor->full_reported == false && voltage >= vol_monitor->config->vol_full_threshold) {
            vol_monitor->event_cb(VOL_MONITOR_EVENT_BAT_FULL, (void *)voltage, vol_monitor->user_ctx);
            vol_monitor->full_reported = true;
        } else if (voltage < vol_monitor->config->vol_full_threshold) {
            vol_monitor->full_reported = false;
        }
    }
    mutex_unlock(vol_monitor->mutex);
}

该函数是电压监控模块的核心组件,通过定时器定期调用,实现了电压采样、状态判断和事件触发的主要逻辑。它使用互斥锁保护共享数据,避免并发访问问题,并通过状态标志位避免重复触发同一事件。

创建与销毁函数分析

vol_monitor_create

vol_monitor_create函数用于创建电压监控实例,分配必要的资源。下面是其源码实现:

/**
 * @brief 创建电压监控实例
 * 
 * 该函数完成以下主要操作:
 * 1. 分配电压监控实例内存
 * 2. 检查配置参数有效性
 * 3. 调用用户提供的初始化函数
 * 4. 创建互斥锁确保线程安全
 * 5. 创建和启动定时器,用于定期检查电池电压
 * 
 * 所有资源创建失败时会进行适当的清理,避免资源泄漏
 * 
 * @param config 配置参数,包含电压读取函数、报告频率、阈值等信息
 * @return vol_monitor_handle_t 成功返回电压监控实例句柄,失败返回NULL
 */
vol_monitor_handle_t vol_monitor_create(vol_monitor_param_t *config)
{
    // 检查配置参数是否为NULL
    AUDIO_NULL_CHECK(TAG, config, return NULL);

    // 分配电压监控实例内存
    vol_monitor_ctx_t *vol_monitor = audio_calloc(1, sizeof(vol_monitor_ctx_t));
    AUDIO_MEM_CHECK(TAG, vol_monitor, return NULL);
    
    // 检查参数有效性
    if (!vol_monitor_param_check(config)) {
        goto error;
    }
    
    // 保存配置并调用初始化函数
    vol_monitor->config = config;
    vol_monitor->config->init(vol_monitor->config->user_data);
    
    // 创建互斥锁
    vol_monitor->mutex = mutex_create();
    
    /* 初始化定时器 */
    if (vol_monitor->config->read_freq > 0) {
        // 定义定时器配置
        const esp_timer_create_args_t timer_args = {
            .callback = vol_check_timer_hdlr,  // 定时器回调函数
            .arg = vol_monitor,                // 回调函数参数
            .dispatch_method = ESP_TIMER_TASK, // 调度方式
            .name = "report",                  // 定时器名称
        };
        
        // 创建并启动定时器
        if (esp_timer_create(&timer_args, &vol_monitor->check_timer) != ESP_OK
            || esp_timer_start_periodic(vol_monitor->check_timer, vol_monitor->config->read_freq * 1000 * 1000) != ESP_OK) {
            goto error;
        }
    }

    return vol_monitor;

// 错误处理部分
error:
    ESP_LOGE(TAG, "vol_monitor_create failed");
    // 释放已创建的资源
    if (vol_monitor->check_timer != NULL) {
        esp_timer_delete(vol_monitor->check_timer);
    }
    if (vol_monitor->mutex) {
        mutex_destroy(vol_monitor->mutex);
    }
    if (vol_monitor) {
        free(vol_monitor);
    }
    return NULL;
}

下面的时序图展示了 vol_monitor_create 函数的执行流程:

应用程序 vol_monitor_create vol_monitor_param_check 内存管理 用户初始化函数(init) FreeRTOS API ESP Timer API 调用(config) 参数检查 audio_calloc(分配实例内存) 返回vol_monitor vol_monitor_param_check(检查参数) 返回检查结果 config->>init(user_data) 初始化完成 mutex_create(创建互斥锁) 返回mutex esp_timer_create(创建定时器) 返回check_timer esp_timer_start_periodic(启动定时器) 返回启动状态 跳转到error处理 alt [定时器创建- 或启动失败- ] alt [read_freq > 0] 返回vol_monitor 跳转到error处理 esp_timer_delete(如果已创建) mutex_destroy(如果已创建) free(释放实例内存) 返回NULL alt [参数检查成功] [参数检查失败] 应用程序 vol_monitor_create vol_monitor_param_check 内存管理 用户初始化函数(init) FreeRTOS API ESP Timer API

这个时序图清晰地展示了 vol_monitor_create 函数的执行流程,包括参数检查、内存分配、用户初始化函数调用、互斥锁创建、定时器配置以及错误处理的完整过程。通过这个图可以直观地理解函数内部的调用关系和数据流向。

vol_monitor_destroy

vol_monitor_destroy函数用于销毁电压监控实例,释放所有资源。下面是其源码实现:

/**
 * @brief 销毁电压监控实例并释放所有资源
 * 
 * 该函数完成以下主要操作:
 * 1. 停止并删除电压检查定时器
 * 2. 调用用户提供的反初始化函数
 * 3. 销毁互斥锁
 * 4. 释放电压监控实例内存
 * 
 * 函数确保所有在vol_monitor_create中分配的资源都被正确释放
 * 
 * @param handle 电压监控句柄
 * @return esp_err_t 成功返回ESP_OK,失败返回错误码
 */
esp_err_t vol_monitor_destroy(vol_monitor_handle_t handle)
{
    // 检查句柄是否有效
    AUDIO_NULL_CHECK(TAG, handle, return ESP_ERR_INVALID_ARG);
    
    // 将句柄转换为内部实现类型
    vol_monitor_ctx_t *vol_monitor = (vol_monitor_ctx_t *)handle;
    
    // 停止并删除定时器
    if (vol_monitor->check_timer != NULL) {
        esp_timer_stop(vol_monitor->check_timer);
        esp_timer_delete(vol_monitor->check_timer);
        vol_monitor->check_timer = NULL;
    }
    
    // 调用用户反初始化函数
    vol_monitor->config->deinit(vol_monitor->config->user_data);
    
    // 销毁互斥锁
    if (vol_monitor->mutex) {
        mutex_destroy(vol_monitor->mutex);
    }
    
    // 释放实例内存
    if (vol_monitor) {
        free(vol_monitor);
    }
    
    ESP_LOGI(TAG, "vol monitor destroyed");
    return ESP_OK;
}

下面的时序图展示了 vol_monitor_destroy 函数的执行流程:

应用程序 vol_monitor_destroy ESP Timer API 用户反初始化函数(deinit) FreeRTOS API 内存管理 调用(handle) 参数检查 esp_timer_stop(停止定时器) 停止完成 esp_timer_delete(删除定时器) 删除完成 config->>deinit(user_data) 反初始化完成 mutex_destroy(销毁互斥锁) 销毁完成 free(释放实例内存) 释放完成 返回ESP_OK 返回ESP_ERR_INVALID_ARG alt [句柄有效] [句柄无效] 应用程序 vol_monitor_destroy ESP Timer API 用户反初始化函数(deinit) FreeRTOS API 内存管理

这个函数是 vol_monitor_create 的配对函数,负责清理所有分配的资源,防止资源泄漏。它停止并删除定时器,调用用户提供的反初始化函数,销毁互斥锁,并释放实例内存,确保系统资源得到完全回收。

资源管理总结

电压监控模块的创建与销毁函数遵循了ESP-ADF组件的通用设计模式:

  1. 资源分配:通过create函数分配所有必要的资源,包括内存、系统对象和硬件资源
  2. 参数验证:在分配资源前进行严格的参数检查,确保配置有效
  3. 错误处理:在创建过程中任何步骤失败都会触发清理流程,释放已分配的资源
  4. 资源回收:通过destroy函数释放所有分配的资源,与create函数配对使用
  5. 状态保护:使用互斥锁等机制确保资源访问的线程安全性

这种设计确保了模块的健壮性和可靠性,防止资源泄漏和并发访问问题,使电压监控模块能够在嵌入式系统中安全高效地运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

omnibots

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值