嵌入式组件-----IPC
1、什么是IPC
在做一个比较简单的项目时,我们可以使用全局变量等作为标志位进行逻辑判断,但是在功能较多的项目上时,使用全局变量作为程序间的标志位当然是不可行的,代码将会混乱且复杂,不利于解耦,因此需要使用到IPC(Interprocess communication),IPC是模块间的通信组件,主要实现的是任务之间的消息转发,广播等功能,模块功能和实现都较为简单。
2、需求分析
- 模块间的消息传递主要是一对多消息和一对一消息,所有的消息都是先经过IPC模块再进行分发,按照模块的消息发送条件判断消息最终到达的目的地
- 消息从发送模块到接收模块要求比较高的执行效率。
3、架构设计
- 使用IPC模块的其他业务模块通过IPC模块实现间接通信,解除模块之间的耦合。
IPC的通信分为同步处理和异步处理
- 使用同步处理时,接收方模块的业务可能会消耗发送方模块的时间长度
- IPC的异步处理可能会出现消息没来及消费的问题,如果阻塞则会影响生产者消息传递,并且有消息丢失的可能性。阻塞时需要短或者不阻塞,为了保证消息不丢失需要在消息队列溢出时把溢出的消息及时消费。
- IPC模块与其他模块的交互就是消息的接收和消息的转发,消息的接收可以是一个统一的接口给其他模块调用,消息的分发需要保存一张消息接收的表,表头包含模块的订阅判断函数指针。
应用场景
- 同步单播
- 同步广播
- 异步单播
- 异步广播
4、代码实现
IPC.C
#include "ipc.h"
static const IPC_MODULE_Typedef *IPC_T;
uint16_t IPC_ModNum = 0;
/**
* @brief IPC模块初始化函数
* @param ipc_t 消息接收模块表
* @param IPC_ModuleNum 消息接收模块数量
*/
void IPC_ModInit(const IPC_MODULE_Typedef *ipc_t,uint16_t IPC_ModuleNum)
{
IPC_T = ipc_t;
IPC_ModNum = IPC_ModuleNum;
}
/**
* @brief IPC消息发送
* @param RecvModId 目标模块ID,为0xFF时为所有模块
* @param MsgId 消息ID
* @param MsgParam 消息参数
*/
void IPC_SendMsg(uint32_t RecvModId,uint32_t MsgId,uint32_t *MsgParam ,uint32_t Msglen)
{
int i = 0;
if (ID_MODULE_ALL == RecvModId) //所有模块都接收的消息
{
for (i; i < IPC_ModNum; i++)
{
IPC_T[i].eventHandleFunc(MsgId, MsgParam,Msglen);
}
}
else //指定模块接收的消息
{
for (i; i < IPC_ModNum; i++)
{
if (RecvModId == IPC_T[i].mod_Id)
{
IPC_T[i].eventHandleFunc(MsgId, MsgParam,Msglen);
}
}
}
}
IPC.h
#ifndef IPC_H
#define IPC_H
#include "types.h"
#define ID_MODULE_ALL 0XFF
typedef void (*EventHandleFunc)(uint32_t MsgId,uint32_t MsgParam,uint32_t Msglen);
/*IPC模块抽象类*/
typedef struct IPC_MODUILE_Typedef_t
{
uint16_t mod_Id;
EventHandleFunc eventHandleFunc;
}IPC_MODULE_Typedef;
/*IPC消息*/
typedef struct IPC_Typedef_t
{
uint32_t msgId;
uint32_t msgParam;
uint32_t msgLen;
}IPC_Typedef;
/*IPC消息*/
/**
* @brief IPC模块初始化函数
* @param ipc_t 消息接收模块表
* @param IPC_ModuleNum 消息接收模块数量
*/
void IPC_ModInit(const IPC_MODULE_Typedef *ipc_t,uint16_t IPC_ModuleNum);
/**
* @brief IPC消息发送
* @param RecvModId 目标模块ID,为0xFF时为所有模块
* @param MsgId 消息ID
* @param MsgParam 消息参数
* @param Msglen 消息长度
*/
void IPC_SendMsg(uint32_t RecvModId,uint32_t MsgId,uint32_t *MsgParam ,uint32_t Msglen);
#endif
5、使用案例
#include "msg.h"
#include "ipc.h"
extern void mod_1_event_handle(uint32_t msg_id,uint32_t *msg_param,uint32_t len);
extern void mod_2_event_handle(uint32_t msg_id,uint32_t *msg_param,uint32_t len);
extern void mod_3_event_handle(uint32_t msg_id,uint32_t *msg_param,uint32_t len);
const IPC_MODULE_Typedef ipc_table[MOD_ID_BUTT] =
{
{MOD_ID_1,mod_1_event_handle},
{MOD_ID_2,mod_2_event_handle},
{MOD_ID_3,mod_3_event_handle},
};
void mod_ipc_init(void)
{
IPC_ModInit(ipc_table,MOD_ID_BUTT);
}
如果需要给模块2发送一个事件
IPC_SendMsg(MOD_ID_2,POWER_OFF,NULL,0);
模块2的事件处理(同步方式)
void mod_2_event_handle(uint32_t msg_id,uint32_t *msg_param,uint32_t len)
{
switch(msg_id)
{
case POWER_OFF:
//关机
break;
default:
break;
}
}
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。