在嵌入式单片机开发过程中难免会遇到一种情况(根据不同的状态执行不同的对应处理程序,这一技术称之为消息地图):通过一个通道如串口接收到不同的命令,而这个时候就需要根据不同的命令去处理对应的任务。如果需要实现这个情况可以用if/else、switch-case去实现,但是我觉得这些都不是特别方便后续的扩展和管理,后面了接到了函数指针,发现可以通过遍历数组的方式匹配任务ID再调用对应的函数指针,那么就可以通过一张类似表格的东西去管理任务了。
首先构建一个消息地图结构体:
typedef struct MsgMap_Item /* 消息地图成员 */
{
uint8_t TaskId; /* 任务ID */
uint8_t (*fnTaskHandle)(uint8_t *, uint16_t); /* 任务处理函数指针 */
} MsgMap_Item_t;
typedef struct MsgMap /* 消息地图 */
{
uint16_t MsgMapItemSize; /* 消息成员大小 */
uint16_t MsgMapItemNum; /* 消息地图数量 */
MsgMap_Item_t *pMsgMapItem; /* 消息地图成员列表 */
}MsgMap_t;
再建立一张消息地图表格
/* 消息地图成员列表 */
MsgMap_Item_t TaskMsgMap[] = {
{ .TaskId = 0x01, /* 任务1 */
.fnTaskHandle = fun1,
},
{
.TaskId = 0x02, /* 任务2 */
.fnTaskHandle = fun2,
},
};
/* 消息地图列表管理 */
MsgMapTable = {
.MsgMapItemSize = sizeof(TaskMsgMap[0]),
.MsgMapItemNum = sizeof(TaskMsgMap)/sizeof(TaskMsgMap[0]),
.pMsgMapItem = TaskMsgMap,
};
最后编写一个消息地图遍历函数
/**
* @brief search message map table.
* @param pMsgMap message map table.
* @param TaskId task id.
* @param pData task data.
* @param DataLen task data length.
* @retval None
*/
uint8_t MsgMap_Search(MsgMap_t *pMsgMap, uint8_t TaskId, void *pData, uint16_t DataLen)
{
MsgMap_Item_t MsgMapItem = {0};
for (uint16_t i = 0; i < pMsgMap->MsgMapItemNum; i++)
{
MsgMapItem = pMsgMap->pMsgMapItem[i];
if (MsgMapItem.TaskId != TaskId)
{
continue; /* 任务ID不匹配 */
}
if (MsgMapItem.fnTaskHandle == NULL)
{
continue; /* 未指定处理函数 */
}
return MsgMapItem.fnTaskHandle(pData, DataLen);
}
return false;
}
以上纯属个人见解,有误之处还望大家指正。