通信协议解析神器:函数指针
在解析通信协议时我们通常一个实体功能命令对应一个实体功能函数;每增加一个功能,则多编写一个功能函数,除此之外,还需要在协议解析处改动,需要改很多地方,非常的不方便.以下介绍一下利用函数指针,实现回调函数形式解析协议。
用户只需要增加协议的cmd、用户函数、将两个参数注册进注册表中进行邦定,当相应的协议到来时即可调用相应的用户函数,极大拓展了程序的可扩展性。
#ifndef _FListTemp_H_
#define _FListTemp_H_
/* 防止uint8_t缺省报错 */
#ifndef uint8_t
#define uint8_t unsigned char
#endif
/* 防止uint16_t缺省报错 */
#ifndef uint8_t
#define uint8_t unsigned char
#endif
/* 最大可解析函数数目 */
#define MAX_RESOLVABLE_COUNT 10
typedef enum CMDFuncitonType_tag
{
NORMAL, // 执行成功
ERR_OVER_MAX_LIMIT, // 错误-超出最大限制
RESERVED_0 // 保留
}CMDFuncitonType_t;
typedef struct CMDFunction_tag
{
uint8_t UserCMD; // 用户命令
void ( *FunctionPoint ) // 功能函数指针
(
uint8_t *UserAppData, // 用户数据
uint16_t UserAppDataLength // 用户数据长度
);
}CMDFunction_t;
extern CMDFuncitonType_t CMDFunction_CheckAndRun
(
CMDFunction_t *UserAppStructLiset, // 用户注册列表
uint8_t StructListLength, // 用户列表成员数
uint8_t userCMD, // 用户命令
uint8_t *userDataPoint, // 用户数据
uint16_t userDataLength // 用户数据长度
);
#endif
接着是c文件代码,此代码包含使用方法的介绍,在文件末:
#include “FListTemp.h”
CMDFuncitonType_t CMDFunction_CheckAndRun
(
CMDFunction_t *UserStructAppList, // 用户注册列表
uint8_t StructListLength, // 用户列表成员数
uint8_t userCMD, // 用户命令
uint8_t *userDataPoint, // 用户数据
uint16_t userDataLength // 用户数据长度
)
{
uint8_t i = 0;
if( StructListLength > MAX_RESOLVABLE_COUNT )
{
return ERR_OVER_MAX_LIMIT;
}
for( i = 0; i < StructListLength; i++ )
{
if( userCMD == UserAppStructList[i].UserCMD )
{
userAppStructList[i].FunctionPoint( userDataPoint, userDataLength );
break;
}
}
return NORMAL;
}
/*********************** 用例 *********************/
/*
#include “FListTemp.h”
// 用户命令表
#define CMD1 0x01
#define CMD2 0x02
#define CMD3 0x03
#define CMD4 0x04
#define CMD5 0x05
// 用户函数声明
void UserAppFunction1( uint8_t * userAppData, uint16_t userAppDataLength );
void UserAppFunction2( uint8_t * userAppData, uint16_t userAppDataLength );
void UserAppFunction3( uint8_t * userAppData, uint16_t userAppDataLength );
void UserAppFunction4( uint8_t * userAppData, uint16_t userAppDataLength );
void UserAppFunction5( uint8_t * userAppData, uint16_t userAppDataLength );
// 用户注册列表
CMDFunction_t UserAppList[] =
{
{ CMD1, UserAppFunction1},
{ CMD2, UserAppFunction2},
{ CMD3, UserAppFunction3},
{ CMD4, UserAppFunction4},
{ CMD5, UserAppFunction5},
}
// 你的工程函数
int main( void )
{
// 用户命令
uint8_t UserAppCMD = 0x01
// 用户数据
uint8_t UserAppData[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
While(1)
{
CMDFunction_CheckAndRun
(
UserAppList, // 用户注册列表
5, // 用户列表成员数
UserCMD , // 用户命令
UserAppData, // 用户数据
Sizeof(UserAppData) // 用户数据长度
);
UserAppCMD++;
if( UserAppCMD >= 7)
{
UserAppCMD = 1;
}
}
}
*/
这两个文件只是这种方法的模板,只要你愿你可以为你的所有模块功能都按照用例那样配置属于每个模块的独有回调群。由于以上代码是用world手撸的(公司外网限制,没办法),如有错误还请留言,如有更好的改良方案,欢迎留言讨论!