1. 物联网设备程序测试框架架构
框架架构图
┌─────────────────────────────────────────────────────────────┐
│ 应用程序层 (Application Layer) │
├─────────────────────────────────────────────────────────────┤
│ main.c - 测试框架控制器 │
│ ├─ 状态监控线程 │
│ ├─ 用户交互线程 │
│ ├─ 事件处理线程 │
│ └─ 性能测试线程 │
├─────────────────────────────────────────────────────────────┤
│ 共享内存接口层 (Shared Memory Interface) │
├─────────────────────────────────────────────────────────────┤
│ sharememory_interface.h - 接口定义 │
│ sharememory.c - 实现 │
├─────────────────────────────────────────────────────────────┤
│ Linux内核层 (Kernel Layer) │
├─────────────────────────────────────────────────────────────┤
│ 共享内存空间 (Shared Memory Space) │
│ └─ IPC机制 (System V IPC) │
└─────────────────────────────────────────────────────────────┘
共享内存地址空间树形结构
共享内存空间 (128字节)
├── [0] SDCARD_DOMAIN (4字节) - SD卡状态
├── [1] UDISK_DOMAIN (4字节) - U盘状态
├── [2] RENDER_DOMAIN (4字节) - 渲染状态
├── [3] AIRPLAY_DOMAIN (4字节) - AirPlay状态
├── [4] ATALK_DOMAIN (4字节) - ATalk状态
├── [5] LOCALPLAYER_DOMAIN (4字节)- 本地播放器状态
├── [6] VR_DOMAIN (4字节) - 语音识别状态
├── [7] BT_HS_DOMAIN (4字节) - 蓝牙电话状态
├── [8] BT_AVK_DOMAIN (4字节) - 蓝牙音乐状态
├── [9] LAPSULE_DOMAIN (4字节) - 胶囊状态
├── [10] TONE_DOMAIN (4字节) - 提示音状态
├── [11] MUSICPLAYER_DOMAIN (4字节)-音乐播放器状态
├── [12] CUSTOM_DOMAIN (4字节) - 自定义状态
└── 剩余空间 (76字节) - 预留扩展
sharememory_interface.h - 接口定义
#ifndef __SHARE_MEMORY_HEAD__ // 防止头文件重复包含的宏定义
#define __SHARE_MEMORY_HEAD__
#ifdef __cplusplus // 如果是C++编译器
extern "C" { // 使用C语言的链接规范,确保C++中能正确链接
#endif
/**
* @brief 表示对应域的状态值
*/
typedef enum { // 定义模块状态枚举
/**
* @brief 错误状态
*/
STATUS_ERROR = -1, // 错误状态,值为-1
/**
* @brief 表示应用已关闭
*/
STATUS_SHUTDOWN, // 应用关闭状态,值为0(自动递增)
/**
* @brief 应用已启动,等待客户端连接
*/
STATUS_RUNNING, // 运行状态,等待客户端连接
/**
* @brief 设备处于拔出状态
*/
STATUS_EXTRACT, // 设备拔出状态
/**
* @brief 设备处于插入状态
*/
STATUS_INSERT, // 设备插入状态
/**
* @brief 已与客户端建立链接,处于播放状态
*/
STATUS_PLAYING, // 播放状态
/**
* @brief 已与客户端建立链接,处于暂停状态
*/
STATUS_PAUSE, // 暂停状态
/**
* @brief 等待事件响应完成
*/
WAIT_RESPONSE, // 等待响应状态
/**
* @brief 事件响应完成
*/
RESPONSE_DONE, // 响应完成状态
/**
* @brief 事件响应完成,但事件源应暂停
*/
RESPONSE_PAUSE, // 响应暂停状态
/**
* @brief 事件响应完成,但失败
*/
RESPONSE_CANCEL, // 响应取消状态
/**
* @brief 状态数量统计
*/
STATUS_MAX, // 状态枚举的最大值,用于边界检查
} module_status;
/**
* @brief 共享内存操作的索引域
*/
typedef enum { // 定义内存域枚举
UNKNOWN_DOMAIN, /**< 未知域 */
SDCARD_DOMAIN, /**< SD卡插拔状态域 */
UDISK_DOMAIN, /**< U盘插拔状态域 */
RENDER_DOMAIN, /**< 渲染状态域 */
AIRPLAY_DOMAIN, /**< airplay状态域 */
ATALK_DOMAIN, /**< atalk状态域 */
LOCALPLAYER_DOMAIN, /**< 本地播放器状态域 */
VR_DOMAIN, /**< 语音识别状态域*/
BT_HS_DOMAIN, /**< 蓝牙电话域 */
BT_AVK_DOMAIN, /**< 蓝牙音乐域 */
LAPSULE_DOMAIN, /**< 胶囊域 */
TONE_DOMAIN, /**< 提示音域(提示音计数,非播放状态) */
MUSICPLAYER_DOMAIN, /**< 音乐播放器状态域 */
CUSTOM_DOMAIN, /**< 自定义域 */
MAX_DOMAIN, /**< 域数量统计 */
} memory_domain;
/**
* @brief 通过枚举值获取对应的枚举字符串
* 通常仅用于调试
*
* 设计模式分析:使用字符串表模式,将枚举值与字符串映射,便于调试和日志输出
* 性能分析:O(1)时间复杂度,直接数组索引访问
*/
extern char *module_status_str[]; // 模块状态字符串数组声明
/**
* @brief 获取当前状态数量
* 通常仅用于调试
*
* 性能分析:O(1)时间复杂度,返回常量值
*/
extern int get_status_cnt(void); // 获取状态数量的函数声明
/**
* @brief 根据共享内存的索引号,获取对应域的字符串
* 通常仅用于调试
*
* 设计模式分析:使用字符串表模式
* 性能分析:O(1)时间复杂度,直接数组索引访问
*/
extern char *memory_domain_str[]; // 内存域字符串数组声明
/**
* @brief 获取当前域的数量
* 通常仅用于调试
*
* 性能分析:O(1)时间复杂度,返回常量值
*/
extern int get_domain_cnt(void); // 获取域数量的函数声明
/**
* @brief 共享内存初始化,在操作共享内存前必须调用一次
*
* @return 成功返回0,错误返回-1
*
* 设计模式分析:使用单例模式,确保共享内存只被初始化一次
* 性能分析:系统调用开销,但只需在程序启动时调用一次
*/
extern int share_mem_init(void); // 共享内存初始化函数声明
/**
* @brief 清空共享内存,将所有域的值设置为零
*
* @return 成功返回0,错误返回-1
*
* 性能分析:O(n)时间复杂度,n为域的数量,需要遍历所有域
*/
extern int share_mem_clear(void); // 清空共享内存函数声明
/**
* @brief 销毁共享内存,每次调用share_mem_init后,
* 当不再使用共享内存API时,调用此函数
*
* @return 成功返回0,错误返回-1
*
* 设计模式分析:资源获取即初始化(RAII)模式的反向操作
* 性能分析:系统调用开销,释放共享内存资源
*/
extern int share_mem_destory(void); // 销毁共享内存函数声明
/**
* @brief 获取指定索引域的值
*
* @param domain [in] 指定的索引
* @param status [out] 状态值
*
* @return 成功返回0,错误返回-1
*
* 设计模式分析:使用访问者模式,提供统一的接口访问不同域
* 性能分析:O(1)时间复杂度,直接内存访问,性能高效
*/
extern int share_mem_get(memory_domain domain, module_status * status); // 获取共享内存值函数声明
/**
* @brief 获取指定索引域的值
*
* @param domain [in] 指定的索引
*
* @return 成功返回模块状态,错误返回STATUS_ERROR
*
* 性能分析:O(1)时间复杂度,直接返回值,比指针参数版本更简洁
*/
extern module_status share_mem_statusget(memory_domain domain); // 获取共享内存状态函数声明
/**
* @brief 设置指定索引域的值
*
* @param domain [in] 指定的索引
* @param status [in] 状态值
*
* @return 成功返回0,错误返回-1
*
* 设计模式分析:使用观察者模式,状态改变可能通知相关模块
* 性能分析:O(1)时间复杂度,直接内存写入操作
*/
extern int share_mem_set(memory_domain domain, module_status status); // 设置共享内存值函数声明
/**
* @brief 获取当前活跃的应用
* @attention 处于暂停状态的应用或正在使用DSP的应用
* 都是活跃的。如果没有应用是活跃的,
* 将得到未知域
*
* @param domain [out] 活跃的应用
*
* @return 成功返回0,错误返回-1
*
* 设计模式分析:使用策略模式,根据特定算法确定活跃应用
* 性能分析:O(n)时间复杂度,需要遍历所有域来确定活跃应用
*/
extern int share_mem_get_active_domain(memory_domain * domain); // 获取活跃域函数声明
#ifdef __cplusplus // 如果是C++编译器
} // 结束C语言链接规范
#endif
#endif /* __SHARE_MEMORY_HEAD__ 结束头文件 */
sharememory.c - 实现
/* ************************************************************************
* 文件名: sharememory.c
* 描述: 共享内存实现文件
* 版本: 1.0
* 创建时间:
* 修订: 无
* 编译器: gcc
* 作者: xllv (),
* 公司:
* ************************************************************************/
#include <sys/types.h> // 系统类型定义
#include <sys/ipc.h> // IPC相关定义
#include <sys/file.h> // 文件锁定相关
#include <sys/shm.h> // 共享内存操作
#include <stdio.h> // 标准输入输出
#include <string.h> // 字符串操作
#include <stdlib.h> // 标准库函数
#include <error.h> // 错误处理
#include <errno.h> // 错误号定义
#include <unistd.h> // UNIX标准函数
#include <sys/shm.h> // 共享内存操作(重复包含,但无害)
#include "sharememory_interface.h" // 共享内存接口头文件
#define SHAREMEM_KEY "/" // 共享内存键值路径
#define SHAREMEM_ID 100 // 共享内存ID
#define SHAREMEM_SIZE 128 // 共享内存大小(字节)
#define SHAREMEM_LOCK "/var/run/sharemem.lock" // 锁文件路径
// 调试宏定义(当前被注释)
#define SHAREMEM_DEBUG(x,y...) //{printf("[ %s : %s : %d] ",__FILE__, __func__, __LINE__); printf(x,##y); printf("\n");}
// 错误输出宏定义
#define SHAREMEM_ERROR(x,y...) {printf("[ %s : %s : %d] ",__FILE__, __func__, __LINE__); printf(x,##y); printf("\n");}
static int shm_id = 0; // 共享内存ID静态变量
static int *shm_addr = NULL; // 共享内存地址指针
/**
* @brief 通过状态值枚举值获取对应枚举名字符串,增强可读性
*
* 设计模式分析:使用字符串表模式,将枚举值与描述字符串映射
* 性能分析:O(1)时间复杂度,直接数组索引访问
*/
char *module_status_str[] = { // 模块状态字符串数组定义
[STATUS_SHUTDOWN] = "STATUS_SHUTDOWN", // 关闭状态
[STATUS_RUNNING] = "STATUS_RUNNING", // 运行状态
[STATUS_EXTRACT] = "STATUS_EXTRACT", // 拔出状态
[STATUS_INSERT] = "STATUS_INSERT", // 插入状态
[STATUS_PLAYING] = "STATUS_PLAYING", // 播放状态
[STATUS_PAUSE] = "STATUS_PAUSE", // 暂停状态
[WAIT_RESPONSE] = "WAIT_RESPONSE", // 等待响应
[RESPONSE_DONE] = "RESPONSE_DONE", // 响应完成
[RESPONSE_PAUSE] = "RESPONSE_PAUSE", // 响应暂停
[RESPONSE_CANCEL] = "RESPONSE_CANCEL", // 响应取消
[STATUS_MAX] = "STATUS_MAX", // 状态最大值
NULL, // 结束标记
};
/**
* @brief 通过共享内存域索号引获取对应域名字的字符串,增强可读性
*
* 设计模式分析:使用字符串表模式
* 性能分析:O(1)时间复杂度,直接数组索引访问
*/
char *memory_domain_str[] = { // 内存域字符串数组定义
[UNKNOWN_DOMAIN] = "UNKNOWN_DOMAIN", // 未知域
[SDCARD_DOMAIN] = "SDCARD_DOMAIN", // SD卡域
[UDISK_DOMAIN] = "UDISK_DOMAIN", // U盘域
[RENDER_DOMAIN] = "RENDER_DOMAIN", // 渲染域
[AIRPLAY_DOMAIN] = "AIRPLAY_DOMAIN", // AirPlay域
[ATALK_DOMAIN] = "ATALK_DOMAIN", // ATalk域
[LOCALPLAYER_DOMAIN] = "LOCALPLAYER_DOMAIN",// 本地播放器域
[VR_DOMAIN] = "VR_DOMAIN", // 语音识别域
[BT_HS_DOMAIN] = "BT_HS_DOMAIN", // 蓝牙电话域
[BT_AVK_DOMAIN] = "BT_AVK_DOMAIN", // 蓝牙音乐域
[LAPSULE_DOMAIN] = "LAPSULE_DOMAIN", // 胶囊域
[TONE_DOMAIN] = "TONE_DOMAIN", // 提示音域
[CUSTOM_DOMAIN] = "CUSTOM_DOMAIN", // 自定义域
[MUSICPLAYER_DOMAIN] = "MUSICPLAYER_DOMAIN",// 音乐播放器域
[MAX_DOMAIN] = "MAX_DOMAIN", // 域最大值
NULL, // 结束标记
};
/**
* @brief 获取域的数量
*
* @return 域的数量
*
* 性能分析:O(1)时间复杂度,直接返回常量
*/
int get_domain_cnt(void) // 获取域数量函数
{
return MAX_DOMAIN; // 返回最大域数量
}
/**
* @brief 获取状态的数量
*
* @return 状态的数量
*
* 性能分析:O(1)时间复杂度,直接返回常量
*/
int get_status_cnt(void) // 获取状态数量函数
{
return STATUS_MAX; // 返回最大状态数量
}
/**
* @brief 共享内存加锁
*
* @return 成功返回文件描述符,失败返回-1
*
* 设计模式分析:使用互斥锁模式确保线程安全
* 性能分析:系统调用开销,但保证了数据一致性
*/
static int share_mem_lock(void) // 共享内存加锁函数
{
int ret = -1; // 返回值
int sharemem_lock_fd = -1; // 锁文件描述符
// 打开或创建锁文件
sharemem_lock_fd = open(SHAREMEM_LOCK, O_RDWR | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (sharemem_lock_fd < 0) { // 打开失败
fprintf(stderr, "%s: open %s fail: %s\n", __func__, SHAREMEM_LOCK, strerror(errno));
return sharemem_lock_fd; // 返回错误
}
ret = flock(sharemem_lock_fd, LOCK_EX); // 获取排他锁
if (ret) { // 加锁失败
fprintf(stderr, "%s: flock failed.\n", __func__);
close(sharemem_lock_fd); // 关闭文件
sharemem_lock_fd = -1; // 重置文件描述符
return sharemem_lock_fd; // 返回错误
}
return sharemem_lock_fd; // 返回锁文件描述符
}
/**
* @brief 共享内存解锁
*
* @param lock 锁文件描述符
* @return 总是返回0
*
* 性能分析:系统调用开销,关闭文件描述符
*/
static int share_mem_unlock(int lock) // 共享内存解锁函数
{
if (lock >= 0) // 检查锁文件描述符有效性
close(lock); // 关闭文件(自动释放锁)
return 0; // 返回成功
}
/**
* @brief 获取共享内存地址
*
* @return 成功返回共享内存地址,失败返回(void*)-1
*
* 设计模式分析:使用工厂模式创建/获取共享内存
* 性能分析:系统调用开销,但只需在初始化时调用
*/
static void *share_mem_addr(void) // 获取共享内存地址函数
{
key_t ipckey; // IPC键值
ipckey = ftok(SHAREMEM_KEY, SHAREMEM_ID); // 生成IPC键值
shm_id = shmget(ipckey, SHAREMEM_SIZE, IPC_CREAT | 0666); // 创建/获取共享内存
if (-1 == shm_id) { // 共享内存操作失败
SHAREMEM_ERROR("shmget error %s", strerror(errno));
return (void *)-1; // 返回错误
}
shm_addr = shmat(shm_id, 0, 0); // 附加共享内存到进程地址空间
if ((int *)-1 == shm_addr) { // 附加失败
SHAREMEM_ERROR("shmat error %s", strerror(errno));
if (-1 == shmctl(shm_id, IPC_RMID, NULL)) { // 尝试删除共享内存
SHAREMEM_ERROR("shmctl error %s", strerror(errno));
return (void *)-1; // 返回错误
}
return (void *)-1; // 返回错误
}
return shm_addr; // 返回共享内存地址
}
/**
* @brief 共享内存初始化
*
* @return 成功返回0,失败返回-1
*
* 设计模式分析:使用单例模式,确保只初始化一次
* 性能分析:系统调用开销,但只需在程序启动时调用一次
*/
int share_mem_init(void) // 共享内存初始化函数
{
int tmpfd = -1; // 临时文件描述符
// 检查锁文件是否存在,不存在则创建
if (access(SHAREMEM_LOCK, 0)) { // 检查文件是否存在
tmpfd = creat(SHAREMEM_LOCK, S_IRWXU | S_IROTH | S_IXOTH | S_ISUID); // 创建锁文件
if (tmpfd < 0) { // 创建失败
printf("%s: Create %s FAILED: %s.\n", __func__, SHAREMEM_LOCK, strerror(errno));
return -1; // 返回错误
} else {
close(tmpfd); // 关闭文件
}
}
if (NULL != shm_addr) { // 检查是否已经初始化
SHAREMEM_DEBUG("Has already been initialized");
return 0; // 已初始化,直接返回成功
}
shm_addr = share_mem_addr(); // 获取共享内存地址
if ((int *)-1 == shm_addr) { // 获取失败
return -1; // 返回错误
}
return 0; // 返回成功
}
/**
* @brief 清空共享内存
*
* @return 成功返回0,失败返回-1
*
* 性能分析:O(n)时间复杂度,n为域的数量,需要遍历所有域
*/
int share_mem_clear(void) // 清空共享内存函数
{
int lock = -1; // 锁文件描述符
int i = 0; // 循环计数器
if ((lock = share_mem_lock()) < 0) { // 获取锁
SHAREMEM_ERROR("sharemem lock error.\n");
return -1; // 返回错误
}
if (NULL == shm_addr) { // 检查共享内存是否初始化
SHAREMEM_ERROR("The shared memory is not initialized");
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
share_mem_init(); // 确保共享内存已初始化
// 遍历所有域,设置为关闭状态
for (i = 0; i < get_domain_cnt(); i++) {
if (memory_domain_str[i]) // 检查域字符串是否存在
shm_addr[i] = (int)STATUS_SHUTDOWN; // 设置为关闭状态
}
share_mem_unlock(lock); // 释放锁
return 0; // 返回成功
}
/**
* @brief 获取指定域的状态值
*
* @param domain 域索引
* @param status 状态值输出参数
* @return 成功返回0,失败返回-1
*
* 设计模式分析:使用访问者模式提供统一访问接口
* 性能分析:O(1)时间复杂度,直接内存访问
*/
int share_mem_get(memory_domain domain, module_status * status) // 获取共享内存值函数
{
int lock = -1; // 锁文件描述符
if ((lock = share_mem_lock()) < 0) { // 获取锁
SHAREMEM_ERROR("sharemem lock error.\n");
return -1; // 返回错误
}
if (NULL == shm_addr) { // 检查共享内存是否初始化
SHAREMEM_ERROR("The shared memory is not initialized");
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
*status = (module_status) shm_addr[domain]; // 读取指定域的状态值
share_mem_unlock(lock); // 释放锁
return 0; // 返回成功
}
/**
* @brief 获取指定域的状态值(简化版本)
*
* @param domain 域索引
* @return 状态值
*
* 性能分析:O(1)时间复杂度,但包含函数调用和锁操作开销
*/
module_status share_mem_statusget(memory_domain domain) // 获取共享内存状态函数
{
module_status status = STATUS_ERROR; // 默认错误状态
share_mem_get(domain, &status); // 调用获取函数
return status; // 返回状态值
}
/**
* @brief 设置指定域的状态值
*
* @param domain 域索引
* @param status 状态值
* @return 成功返回0,失败返回-1
*
* 设计模式分析:使用观察者模式,状态改变可能通知相关模块
* 性能分析:O(1)时间复杂度,直接内存写入
*/
int share_mem_set(memory_domain domain, module_status status) // 设置共享内存值函数
{
int lock = -1; // 锁文件描述符
if ((lock = share_mem_lock()) < 0) { // 获取锁
SHAREMEM_ERROR("sharemem lock error.\n");
return -1; // 返回错误
}
if (NULL == shm_addr) { // 检查共享内存是否初始化
SHAREMEM_ERROR("The shared memory is not initialized");
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
shm_addr[domain] = (int)status; // 设置指定域的状态值
share_mem_unlock(lock); // 释放锁
return 0; // 返回成功
}
/**
* @brief 销毁共享内存
*
* @return 成功返回0,失败返回-1
*
* 设计模式分析:资源清理模式,确保资源正确释放
* 性能分析:系统调用开销,释放系统资源
*/
int share_mem_destory(void) // 销毁共享内存函数
{
struct shmid_ds shm_status; // 共享内存状态结构
int lock = -1; // 锁文件描述符
if ((lock = share_mem_lock()) < 0) { // 获取锁
SHAREMEM_ERROR("sharemem lock error.\n");
return -1; // 返回错误
}
if (NULL == shm_addr) { // 检查共享内存是否初始化
SHAREMEM_DEBUG("The shared memory is not initialized");
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
if (-1 == shmdt(shm_addr)) { // 分离共享内存
SHAREMEM_ERROR("shmdt error %s", strerror(errno));
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
if (-1 == shmctl(shm_id, IPC_STAT, &shm_status)) { // 获取共享内存状态
SHAREMEM_ERROR("shmdt error %s", strerror(errno));
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
if (0 == shm_status.shm_nattch) { // 检查是否没有其他进程附加
if (-1 == shmctl(shm_id, IPC_RMID, NULL)) { // 删除共享内存
SHAREMEM_ERROR("shmctl error %s", strerror(errno));
share_mem_unlock(lock); // 释放锁
return -1; // 返回错误
}
}
shm_addr = NULL; // 重置共享内存地址指针
share_mem_unlock(lock); // 释放锁
return 0; // 返回成功
}
/**
* @brief 获取当前活跃的域
*
* @param domain 活跃域输出参数
* @return 成功返回0,失败返回-1
*
* 设计模式分析:使用策略模式确定活跃应用
* 性能分析:O(n)时间复杂度,需要检查所有可能的活动域
*/
int share_mem_get_active_domain(memory_domain * domain) // 获取活跃域函数
{
module_status status; // 状态变量
*domain = UNKNOWN_DOMAIN; // 默认设为未知域
int count = 0; // 活跃域计数器
// 检查蓝牙电话域
if (0 == share_mem_get(BT_HS_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = BT_HS_DOMAIN; // 设置为蓝牙电话域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查蓝牙音乐域
if (0 == share_mem_get(BT_AVK_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = BT_AVK_DOMAIN; // 设置为蓝牙音乐域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查AirPlay域
if (0 == share_mem_get(AIRPLAY_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = AIRPLAY_DOMAIN; // 设置为AirPlay域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查ATalk域
if (0 == share_mem_get(ATALK_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = ATALK_DOMAIN; // 设置为ATalk域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查渲染域
if (0 == share_mem_get(RENDER_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = RENDER_DOMAIN; // 设置为渲染域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查本地播放器域
if (0 == share_mem_get(LOCALPLAYER_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = LOCALPLAYER_DOMAIN; // 设置为本地播放器域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查语音识别域
if (0 == share_mem_get(VR_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = VR_DOMAIN; // 设置为语音识别域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查胶囊域
if (0 == share_mem_get(LAPSULE_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = LAPSULE_DOMAIN; // 设置为胶囊域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查自定义域
if (0 == share_mem_get(CUSTOM_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = CUSTOM_DOMAIN; // 设置为自定义域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
// 检查音乐播放器域
if (0 == share_mem_get(MUSICPLAYER_DOMAIN, &status)) {
if (STATUS_PLAYING == status || STATUS_PAUSE == status) {
*domain = MUSICPLAYER_DOMAIN; // 设置为音乐播放器域
count++; // 计数增加
}
} else {
return -1; // 返回错误
}
if (count > 1) { // 检查是否有多个活跃域
SHAREMEM_ERROR("More than one application is active");
return -1; // 返回错误
}
return 0; // 返回成功
}
2. main.c 测试程序
/* ************************************************************************
* 文件名: main.c
* 描述: 物联网设备共享内存测试框架主程序
* 版本: 2.0
* 创建时间: 2024
* 修订: 支持多平台交叉编译
* 编译器: gcc/g++
* 作者:
* 许可证: MIT
* ************************************************************************/
#include <stdio.h> // 标准输入输出
#include <stdlib.h> // 标准库函数
#include <string.h> // 字符串操作
#include <unistd.h> // UNIX标准函数
#include <pthread.h> // 线程支持
#include <signal.h> // 信号处理
#include <time.h> // 时间函数
#include "sharememory_interface.h" // 共享内存接口头文件
// 全局变量定义
static volatile int running = 1; // 程序运行控制标志
/**
* @brief 信号处理函数
* @param sig 信号编号
*
* 设计模式:观察者模式 - 监听系统信号
* 性能:O(1)时间复杂度,直接设置标志位
*/
void signal_handler(int sig) // 信号处理函数
{
printf("\n接收到信号 %d,正在关闭程序...\n", sig); // 输出信号信息
running = 0; // 设置运行标志为0
}
/**
* @brief 状态监控线程函数
* @param arg 线程参数
* @return 线程退出状态
*
* 设计模式:生产者-消费者模式 - 持续监控状态变化
* 性能:周期性监控,CPU占用可控
*/
void* status_monitor_thread(void* arg) // 状态监控线程
{
printf("状态监控线程启动\n"); // 线程启动提示
while (running) { // 主循环
printf("\n=== 设备状态监控 ===\n"); // 监控标题
// 遍历所有域并显示状态
for (memory_domain domain = UNKNOWN_DOMAIN; domain < MAX_DOMAIN; domain++) {
module_status status = share_mem_statusget(domain); // 获取状态
if (status != STATUS_ERROR) { // 检查状态有效性
printf("域: %-20s 状态: %-15s (%d)\n", // 格式化输出
memory_domain_str[domain],
module_status_str[status],
status);
}
}
// 获取活跃域
memory_domain active_domain;
if (share_mem_get_active_domain(&active_domain) == 0) { // 获取活跃域
printf("当前活跃域: %s\n", memory_domain_str[active_domain]); // 输出活跃域
} else {
printf("当前活跃域: 无或冲突\n"); // 错误提示
}
sleep(2); // 监控间隔2秒
}
printf("状态监控线程退出\n"); // 线程退出提示
return NULL; // 返回空指针
}
/**
* @brief 模拟设备事件线程
* @param arg 线程参数
* @return 线程退出状态
*
* 设计模式:状态机模式 - 模拟设备状态变化
* 性能:随机事件生成,模拟真实场景
*/
void* device_simulator_thread(void* arg) // 设备模拟线程
{
printf("设备模拟线程启动\n"); // 线程启动提示
srand(time(NULL)); // 随机数种子初始化
while (running) { // 主循环
// 随机选择一个域和状态进行模拟
memory_domain domain = rand() % MAX_DOMAIN; // 随机选择域
module_status status = rand() % STATUS_MAX; // 随机选择状态
if (domain != UNKNOWN_DOMAIN && status != STATUS_ERROR) { // 有效性检查
printf("模拟事件: 设置 %s 为 %s\n", // 事件提示
memory_domain_str[domain],
module_status_str[status]);
if (share_mem_set(domain, status) == 0) { // 设置状态
printf("事件设置成功\n"); // 成功提示
} else {
printf("事件设置失败\n"); // 失败提示
}
}
sleep(3 + rand() % 5); // 随机间隔3-7秒
}
printf("设备模拟线程退出\n"); // 线程退出提示
return NULL; // 返回空指针
}
/**
* @brief 用户交互线程
* @param arg 线程参数
* @return 线程退出状态
*
* 设计模式:命令模式 - 处理用户输入命令
* 性能:阻塞式输入,低CPU占用
*/
void* user_interface_thread(void* arg) // 用户交互线程
{
printf("用户交互线程启动\n"); // 线程启动提示
printf("命令列表:\n"); // 命令提示
printf(" 1 - 清空共享内存\n"); // 命令1
printf(" 2 - 显示所有状态\n"); // 命令2
printf(" 3 - 设置SD卡状态\n"); // 命令3
printf(" 4 - 设置蓝牙状态\n"); // 命令4
printf(" q - 退出程序\n"); // 退出命令
char input[256]; // 输入缓冲区
while (running) { // 主循环
printf("\n请输入命令: "); // 输入提示
if (fgets(input, sizeof(input), stdin)) { // 读取输入
switch (input[0]) { // 命令分发
case '1': // 清空共享内存
printf("执行清空共享内存...\n"); // 执行提示
if (share_mem_clear() == 0) { // 调用清空函数
printf("清空成功\n"); // 成功提示
} else {
printf("清空失败\n"); // 失败提示
}
break;
case '2': // 显示所有状态
printf("当前所有状态:\n"); // 显示标题
for (int i = 0; i < get_domain_cnt(); i++) { // 遍历域
module_status status = share_mem_statusget(i); // 获取状态
if (status != STATUS_ERROR && memory_domain_str[i]) { // 有效性检查
printf(" %s: %s\n", memory_domain_str[i], // 输出状态
module_status_str[status]);
}
}
break;
case '3': // 设置SD卡状态
printf("设置SD卡状态 - 输入状态值 (0-9): "); // 状态输入提示
if (fgets(input, sizeof(input), stdin)) { // 读取状态
int status_val = atoi(input); // 转换状态值
if (status_val >= 0 && status_val < STATUS_MAX) { // 范围检查
share_mem_set(SDCARD_DOMAIN, status_val); // 设置状态
printf("SD卡状态已设置为: %s\n", // 成功提示
module_status_str[status_val]);
} else {
printf("无效的状态值\n"); // 错误提示
}
}
break;
case '4': // 设置蓝牙状态
printf("设置蓝牙音乐状态 - 输入状态值 (0-9): "); // 状态输入提示
if (fgets(input, sizeof(input), stdin)) { // 读取状态
int status_val = atoi(input); // 转换状态值
if (status_val >= 0 && status_val < STATUS_MAX) { // 范围检查
share_mem_set(BT_AVK_DOMAIN, status_val); // 设置状态
printf("蓝牙音乐状态已设置为: %s\n", // 成功提示
module_status_str[status_val]);
} else {
printf("无效的状态值\n"); // 错误提示
}
}
break;
case 'q': // 退出程序
printf("退出程序...\n"); // 退出提示
running = 0; // 设置运行标志
break;
default: // 未知命令
printf("未知命令,请重新输入\n"); // 错误提示
break;
}
}
}
printf("用户交互线程退出\n"); // 线程退出提示
return NULL; // 返回空指针
}
/**
* @brief 性能测试线程
* @param arg 线程参数
* @return 线程退出状态
*
* 设计模式:策略模式 - 执行不同的性能测试策略
* 性能:压力测试,评估系统性能
*/
void* performance_test_thread(void* arg) // 性能测试线程
{
printf("性能测试线程启动\n"); // 线程启动提示
int test_count = 0; // 测试计数器
const int MAX_TESTS = 1000; // 最大测试次数
while (running && test_count < MAX_TESTS) { // 测试循环
// 性能测试:连续设置和获取状态
clock_t start_time = clock(); // 开始时间
for (int i = 0; i < 100; i++) { // 执行100次操作
memory_domain test_domain = (i % (MAX_DOMAIN - 1)) + 1; // 测试域
module_status test_status = (i % (STATUS_MAX - 1)) + 1; // 测试状态
share_mem_set(test_domain, test_status); // 设置状态
module_status read_status = share_mem_statusget(test_domain); // 读取状态
if (test_status != read_status) { // 验证一致性
printf("性能测试错误: 写入 %d 读取 %d\n", // 错误输出
test_status, read_status);
}
}
clock_t end_time = clock(); // 结束时间
double duration = ((double)(end_time - start_time)) / CLOCKS_PER_SEC; // 计算耗时
printf("性能测试 %d: 100次操作耗时 %.6f 秒\n", // 性能输出
test_count + 1, duration);
test_count++; // 计数器递增
sleep(5); // 测试间隔5秒
}
printf("性能测试线程退出\n"); // 线程退出提示
return NULL; // 返回空指针
}
/**
* @brief 主函数
* @param argc 参数个数
* @param argv 参数数组
* @return 程序退出码
*
* 设计模式:模板方法模式 - 定义程序执行流程
* 性能:程序入口,资源管理和线程调度
*/
int main(int argc, char *argv[]) // 主函数
{
printf("=== 物联网设备共享内存测试框架 ===\n"); // 程序标题
printf("版本: 2.0\n"); // 版本信息
printf("作者: AI Assistant\n"); // 作者信息
printf("编译时间: %s %s\n", __DATE__, __TIME__); // 编译信息
// 注册信号处理
signal(SIGINT, signal_handler); // Ctrl+C信号
signal(SIGTERM, signal_handler); // 终止信号
// 初始化共享内存
printf("初始化共享内存...\n"); // 初始化提示
if (share_mem_init() != 0) { // 调用初始化函数
fprintf(stderr, "共享内存初始化失败\n"); // 错误输出
return -1; // 返回错误码
}
printf("共享内存初始化成功\n"); // 成功提示
// 创建线程
pthread_t monitor_thread, simulator_thread, ui_thread, perf_thread; // 线程变量
printf("创建监控线程...\n"); // 线程创建提示
if (pthread_create(&monitor_thread, NULL, status_monitor_thread, NULL) != 0) { // 创建监控线程
fprintf(stderr, "监控线程创建失败\n"); // 错误输出
return -1; // 返回错误码
}
printf("创建设备模拟线程...\n"); // 线程创建提示
if (pthread_create(&simulator_thread, NULL, device_simulator_thread, NULL) != 0) { // 创建设备模拟线程
fprintf(stderr, "设备模拟线程创建失败\n"); // 错误输出
return -1; // 返回错误码
}
printf("创建用户交互线程...\n"); // 线程创建提示
if (pthread_create(&ui_thread, NULL, user_interface_thread, NULL) != 0) { // 创建用户交互线程
fprintf(stderr, "用户交互线程创建失败\n"); // 错误输出
return -1; // 返回错误码
}
printf("创建性能测试线程...\n"); // 线程创建提示
if (pthread_create(&perf_thread, NULL, performance_test_thread, NULL) != 0) { // 创建性能测试线程
fprintf(stderr, "性能测试线程创建失败\n"); // 错误输出
return -1; // 返回错误码
}
printf("所有线程创建成功,测试框架运行中...\n"); // 成功提示
printf("按Ctrl+C或输入'q'退出程序\n"); // 退出提示
// 等待线程结束
pthread_join(ui_thread, NULL); // 等待用户交互线程
pthread_join(monitor_thread, NULL); // 等待监控线程
pthread_join(simulator_thread, NULL); // 等待设备模拟线程
pthread_join(perf_thread, NULL); // 等待性能测试线程
// 清理共享内存
printf("清理共享内存...\n"); // 清理提示
if (share_mem_destory() != 0) { // 调用销毁函数
fprintf(stderr, "共享内存销毁失败\n"); // 错误输出
} else {
printf("共享内存清理成功\n"); // 成功提示
}
printf("测试框架正常退出\n"); // 退出提示
return 0; // 返回成功
}
3. 改进的 Makefile(支持多平台)
# Makefile for IoT Shared Memory Test Framework
# 支持多平台交叉编译: x86_64, aarch64, arm
# 编译器配置
# 默认使用系统GCC
CC = gcc
CXX = g++
# 可选交叉编译器
CROSS_COMPILE =
# 架构检测
ARCH ?= $(shell uname -m)
# 根据架构设置编译器
ifeq ($(ARCH), aarch64)
# ARM64架构
CC = aarch64-linux-gnu-gcc
CXX = aarch64-linux-gnu-g++
CROSS_COMPILE = aarch64-linux-gnu-
else ifeq ($(ARCH), armv7l)
# ARM32架构
CC = arm-linux-gnueabihf-gcc
CXX = arm-linux-gnueabihf-g++
CROSS_COMPILE = arm-linux-gnueabihf-
else ifneq ($(findstring arm, $(ARCH)),)
# 其他ARM变种
CC = arm-linux-gnu-gcc
CXX = arm-linux-gnu-g++
CROSS_COMPILE = arm-linux-gnu-
endif
# 编译目标
TARGET = iot_shared_mem_test # 最终可执行文件名
SHARED_LIB = libsharemem.so # 共享库文件名
# 源码文件
SRCS = main.c sharememory.c # 源文件列表
OBJS = $(SRCS:.c=.o) # 对象文件列表
# 头文件路径
INCLUDES = -I. # 头文件搜索路径
# 编译选项
CFLAGS = -Wall -Wextra -Werror -O2 -g -fPIC $(INCLUDES) # C编译标志
# -Wall: 开启所有警告
# -Wextra: 额外警告
# -Werror: 警告视为错误
# -O2: 优化级别2
# -g: 调试信息
# -fPIC: 位置无关代码(用于共享库)
CXXFLAGS = $(CFLAGS) -std=c++11 # C++编译标志,使用C++11标准
# 链接选项
LDFLAGS = -lpthread -lrt # 链接标志
# -lpthread: POSIX线程库
# -lrt: 实时扩展库
# 共享库链接选项
SHARED_LDFLAGS = -shared -Wl,-soname,$(SHARED_LIB) # 共享库链接标志
# 安装路径
PREFIX = /usr/local # 默认安装前缀
BINDIR = $(PREFIX)/bin # 可执行文件安装目录
LIBDIR = $(PREFIX)/lib # 库文件安装目录
INCDIR = $(PREFIX)/include # 头文件安装目录
# 默认目标: 编译所有
all: $(TARGET) $(SHARED_LIB) # 默认目标
# 主目标链接
$(TARGET): $(OBJS) # 可执行文件依赖对象文件
$(CC) -o $@ $(OBJS) $(LDFLAGS) # 链接生成可执行文件
@echo "编译完成: $(TARGET) for $(ARCH)" # 完成提示
# 共享库编译
$(SHARED_LIB): sharememory.o # 共享库依赖sharememory对象文件
$(CC) $(SHARED_LDFLAGS) -o $@ $^ $(LDFLAGS) # 创建共享库
@echo "共享库编译完成: $(SHARED_LIB)" # 完成提示
# 模式规则: 从.c文件编译.o文件
%.o: %.c # C源文件编译规则
$(CC) $(CFLAGS) -c $< -o $@ # 编译C文件
# 模式规则: 从.cpp文件编译.o文件
%.o: %.cpp # C++源文件编译规则
$(CXX) $(CXXFLAGS) -c $< -o $@ # 编译C++文件
# 清理目标
clean: # 清理编译产物
rm -f $(TARGET) $(SHARED_LIB) $(OBJS) # 删除目标文件和库
rm -f *.so *.a # 删除其他库文件
@echo "清理完成" # 清理完成提示
# 安装目标
install: all # 安装目标依赖all
mkdir -p $(BINDIR) $(LIBDIR) $(INCDIR) # 创建安装目录
cp $(TARGET) $(BINDIR)/ # 安装可执行文件
cp $(SHARED_LIB) $(LIBDIR)/ # 安装共享库
cp sharememory_interface.h $(INCDIR)/ # 安装头文件
@echo "安装完成到 $(PREFIX)" # 安装完成提示
# 卸载目标
uninstall: # 卸载目标
rm -f $(BINDIR)/$(TARGET) # 删除可执行文件
rm -f $(LIBDIR)/$(SHARED_LIB) # 删除共享库
rm -f $(INCDIR)/sharememory_interface.h # 删除头文件
@echo "卸载完成" # 卸载完成提示
# 调试版本
debug: CFLAGS += -DDEBUG -O0 -g3 # 调试版本编译选项
debug: $(TARGET) # 调试版本目标
@echo "调试版本编译完成" # 调试版本完成提示
# 跨平台编译目标
x86: # x86平台编译
$(MAKE) ARCH=x86_64 # 设置架构并编译
arm: # ARM平台编译
$(MAKE) ARCH=arm CC=arm-linux-gnu-gcc # ARM编译
aarch64: # ARM64平台编译
$(MAKE) ARCH=aarch64 CC=aarch64-linux-gnu-gcc # ARM64编译
# 静态分析
analyze: CFLAGS += -fanalyzer # 开启静态分析
analyze: clean all # 静态分析目标
@echo "静态分析完成" # 分析完成提示
# 帮助信息
help: # 帮助目标
@echo "可用目标:" # 帮助标题
@echo " all - 编译所有目标 (默认)" # all目标说明
@echo " clean - 清理编译产物" # clean目标说明
@echo " install - 安装到系统" # install目标说明
@echo " uninstall - 卸载" # uninstall目标说明
@echo " debug - 编译调试版本" # debug目标说明
@echo " x86 - 编译x86版本" # x86目标说明
@echo " arm - 编译ARM版本" # arm目标说明
@echo " aarch64 - 编译ARM64版本" # aarch64目标说明
@echo " analyze - 静态代码分析" # analyze目标说明
@echo " help - 显示此帮助信息" # help目标说明
# 伪目标声明
.PHONY: all clean install uninstall debug x86 arm aarch64 analyze help # 伪目标列表
# 依赖关系
main.o: main.c sharememory_interface.h # main.o依赖关系
sharememory.o: sharememory.c sharememory_interface.h # sharememory.o依赖关系
4. 使用说明
编译和运行
# 默认编译(自动检测架构)
make
# 编译特定平台
make x86 # x86_64平台
make arm # ARM平台
make aarch64 # ARM64平台
# 编译调试版本
make debug
# 运行测试程序
./iot_shared_mem_test
# 清理编译文件
make clean
# 安装到系统
sudo make install
测试框架功能
-
状态监控:实时监控所有设备域的状态变化
-
设备模拟:自动模拟设备状态变化事件
-
用户交互:支持手动命令控制设备状态
-
性能测试:压力测试共享内存性能
-
多平台支持:支持x86、ARM、ARM64架构
共享内存管理机制
-
地址分配:每个域占用4字节,按枚举顺序排列
-
并发控制:使用文件锁确保多进程安全访问
-
资源管理:自动初始化和清理共享内存
-
状态一致性:通过锁机制保证读写操作的原子性
这个测试框架为物联网设备提供了一个完整的共享内存管理和测试解决方案。