序:
最近在看一本关于设计模式的<<head first 设计模式>>,感觉不错,根据看到的一些东西,回头看看自己原来写的代码,做了一次:知行合一。此书看后,感觉对原来很多东西有所感悟,就差去家当和尚。此书可以反复研读,已经计划看完遍之后,再过一段时间再看。不过模式再好,也是需要拿使用的。
正文:
本人在mtk平台上做串口应用有一段时间了,从最初要实现的文件传输,到现在外接各种设备,串口应用已经多达四种。
最初初现文件传输时,只是简单的在mtk层数据接收处理函数中添加文件传输处理的接口。
如下:
HandleMMIReceivedData(int port ,char *pData,int nDataLen) { //处理文件传输 Deal_FileTransmit(pData,nDataLen); }
因为最初只使用一个端口,只有一个功能模块。
之后,串口应用又添加了,打印,AT等,串口从原来一个变成现在的三个,之后的代码变成:
typedef enum { PHONE_WAIT=1, /*待机状态*/ PHONE_DATA_BACKUP=2, /*数据备份状态 */ PHONE_CALL=7, /*通话状态*/ //…………………其它状态 PHONE_NULL }PHONE_STATUS_E; /************************************************************************/ /* 取得话机状态 */ /************************************************************************/ int GetPhoneStatus_by_port(unsigned char m_port ) { return g_phoneStatus_byport[m_port]; } /************************************************************************/ /* 设置话机状态 */ /************************************************************************/ void SetPhoneStatus_by_port(int nStatus,unsigned char m_port ) { g_phoneStatus_byport[m_port] = nStatus; } /************************************************************************/ /*串口数据处理 */ /************************************************************************/ HandleMMIReceivedData(int port,char *pData,int nDataLen) { if ( port==g_print_uartPort &&nPhoneStatus ==PHONE_PRINT )//打印 { Print_Handle_RecvData(m_RBuf,buffLen); } else if ( port==g_at_uartPort &&nPhoneStatus ==PHONE_AT )//AT { ATCOMM_Handle_RecvData(m_RBuf,buffLen); } //.......其它功能的处理 }
主要思想是通过当时的端口号和终端状态进行相应的数据处理。
问题:以后如果还需要添中新的功能模块,就需要在终端状态和数据处理中添加相应的代码,虽然添加的代码量不大,但要所设计模式的原则:
找出应用中可能需变化之处,把他们独立开来,不要和那些不需要变化的代码混在一起。
如果说MTK层的数据处理HandleMMIReceivedData就应该是不需要变化之处,每次的功能模块就是可能需要变化之处。那么就是要把他们独立开发。从几种设计模式应用中可以找出比较类似的一个模式,那就是观察者模式。
在MTK中有一个是叫做消息注册,其本质也应该就是观察者模式。如果使用原来的消息注册,有一个问题就是一个应用要对应一个msg_id,那么通用性也不好。那就在原来消息注册的基础上,我们自己来实际观察者模式。以下是主要实现的测试代码:
// MessageTest.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <string.h> typedef void (*FuncPtr) (unsigned char *,unsigned int); typedef struct { int port ; //接收数据的端口 FuncPtr pHandleRecvFun; //处理接收到的数据的函数指针 }xn_uart_handle_recv_struct; #define XN_MAX_UART_NUM 4 //现在终端最大的串口数 typedef struct { int nUartCount ; xn_uart_handle_recv_struct uartRecvStru[XN_MAX_UART_NUM]; }xn_uart_handle_mode_struct; xn_uart_handle_mode_struct g_uartHandleRecv; /* 本次处理主要是使用观察者模式,主要动作是注册和注销 */ void XINO_TRACE(char *funName,char *tip) { printf("fun is [%-30s],tip is: %s \r\n",funName,tip); } //初始化 void XN_UartHandle_Init(void) { XINO_TRACE("XN_UartHandle_Init","init data "); memset((void *)&g_uartHandleRecv.nUartCount,0,sizeof(g_uartHandleRecv)); } int XN_UartCheckPort(int nIndex) { if( 0>nIndex || (nIndex+1)>XN_MAX_UART_NUM ) //输入的序号不在正确的范围内 { XINO_TRACE("XN_UartCheckPort","return -1"); return -1; } XINO_TRACE("XN_UartCheckPort","return 1"); return 1; } //查找 /******************************************************************************* * 函数名称: xn_uart_findbyport * * 功能描述: 通过端口号查找 * * 参数说明: * * * 返 回 值: >=0 找到了返回这个端口号在列表中的序号 =-1 在列表中不存在 * * 历史记录: * 日期: 2009-1-16 修改人linhai * 描述: 创建 *******************************************************************************/ int xn_uart_findbyport(int nport) { int i = 0; for(i=0;i<g_uartHandleRecv.nUartCount && i<XN_MAX_UART_NUM ;i++) { int nUartPort = g_uartHandleRecv.uartRecvStru[i].port; if(nUartPort==nport) { printf("fun is [xn_uart_findbyport] find by port %d index = %d\r\n ",nport,i); return i; } } XINO_TRACE("xn_uart_findbyport","return -1"); return -1; } //更新 void xn_uart_update_callHandleFun(int nIndex,xn_uart_handle_recv_struct mUartRecvStru) { g_uartHandleRecv.uartRecvStru[nIndex].port = mUartRecvStru.port; g_uartHandleRecv.uartRecvStru[nIndex].pHandleRecvFun = mUartRecvStru.pHandleRecvFun; printf("fun is [xn_uart_update_callHandleFun] update data index=%d port=%d after count is =%d\r\n", nIndex,mUartRecvStru.port,g_uartHandleRecv.nUartCount); } //添加 void xn_uart_add_callHandleFun(xn_uart_handle_recv_struct mUartRecvStru) { int port = mUartRecvStru.port; int nIndex = 0; XINO_TRACE("xn_uart_add_callHandleFun","add data"); if(XN_UartCheckPort(port)==-1) { return; } nIndex = xn_uart_findbyport(port); if(nIndex==-1) { if(g_uartHandleRecv.nUartCount>XN_MAX_UART_NUM) { return; } nIndex = g_uartHandleRecv.nUartCount; g_uartHandleRecv.nUartCount++; } xn_uart_update_callHandleFun(nIndex,mUartRecvStru); } //删除 void xn_uart_dele_callHandleFun(int nPort) { int nIdex = -1; XINO_TRACE("xn_uart_dele_callHandleFun","dele by port"); if(XN_UartCheckPort(nPort)==-1) { return; } nIdex = xn_uart_findbyport(nPort); if(nIdex==-1) { return; } else { int i = nIdex; for(i;i<g_uartHandleRecv.nUartCount;i++) { g_uartHandleRecv.uartRecvStru[i].port =g_uartHandleRecv.uartRecvStru[i+1].port ; g_uartHandleRecv.uartRecvStru[i].pHandleRecvFun = g_uartHandleRecv.uartRecvStru[i+1].pHandleRecvFun; } g_uartHandleRecv.uartRecvStru[i].port =0; g_uartHandleRecv.uartRecvStru[i].pHandleRecvFun =NULL; g_uartHandleRecv.nUartCount--; } printf("xn_uart_dele_callHandleFun: g_uartHandleRecv.count = %d \r\n",g_uartHandleRecv.nUartCount); } /******************************************************************************* * 函数名称: xn_uart_subscribe * * 功能描述: 注册 * * 参数说明: * * * 返 回 值: void * * 历史记录: * 日期: 2009-1-16 修改人linhai * 描述: 创建 *******************************************************************************/ void xn_uart_subscribe( int nport ,FuncPtr pFun ) { xn_uart_handle_recv_struct subscriber; subscriber.port = nport; subscriber.pHandleRecvFun = pFun; xn_uart_add_callHandleFun(subscriber); } /******************************************************************************* * 函数名称: xn_uart_desubscribe * * 功能描述: 注销 * * 参数说明: * * * 返 回 值: void * * 历史记录: * 日期: 2009-1-16 修改人linhai * 描述: 创建 *******************************************************************************/ void xn_uart_desubscribe(int port) { xn_uart_dele_callHandleFun(port); } void HandleMMIReceivedData(unsigned char port) { FuncPtr mFun = NULL; int nIndex = 0; nIndex = xn_uart_findbyport(port); if (nIndex!=-1) { mFun = g_uartHandleRecv.uartRecvStru[nIndex].pHandleRecvFun; mFun((unsigned char *)"hello world",strlen("hello world")); } } void fun(unsigned char *data,unsigned int datalen) { printf("\r\n handlerecv data fun %s\r\n",data); return; } int main(int argc, char* argv[]) { //--------------------- xn_uart_handle_recv_struct temp; //-------------------------- XN_UartHandle_Init(); // printf("----------------begin test-----------------\n"); temp.port =1; temp.pHandleRecvFun = fun; xn_uart_subscribe(temp); HandleMMIReceivedData(1); xn_uart_desubscribe(temp.port); printf("----------------end test-----------------\n"); // return 0; }
附件是上面代码的工程。
第三次修改的代码和原来相比修变不大,其本质也就是建立一个数据组,里面保存端口所对应的函数指针。在接收到数据后,从相应的端口中取出相应的函数指针。现在世界太平了,今后如果再有什么新的串口需求,只要专注了模块的功能实现,在需要使用的地方调用注册和注销接口。这样模块之间的独立性就实现了。