1、前言
在熟悉任务调度、程序分层和模块化编程关于软件架构、分层和模块设计后,除了函数调用设计中出现的情况外,还会遇到同层模块之前如何进行消息交互,通常是应用层之间。
2、解决思路
上述情况,也可以采用回调函数的实现方式进行模块解耦,但是需要引入新的内容,即公共模块Commoon层(包含第三方功能库)。
公共模块主要有各模块都需要使用的类型定义、结构体定义、通用函数或常用宏定义等(通常属于基础类的功能,不会受功能需求和不同平台的影响)。
基于公共模块,为了解决各模块之前的数据交互,可以通过公共模块实现基础类的功能达到各应用层模块解耦的目的。
看图:
从上述看,也许有人感觉这样处理反而复杂了,直接调用不香吗?(上述人机交互模块属于被观察者,参数和其他模块属于观察者)
3、示例代码
事件通知模块头文件
#ifndef _NOTIFY_H_
#define _NOTIFY_H_
#include <stdint.h>
/**
* @brief 应用模块ID枚举定义
*
*/
typedef enum
{
NOTIFY_ID_HMI = 0, // 人机交互模块
NOTIFY_ID_SYS_PARAM, // 参数管理模块
NOTIFY_ID_TOTAL
} NotifyId_e;
/**
* @brief 事件类型枚举定义
*
*/
typedef enum
{
NOTIFY_EVENT_PARAM_UPDATE, // 参数更新事件, 对应结构体 PrramUpdateInfo_t
NOTIFY_EVENT_TOTAL
} NotifyEvent_e;
typedef struct
{
uint16_t addr;
uint32_t param;
}PrramUpdateInfo_t;
typedef int (*EventNotifyCB)(NotifyId_e id, NotifyEvent_e eEvent, const void *pData, uint32_t length);
extern void Notify_Init(void);
extern int Notify_Attach(NotifyId_e id, NotifyEvent_e eEvent, EventNotifyCB pfnCallback);
extern int Notify_Detach(NotifyId_e id, NotifyEvent_e eEvent);
extern int Notify_EventNotify(NotifyId_e id, NotifyEvent_e eEvent, const void *pData, uint32_t length);
#endif /* _NOTIFY_H_ */
事件通知模块源文件:
#include "notify.h"
#include <string.h>
static EventNotifyCB sg_pfnCallback[NOTIFY_ID_TOTAL][NOTIFY_EVENT_TOTAL];
/**
* @brief 事件初始化
*
*/
void Notify_Init(void)
{
memset(sg_pfnCallback, 0, sizeof(sg_pfnCallback));
}
/**
* @brief 添加事件监听通知
*
* @param[in] id 应用模块ID
* @param[in] eEvent 事件
* @param[in] pfnCallback 回调函数
* @return 0,成功; -1,失败
*/
int Notify_Attach(NotifyId_e id, NotifyEvent_e eEvent, EventNotifyCB pfnCallback)
{
if (id >= 0 && id < NOTIFY_ID_TOTAL && eEvent < NOTIFY_EVENT_TOTAL)
{
sg_pfnCallback[id][eEvent] = pfnCallback;
return 0;
}
return -1;
}
/**
* @brief 删除事件监听通知
*
* @param[in] id 应用模块ID
* @param[in] eEvent 事件
* @return 0,成功; -1,失败
*/
int Notify_Detach(NotifyId_e id, NotifyEvent_e eEvent)
{
if (id >= 0 && id < NOTIFY_ID_TOTAL && eEvent < NOTIFY_EVENT_TOTAL)
{
sg_pfnCallback[id][eEvent] = 0;
return 0;
}
return -1;
}
/**
* @brief 事件通知
*
* @param[in] id 应用模块ID
* @param[in] eEvent 事件类型
* @param[in] pData 消息内容
* @param[in] length 消息长度
* @return 0,成功; -1,失败
*/
int Notify_EventNotify(NotifyId_e id, NotifyEvent_e eEvent, const void *pData, uint32_t length)
{
int i;
if (eEvent < NOTIFY_EVENT_TOTAL)
{
for (i = 0; i < NOTIFY_ID_TOTAL; i++)
{
if (sg_pfnCallback[i][eEvent] != 0)
{
sg_pfnCallback[i][eEvent](id, eEvent, pData, length);
}
}
return 0;
}
return -1;
}
参数应用层模块:
#include "notify.h"
static int Param_OnNotifyProc(NotifyId_e id, NotifyEvent_e eEvent, const void *pData, uint32_t length);
void Param_Init(void)
{
Notify_Attach(NOTIFY_ID_SYS_PARAM, NOTIFY_EVENT_PARAM_UPDATE, Param_OnNotifyProc);
}
// 事件回调处理
int Param_OnNotifyProc(NotifyId_e id, NotifyEvent_e eEvent, const void *pData, uint32_t length)
{
switch (eEvent)
{
case NOTIFY_EVENT_PARAM_UPDATE:
{
PrramUpdateInfo_t *pInfo = (PrramUpdateInfo_t *)pData;
SaveParam(pInfo->addr, pInfo->param);// 保存参数
}
break;
default:
break;
}
return 0;
}
人机交互应用层模块
#include "notify.h"
void Hmi_Init(void)
{
}
// 需要保存参数
int Hmi_SaveProc(void)
{
ParamUpdateInfo_t info;
info.addr = 5;
info.param = 20;
Notify_EventNotify(NOTIFY_ID_HMI, NOTIFY_EVENT_HMI_UPDATE, &info, sizeof(ParamUpdateInfo_t));
}