目录
ESP-ADF esp_dispatcher组件之periph_service子模块资源管理函数详解
版本信息: v2.7-65-gcf908721
本章节分析的源码位于
/components/esp_dispatcher/periph_service.c
文件
数据管理概述
periph_service子模块的数据管理函数负责管理服务实例的用户数据和控制服务行为。这些函数提供了在服务实例和应用程序之间共享数据的机制,以及通过IO控制命令改变服务行为的能力。数据管理机制使得服务能够保存状态信息并根据应用程序的需求调整行为。
数据管理主要包括以下几个方面:
- 用户数据存储:通过
periph_service_set_data
和periph_service_get_data
函数,应用程序可以在服务实例中存储和获取自定义数据 - 服务行为控制:通过
periph_service_ioctl
函数,应用程序可以向服务发送命令,控制服务的行为
这些功能是服务与应用程序之间数据交换和行为调整的核心机制,为开发灵活的外设应用提供了强大支持。
数据管理函数分析
periph_service_set_data
periph_service_set_data
函数用于设置服务实例的用户数据。下面是其源码实现:
/**
* @brief 设置服务实例的用户数据
*
* 该函数允许应用程序在服务实例中存储自定义数据
* 用户数据可以是任意类型,通过void指针传递
*
* @param handle 外设服务实例句柄
* @param data 要存储的用户数据指针
* @return esp_err_t 成功返回ESP_OK,失败返回错误码
*/
esp_err_t periph_service_set_data(periph_service_handle_t handle, void *data)
{
// 参数检查
AUDIO_NULL_CHECK(TAG, handle, return ESP_ERR_INVALID_ARG);
// 获取服务实例
periph_service_impl_t *impl = (periph_service_impl_t *) handle;
// 设置用户数据
impl->user_data = data;
return ESP_OK;
}
下面的时序图展示了 periph_service_set_data
函数的执行流程:
periph_service_set_data
函数的实现非常简单,它检查参数有效性,然后将应用程序提供的数据保存在服务实例的 user_data
字段中。这个函数允许应用程序为每个服务实例关联一个自定义的数据结构,用于存储服务相关的状态或配置信息。
periph_service_get_data
periph_service_get_data
函数用于获取服务实例的用户数据。下面是其源码实现:
/**
* @brief 获取服务实例的用户数据
*
* 该函数从服务实例中获取之前通过periph_service_set_data设置的用户数据
*
* @param handle 外设服务实例句柄
* @return void* 成功返回用户数据指针,失败返回NULL
*/
void *periph_service_get_data(periph_service_handle_t handle)
{
// 参数检查
AUDIO_NULL_CHECK(TAG, handle, return NULL);
// 获取服务实例
periph_service_impl_t *impl = (periph_service_impl_t *) handle;
// 返回用户数据
return impl->user_data;
}
下面的时序图展示了 periph_service_get_data
函数的执行流程:
periph_service_get_data
函数也很简单,它检查参数有效性,然后返回服务实例 user_data
字段中存储的数据指针。应用程序需要知道数据的实际类型,并进行适当的类型转换。
periph_service_ioctl
periph_service_ioctl
函数用于控制服务实例的行为。下面是其源码实现:
/**
* @brief 控制服务实例的行为
*
* 该函数通过向服务发送命令来控制服务行为
* 具体支持的命令和参数由服务实现定义
*
* @param handle 外设服务实例句柄
* @param ioctl_handle IO控制句柄,通常是具体控制目标
* @param cmd 命令码
* @param value 命令参数
* @return esp_err_t 成功返回ESP_OK或服务返回值,失败返回错误码
*/
esp_err_t periph_service_ioctl(periph_service_handle_t handle, void *ioctl_handle, int cmd, int value)
{
// 获取服务实例并进行参数检查
periph_service_impl_t *impl = (periph_service_impl_t *) handle;
AUDIO_NULL_CHECK(TAG, (handle && impl->service_ioctl), return ESP_ERR_INVALID_ARG);
// 调用服务实现提供的IO控制函数
return impl->service_ioctl(ioctl_handle, cmd, value);
}
下面的时序图展示了 periph_service_ioctl
函数的执行流程:
periph_service_ioctl
函数是一个通用的控制接口,它将控制命令转发给服务实现提供的IO控制函数。具体支持的命令和参数由服务实现定义,这种设计使得不同类型的外设服务可以提供特定的控制能力。
数据管理实际应用
用户数据的应用场景
用户数据在许多场景下都非常有用,例如:
- 状态保存:保存服务的运行状态,如蓝牙连接信息、音量级别等
- 上下文关联:将应用程序上下文与服务关联,便于在回调函数中访问
- 配置存储:存储服务的运行时配置,如特定参数设置
- 资源共享:在服务和应用程序之间共享资源,如缓冲区或处理器实例
以下是一个使用用户数据的示例:
// 定义服务自定义数据结构
typedef struct {
int volume; // 音量级别
bool mute; // 静音状态
uint32_t last_cmd_time; // 最后命令时间
int active_source; // 活动音源
} audio_service_data_t;
// 初始化服务
void init_audio_service()
{
// 创建服务
periph_service_handle_t audio_service = audio_service_create(&audio_cfg);
// 创建并初始化服务数据
audio_service_data_t *service_data = malloc(sizeof(audio_service_data_t));
service_data->volume = 50;
service_data->mute = false;
service_data->last_cmd_time = esp_timer_get_time();
service_data->active_source = AUDIO_SOURCE_DEFAULT;
// 设置服务数据
periph_service_set_data(audio_service, service_data);
// 启动服务
periph_service_start(audio_service);
}
// 回调函数
static esp_err_t audio_service_cb(periph_service_handle_t handle, periph_service_event_t *evt, void *ctx)
{
// 获取服务数据
audio_service_data_t *service_data = periph_service_get_data(handle);
// 更新最后命令时间
service_data->last_cmd_time = esp_timer_get_time();
// 处理事件
switch (evt->type) {
case AUDIO_EVENT_VOLUME_UP:
if (!service_data->mute && service_data->volume < 100) {
service_data->volume += 5;
ESP_LOGI(TAG, "Volume increased to %d", service_data->volume);
}
break;
case AUDIO_EVENT_VOLUME_DOWN:
if (!service_data->mute && service_data->volume > 0) {
service_data->volume -= 5;
ESP_LOGI(TAG, "Volume decreased to %d", service_data->volume);
}
break;
// 处理其他事件...
}
return ESP_OK;
}
IO控制的应用场景
IO控制函数提供了一种通用机制,用于向服务发送特定命令,常见场景包括:
- 配置修改:修改服务的运行参数,如音量、灵敏度等
- 模式切换:切换服务的工作模式,如蓝牙配对模式、扫描模式等
- 状态查询:查询服务的内部状态,如连接状态、电量等
- 动作触发:触发服务执行特定动作,如重启、重新扫描等
以下是一个使用IO控制的示例:
// 蓝牙服务命令定义
#define BT_IOCTL_SET_DISCOVERY_MODE 1
#define BT_IOCTL_START_DISCOVERY 2
#define BT_IOCTL_STOP_DISCOVERY 3
#define BT_IOCTL_CONNECT_DEVICE 4
#define BT_IOCTL_DISCONNECT_DEVICE 5
// 蓝牙服务类型定义
#define BT_DISCOVERY_MODE_NONE 0
#define BT_DISCOVERY_MODE_LIMITED 1
#define BT_DISCOVERY_MODE_GENERAL 2
// 模式设置示例
void set_bt_discovery_mode(periph_service_handle_t bt_service, int mode)
{
// 使用IO控制设置蓝牙发现模式
esp_err_t ret = periph_service_ioctl(bt_service, NULL, BT_IOCTL_SET_DISCOVERY_MODE, mode);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set discovery mode: %s", esp_err_to_name(ret));
}
}
// 连接设备示例
void connect_bt_device(periph_service_handle_t bt_service, bt_device_t *device)
{
// 使用IO控制连接蓝牙设备
esp_err_t ret = periph_service_ioctl(bt_service, device, BT_IOCTL_CONNECT_DEVICE, 0);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to connect device: %s", esp_err_to_name(ret));
}
}
服务实现IO控制示例
服务实现需要提供IO控制函数来处理应用程序发送的命令。下面是一个蓝牙服务IO控制函数的示例:
/**
* @brief 蓝牙服务IO控制函数示例
*/
static esp_err_t bt_service_ioctl(void *ioctl_handle, int cmd, int value)
{
esp_err_t ret = ESP_OK;
switch (cmd) {
case BT_IOCTL_SET_DISCOVERY_MODE:
// 设置蓝牙发现模式
ret = bt_set_discovery_mode(value);
break;
case BT_IOCTL_START_DISCOVERY:
// 启动蓝牙设备发现
ret = bt_start_discovery(value); // value可能表示持续时间
break;
case BT_IOCTL_STOP_DISCOVERY:
// 停止蓝牙设备发现
ret = bt_stop_discovery();
break;
case BT_IOCTL_CONNECT_DEVICE:
if (ioctl_handle) {
// 连接指定蓝牙设备
bt_device_t *device = (bt_device_t *)ioctl_handle;
ret = bt_connect_device(device);
} else {
ret = ESP_ERR_INVALID_ARG;
}
break;
case BT_IOCTL_DISCONNECT_DEVICE:
if (ioctl_handle) {
// 断开指定蓝牙设备
bt_device_t *device = (bt_device_t *)ioctl_handle;
ret = bt_disconnect_device(device);
} else {
ret = ESP_ERR_INVALID_ARG;
}
break;
default:
ESP_LOGW(TAG, "Unknown command: %d", cmd);
ret = ESP_ERR_INVALID_ARG;
break;
}
return ret;
}
数据管理在服务架构中的作用
数据管理函数在periph_service子模块的整体架构中扮演着重要角色,它们与资源管理函数、状态控制函数和回调管理函数一起,构成了完整的服务管理框架。下面的图表展示了这些函数之间的关系:
这个图表展示了periph_service子模块中各类函数的逻辑关系:
- 首先创建服务实例(
periph_service_create
) - 设置回调函数(
periph_service_set_callback
)和用户数据(periph_service_set_data
) - 启动服务(
periph_service_start
) - 服务运行阶段,通过IO控制(
periph_service_ioctl
)管理服务行为,通过回调函数(periph_service_callback
)通知事件,通过用户数据(periph_service_get_data
)共享状态 - 最后停止服务(
periph_service_stop
)并销毁服务实例(periph_service_destroy
)
通过这种设计,periph_service子模块提供了一套完整的服务管理框架,使应用程序能够以统一的方式管理各种外设服务,提高了代码的模块化程度和可维护性。