在嵌入式中结合设计模式的一个小应用【观察都模式】

12 篇文章 0 订阅

序:

      最近在看一本关于设计模式的<<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;
}

 附件是上面代码的工程。

 

       第三次修改的代码和原来相比修变不大,其本质也就是建立一个数据组,里面保存端口所对应的函数指针。在接收到数据后,从相应的端口中取出相应的函数指针。现在世界太平了,今后如果再有什么新的串口需求,只要专注了模块的功能实现,在需要使用的地方调用注册和注销接口。这样模块之间的独立性就实现了。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值