您的位置:首页 > 其它

gsm 收发短信 打电话

2014-07-22 22:44 525 查看
/*************************************************************************************************************
 * 文件名:			SIM900.c
 * 功能:			STM32 SIM900底层驱动函数
 * 作者:			cp1300@139.com
 * 创建时间:		2013-10-16
 * 最后修改时间:	2013-10-16
 * 详细:			GSM_CDMA发送短信等
					2014-04-22:添加字节超时与总超时
*************************************************************************************************************/
#include "system.h"
#include "usart.h"
#include "SIM900.h"
#include "delay.h"
#include "string.h"
#include "ucos_ii.h"
#include "unicode_gbk.h"
#include "main.h"

//SIM900通信缓冲区
u8	SIM900_Buff[SIM900_BUFF_SIZE];	//缓冲区

//调试开关
#define SIM900_DBUG	0
#if SIM900_DBUG
	#include "system.h"
	#define SIM900_debug(format,...)	uart_printf(format,##__VA_ARGS__)
#else
	#define SIM900_debug(format,...)	/\
/
#endif	//SIM900_DBUG

//所有短信接收缓冲区
//#define PDU_BUFF_SIZE	1024*20			//20KB	可以一次读取50条未读短信
u8	SmsPduBuff[PDU_BUFF_SIZE];			//PDU数据缓冲区

static u8 PhoneNumtoPDUChar(u8 *pNum, char *pChar,u8 NumLen);		//将电话号码字符转换为PDU要求的字符
static u8 ChartoPhoneNum(char *pChar, char *pNum, u8 CharLen);		//将字符转换为电话号码
static u32 StringToUnicodeStr(char *pStr, char *pucode,u32 SrtLen);	//将字符串转换为unicode,并存储为16进制样式的字符串
static u32 UnicodeStrToString(u8 *pucode,char *pStr,u32 SrtLen);	//将字符unicode转换为字符串
static u32 GSM_StringToHex(char *pStr, u8 NumDigits);				//将16进制样式字符串转换为16进制整型数(必须保证字符串字母都是大写)
static void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits);	//将整型数字转换为16进制样式字符串(字母为大写,不带结束符)
static int gsmDecode7bit(const u8* pSrc, char* pDst, int nSrcLength);//7bit编码解码
static int gsmEncode7bit(const char* pSrc,u8* pDst);
static u16 GSM_GetU2SCharOffset(char *pBuff,u16 CharNum);

static PHONE_NUMBER SMSServeNumber;									//全局短信中心号码

/*************************************************************************************************************************
* 函数				:	void SIM900_SetSMSServeNumber(char *pSMSServeNumber,u8 NumLen)
* 功能				:	设置全局短信中心号码
* 参数				:	pSMSServeNumber:短信中心号码,NumLen:短信中心号码长度
* 返回				:	无
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-25
* 最后修改时间 	: 	2013-10-25
* 说明				: 	用于发送短信的时候进行调用
*************************************************************************************************************************/
void SIM900_SetSMSServeNumber(char *pSMSServeNumber,u8 NumLen)
{
	u8 i;
	
	if(NumLen > PHONE_NUMBER_MAX_LEN) NumLen = PHONE_NUMBER_MAX_LEN;	//限制电话号码长度
	for(i = 0;i < NumLen;i ++)
	{
		SMSServeNumber.PhoneNumBuff[i] = pSMSServeNumber[i];
	}
	SMSServeNumber.PhoneNumLen = NumLen;
	SMSServeNumber.PhoneNumBuff[SMSServeNumber.PhoneNumLen] = '\0';		//添加结束符
	SIM900_debug("设置短信中心号码为:%s\r\n",SMSServeNumber.PhoneNumBuff);
}

/*************************************************************************************************************************
* 函数				:	bool GSM_CheckNotASCII(char *pBuff,u16 Len)
* 功能				:	检查字符串中是否含有非ASCII编码
* 参数				:	pBuff:字符串缓冲区;Len:长度
* 返回				:	FALSE:字符串全部为ASCII编码;TRUE:字符串含有非ASCII编码,一般为汉字编码
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-25
* 最后修改时间 	: 	2013-10-25
* 说明				: 	用于选择发送短信的模式,选择U2S或者7BIT编码
*************************************************************************************************************************/
bool GSM_CheckNotASCII(char *pBuff,u16 Len)
{
	u16 i;
	
	for(i = 0;i < Len;i ++)
	{
		if(pBuff[i] >= 0x80)
			return TRUE;
	}
	return FALSE;
}

/*************************************************************************************************************************
* 函数				:	static u16 GSM_GetU2SCharOffset(char *pBuff,u16 CharNum)
* 功能				:	计算指定字符的偏移位置
* 参数				:	pBuff:字符串缓冲区;
						CharNum:字符偏移
* 返回				:	字符串大小
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-25
* 最后修改时间 	: 	2013-10-25
* 说明				: 	计算指定数量的字符(不分中英文)的大小,比如PDU,U2S模式下,短信只能有70个字符,但是不分中英文
						此时英文只占用一个字节,但是中文占用2个字节
*************************************************************************************************************************/
static u16 GSM_GetU2SCharOffset(char *pBuff,u16 CharNum)
{
	u16 i;
	u16 cnt = 0;
	

	for(i = 0;i < CharNum;)
	{
		if(pBuff[i] >= 0x80)	//中文
		{
			cnt +=2;
			i +=2;
		}
		else if(pBuff[i] == 0)	//字符串结束
		{
			break;
		}
		else					//ASCII
		{
			cnt += 1;
			i ++;
		}
	}
	return cnt;
}

/*************************************************************************************************************************
* 函数				:	bool SIM900_WaitSleep(void)
* 功能				:	等待GSM模块空闲,并重新唤醒
* 参数				:	TimeOut:等待超时,时间单位ms
* 返回				:	TRUE:成功;FALSE:超时
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-25
* 最后修改时间 	: 	2013-10-25
* 说明				: 	用于等待操作完成,防止快速操作造成模块不响应
*************************************************************************************************************************/
bool SIM900_WaitSleep(u32 TimeOut)
{
	u32 i;
	u32 cnt;
	
	TimeOut /= 100;
	TimeOut +=1;
	
	SIM900_SetDTR(1);							//等待模块空闲后进入SLEEP模式
	
	for(i = 0;i < TimeOut;i ++)
	{
		GSM_Delay100MS();						//延时100ms
		SIM900_SendATcom("AT");					//发送"AT",同步波特率,并且等待应答
		if(AT_RETURN_TIME_OUT == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 15))	//等待响应,超时150ms
		{
			break;
		}
	}
	SIM900_SetDTR(0);							//唤醒
	if(i == TimeOut) 
	{
		SIM900_debug("模块进入空闲模式失败!\r\n");
		return FALSE;
	}
	GSM_Delay100MS();						//延时100ms
	
	SIM900_debug("模块进入空闲模式成功!\r\n");
	SIM900_TestAT(10);
	return TRUE;
}

/*************************************************************************************************************************
*函数        	:	bool GSM_SendSMS(char *pSMS, char *pPhoneNumber)
*功能        	:	发送一条短信
*参数        	:	pSMS:短信内容缓冲区指针,内容为文本文档,并且字符串需要结束符
					pPhoneNumber:目标电话号码
*返回        	:	TRUE:短信发送成功;FALSE:短信发送失败
*依赖        	:	底层
*作者        	:	cp1300@139.com
*时间        	:	2013-10-25
*最后修改时间	:	2013-10-25
*说明        	:	需要先调用SIM900_SetSMSServeNumber()设置短信中心号码
					需要使用全局的PDU数据缓冲区
					一定要添加结束符
					当短信长度超过单条短信长度限制后会发送多条短信
*************************************************************************************************************************/
#define SMS_MAX_LEN		2048					//短信最大长度
bool GSM_SendSMS(char *pSMS, char *pPhoneNumber)
{
	char SMSBuff[160+1];	//短信最大160B,加上一个结束符
	u8 PDUBuff[512];		//短信PDU数据缓冲区
	u16 SMSLen;				//短信长度
	u16 SMSOffset;			//短信发送偏移位置,用于发送多条短信
	u16 i,j;
	
	SMSLen = strlen(pSMS);	//获取要发送的短信长度
	if(SMSLen > SMS_MAX_LEN) SMSLen = SMS_MAX_LEN;	//限制短信最大长度,防止无限发送
	
	if(strlen(SMSServeNumber.PhoneNumBuff) == 0)
	{
		SIM900_debug("由于短信中心号码设置失败,导致短信无法发送!\r\n");
		return FALSE;
	}
	
	SMSOffset = 0;			//起始偏移为0
	while(1)
	{
		if((SMSLen-SMSOffset) > 160)
			j = 160;
		else 
			j = SMSLen-SMSOffset;
		for(i = 0;i < j;i ++)
		{
			SMSBuff[i] = pSMS[SMSOffset + i];	//复制短信到发送缓冲区
		}
		SMSBuff[j] = 0;	//添加结束符
		
		if(GSM_CheckNotASCII(SMSBuff,j) == TRUE)	//分割的短信中含有非ASCII编码,那么只能使用U2S编码,只能发送70个字符(包括中英文)
		{
			SMSOffset += GSM_GetU2SCharOffset(SMSBuff,70);	//第一条短信限制70个字符,返回下一条分割的起始位置
			SMSBuff[SMSOffset] = 0;
		}
		else
		{
			SMSOffset += j;	//下一条分割的起始位置
			SMSBuff[SMSOffset] = 0;
		}
		
		//SIM900_WaitSleep(1000);	//等待上一个操作完成
		if(GSM_SendOneSMS(SMSBuff, PDUBuff, SMSServeNumber.PhoneNumBuff, pPhoneNumber) == TRUE)
		{
			SIM900_debug("发送短信成功!\r\n");
			
			
		}
		else
		{
			SIM900_debug("发送短信失败!\r\n");
			return FALSE;
		}
		if(SMSOffset >= SMSLen) break;	//短信发送完成,退出
	}
	
	return TRUE;
	
}

/*************************************************************************************************************************
* 函数			:	void SIM900_HardwareInit(void)
* 功能			:	初始化SIM900相关的硬件
* 参数			:	无
* 返回			:	无
* 依赖			:	无
* 作者			:	cp1300@139.com
* 时间			:	2013-10-16
* 最后修改时间 	: 	2013-10-16
* 说明			: 	主要初始化与SIM900相关的STM32 IO 以及 UART
*************************************************************************************************************************/
void SIM900_HardwareInit(void)
{
	SIM900_UartInit();									//初始化串口
	SIM900_SetRxBuff(SIM900_Buff, SIM900_BUFF_SIZE);	//设置通信缓冲区

	//初始化RI,用于指示新短信或者电话
	DeviceClockEnable(DEV_GPIOB,ENABLE);				//使能GPIOB时钟
	GPIOx_Init(GPIOB,BIT14, IN_IPU, IN_IN);				//上拉输入
	GPIOx_Init(GPIOB,BIT12|BIT13|BIT15, OUT_PP, SPEED_10M);	//推挽输出
	SIM900_SetDTR(0);									//取消SLEEP
	SIM900_SetRESET(1);									//复位无效
	SIM900_SetPWR(1);									//上电无效
}

/*************************************************************************************************************************
* 函数				:	void SIM900_HardwarePowerUP(void)
* 功能				:	SIM900硬件开机
* 参数				:	无
* 返回				:	无
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-29
* 最后修改时间 	: 	2013-10-29
* 说明				: 	用于SIM900模块开机,拉低PWR
*************************************************************************************************************************/
void SIM900_HardwarePowerUP(void)
{
	SIM900_SetPWR(1);	//恢复高电平
	GSM_DelayMS(200);
	SIM900_SetPWR(0);	//拉低750ms开机
	GSM_DelayMS(750);
	GSM_Delay100MS();
	SIM900_SetPWR(1);	//恢复高电平
	GSM_DelaySer(3);	//延时3S等待开机完毕							
}

/*************************************************************************************************************************
* 函数				:	void SIM900_HardwarePowerDOWN(void)
* 功能				:	SIM900硬件关机
* 参数				:	无
* 返回				:	无
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-29
* 最后修改时间 	: 	2013-10-29
* 说明				: 	用于SIM900模块关机机,拉低PWR大于1S小于5S
*************************************************************************************************************************/
void SIM900_HardwarePowerDOWN(void)
{
	SIM900_SetPWR(1);	//恢复高电平
	GSM_DelayMS(200);
	SIM900_SetPWR(0);	//拉低1500ms关机
	GSM_DelaySer(1);	
	GSM_DelayMS(500);
	SIM900_SetPWR(1);	//恢复高电平
	GSM_DelaySer(2);	//延时2S等待注销网络					
}

/*************************************************************************************************************************
* 函数				:	void SIM900_HardwareReset(void)
* 功能				:	SIM900硬件复位
* 参数				:	无
* 返回				:	无
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-29
* 最后修改时间 	: 	2013-10-29
* 说明				: 	用于SIM900模块硬件复位
*************************************************************************************************************************/
void SIM900_HardwareReset(void)
{
	SIM900_SetRESET(1);	//恢复高电平
	GSM_Delay100MS();
	SIM900_SetRESET(0);	//拉低100mS复位
	GSM_Delay100MS();
	SIM900_SetRESET(1);	//恢复高电平
	GSM_DelaySer(2);	//延时2S					
}

/*************************************************************************************************************************
* 函数			:	bool SIM900_ModuleInit(void)
* 功能			:	初始化SIM900模块
* 参数			:	无
* 返回			:	FALSE:初始化失败;TRUE:初始化成功
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-16
* 最后修改时间 	: 	2013-10-16
* 说明			: 	主要初始化与SIM900配置,以及初始化网络
*************************************************************************************************************************/
bool SIM900_ModuleInit(void)
{
	u32 cnt;
	u8 retry = 5;		//重试次数
	
	//检测模块存在
	retry = 5;		//重试次数
	do
	{
		SIM900_SendATcom("AT");	//发送"AT",同步波特率,并且等待应答
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 10))	//等待响应,超时100ms
		{
			break;
		}
		retry --;
	}while(retry);
	if(retry == 0) return FALSE;
	
	//设置关闭回显
	retry = SIM900_RETRY;		//重试次数
	do
	{
		SIM900_SendATcom("ATE 0");	//发送"ATE",关闭回显模式
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 10))	//等待响应,超时100ms
		{
			SIM900_debug("\r\n关闭AT回显模式成功!\r\n");
			break;
		}
		
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("\r\n关闭AT回显模式失败!\r\n");
		return FALSE;
	}
	
	//设置短消息格式为PDU格式
	retry = SIM900_RETRY;		//重试次数
	do
	{
		SIM900_SendATcom("AT+CMGF=0");	//发送"AT+CMGF",设置短消息格式为PDU格式
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 10))	//等待响应,超时100ms
		{
			SIM900_debug("\r\n设置短消息格式为PDU格式成功!\r\n");
			break;
		}
		
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("\r\n设置短消息格式为PDU格式失败!\r\n");
		return FALSE;
	}
	
	//使能RI引脚提示
	retry = SIM900_RETRY;		//重试次数
	do
	{
		SIM900_SendATcom("AT+CFGRI=1");	//发送"AT+CFGRI",启动RI引脚提示
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 10))	//等待响应,超时100ms
		{
			SIM900_debug("\r\n启动RI引脚提示成功!\r\n");
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("\r\n启动RI引脚提示失败!\r\n");
		return FALSE;
	}
	
	//设置模块sleep模式使能
	retry = SIM900_RETRY;		//重试次数
	do
	{
		SIM900_SendATcom("AT+CSCLK=1");	//发送"AT+CSCLK",启动SLEEP模式
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 10))	//等待响应,超时100ms
		{
			SIM900_debug("\r\n设置SLEEP成功!\r\n");
			break;
		}
		
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("\r\n设置SLEEP失败!\r\n");
		return FALSE;
	}
	
	SIM900_SetDTR(1);	//使能SLEEP模式
	return TRUE;
}

/*************************************************************************************************************************
* 函数			:	bool SIM900_TestAT(u32 retry)
* 功能			:	SIM900 AT 命令通信测试
* 参数			:	retry:重试次数
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	每隔20ms向SIM900发送一个"AT",等待响应返回
*************************************************************************************************************************/
bool SIM900_TestAT(u32 retry)
{
	u32 cnt;

	//检测模块存在
	do
	{
		SIM900_SendATcom("AT");												//发送"AT",同步波特率,并且等待应答
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 15))	//等待响应,超时150ms
		{
			return TRUE;
		}
		retry --;
	}while(retry);
	
	return FALSE;
}

/*************************************************************************************************************************
* 函数				:	SIM900_ERROR SIM900_GetATResp(u8 *pRxBuff, u32 *pLen, const char *pKeyword, u32 ByteTime, u32 TimeOut)
* 功能				:	获取SIM900的AT指令响应
* 参数				:	pRxBuff:接收缓冲区指针(输入);pLen:接收到的数据大小(输出),
						pKeyword:关键字,为字符串,比如"OK",如果在接收到的字符串中有OK字符,就返回成功,否则失败(输入)
						ByteTime:字节超时时间,单位ms最大999ms
						TimeOut:等待超时时间,单位字节超时时间
* 返回				:	SIM900_ERROR
* 依赖				:	无
* 作者				:	cp1300@139.com
* 时间				:	2013-10-16
* 最后修改时间 	: 	2014-04-22
* 说明				: 	本函数会在接收缓冲区字符串结束添加'\0'
						2014-04-22:添加字节超时与总超时
*************************************************************************************************************************/
SIM900_ERROR SIM900_GetATResp(u8 *pRxBuff, u32 *pLen, const char *pKeyword, u32 ByteTime, u32 TimeOut)
{
	u32 cnt1, cnt2=0;	//接收数据计数器
	u32 timeCnt = TimeOut;
	
	if(ByteTime > 999)ByteTime = 999;
	do
	{
		cnt1 = cnt2;
		GSM_DelayMS(ByteTime);				//延时字节超时
		cnt2 = SIM900_GetRxCnt();			//获取接收数据计数器
		if(cnt1 == cnt2)					//完成接收数据了,退出等待
		{
			timeCnt --;
			if((cnt1 > 0)&&(timeCnt!=0)) timeCnt=1;				//数据接收完毕,退出
		}
		else
		{
			timeCnt = TimeOut;
		}
	}while(timeCnt);
	
	//等待超时
	if(cnt2 == 0)
	{
		SIM900_debug("\r\nAT指令返回超时\r\n");
		return AT_RETURN_TIME_OUT;			//返回超时错误
	}
	//数据接收完毕
	*pLen = cnt2;							//返回接收数据长度
	pRxBuff[cnt2]	= '\0';					//将数据结尾添加结束字符串
	
	SIM900_debug("%s\r\n",pRxBuff);			//打印返回信息

	if(strstr((const char*)pRxBuff, pKeyword) != NULL) 	//搜索关键字
	{
		SIM900_debug("%s 返回成功!\r\n",pKeyword);
	    return AT_RETURN_OK;
	}
	else if(strstr((const char*)pRxBuff, "ERROR") != NULL)
	{
		SIM900_debug("%s 返回错误!\r\n",pKeyword);
		return AT_RETURN_ERROR;
	}
	else
	{
		SIM900_debug("%s 返回未知!\r\n",pKeyword);
		return AT_RETURN_UNKNOWN;
	}
	
	
}

/*************************************************************************************************************************
* 函数			:	int SIM900_GetSmsNum(void)
* 功能			:	获取SIM卡存储的短信数量
* 参数			:	无
* 返回			:	<0:错误,其它:短信数量
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	无
*************************************************************************************************************************/
int SIM900_GetSmsNum(void)
{
	u8 n;
	u32 cnt;
	char *p;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{
		SIM900_SendATcom("AT+CPMS?");	//发送"AT+CPMS",获取短信数量
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0) return -1;								//超时
	
	p = strstr((const char*)SIM900_Buff, "\"SM\"");			//搜索字符""SM""
	if(p != NULL) 				
	{	
		if(p[6] != ',')	n = 2;								//短信数量有可能是1位数,也有可能是2位数,通过判断后面是否为','
		else n = 1;
		return GSM_StringToDec(p + 5, n);					//跳过前面的5字节,""SM",",并获取存储的短信数量					
	}
	return -1;												//错误
}

/*************************************************************************************************************************
* 函数				:	bool SIM900_DelMultiSMS(SIM900_DEL DelStatus)
* 功能				:	SIM900批量删除短信
* 参数				:	SIM900_DEL
* 返回				:	TRUE:成功;FALSE:失败;
* 依赖				:	底层
* 作者				:	cp1300@139.com
* 时间				:	2013-10-17
* 最后修改时间 		: 	2013-10-20
* 说明				: 	批量删除的时候可能会很慢
*************************************************************************************************************************/
bool SIM900_DelMultiSMS(SIM900_DEL DelStatus)
{
	u32 cnt;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{
		switch(DelStatus)
		{
			case DEL_READ_SMS:			//删除所有已读短信
				SIM900_SendATcom("AT+CMGDA=1");	break;
			case DEL_UNREAD_SMS:		//删除所有未读短信
				SIM900_SendATcom("AT+CMGDA=2");	break;
			case DEL_SENT_SMS:			//删除所有已经发送的短信
				SIM900_SendATcom("AT+CMGDA=3");	break;
			case DEL_UNSENT_SMS:		//删除所有未发送短信
				SIM900_SendATcom("AT+CMGDA=4");	break;
			case DEL_INBOX_SMS:			//删除所有接收短信
				SIM900_SendATcom("AT+CMGDA=5");	break;
			case DEL_ALL_SMS:			//删除所有短信
				SIM900_SendATcom("AT+CMGDA=6");	break;
			default: return FALSE;
		}
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 200))//等待响应,超时2S
		{
			return TRUE;
		}
		SIM900_Ready();	//等待就绪
	}while(retry --);
	
	return FALSE;
}

/*************************************************************************************************************************
* 函数				:	SIM900_ERROR SIM900_GetUnreadSMS(u8 *pUnreadSMSBuff, u32 BuffSize, u32 *pPDUCnt)
* 功能				:	读取SIM900所有的未读短信
* 参数				:	pUnreadSMSBuff:未读短信PDU数据缓冲区指针,BuffSize:缓冲区大小,pPDUCnt:PDU数据大小
* 返回				:	SIM900_ERROR
* 依赖				:	底层
* 作者				:	cp1300@139.com
* 时间				:	2013-10-17
* 最后修改时间 	: 	2013-10-17
* 说明				: 	短信最大存储数量为50条
						缓冲区必须足够大,做好最坏打算,有50条未读短信,如果缓冲区不够大,会发送溢出
						溢出后虽然不会造成系统错误,但是会覆盖前面的未读短信数据.
*************************************************************************************************************************/
SIM900_ERROR SIM900_GetUnreadSMS(u8 *pUnreadSMSBuff, u32 BuffSize, u32 *pPDUCnt)
{
	SIM900_ERROR error;
	u8 retry = SIM900_RETRY;		//重试次数
	
	SIM900_SetRxBuff(pUnreadSMSBuff, BuffSize);						//重新设置接收缓冲区
	do
	{
		SIM900_SendATcom("AT+CMGL=0");									//发送"AT+CMGL",读取所有的未读短息
		error = SIM900_GetATResp(pUnreadSMSBuff, pPDUCnt, "OK", 250, 4);	//等待响应,超时1000ms
		if(error == AT_RETURN_OK)
			break;
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	SIM900_SetRxBuff(SIM900_Buff, SIM900_BUFF_SIZE);				//恢复默认缓冲区
	
	return error;
}

/*************************************************************************************************************************
*函数        	:	bool GSM_ParsePDUSMS(char *pPDU,char *pSMS,u32 len,SMS_INFO *pInfo)
*功能        	:	解析一条PDU格式短信
*参数        	:	pPDU:短信PDU数据缓冲区指针
* 					pSMS:解析后的短信缓冲区指针
* 					pInfo:短信信息指针
*返回        	:	TRUE:成功;FALSE:失败
*依赖        	:	void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt);
*作者        	:	cp1300@139.com
*时间        	:	2013-04-04
*最后修改时间	:	2013-05-01
*说明        	:	无
*************************************************************************************************************************/
bool GSM_ParsePDUSMS(char *pPDU, char *pSMS, u32 PDUSize, SMS_INFO *pInfo)
{
	u16 cnt = 0;
	u16 temp;
	char *p;
	u16 SMS_Size;
	
	p = strstr((const char*)pPDU, "+CMGR:");
	if(p == NULL)
	{
		SIM900_debug("短信中没有搜索到\"+CMGR:\"\r\n");
		p = strstr((const char*)pPDU, "+CMGL:");
		if(p == NULL)
		{
			SIM900_debug("短信中没有搜索到\"+CMGL:\"\r\n");
			return FALSE;
		}
	}
	//提取短信的编号 //+CMGR: 1,"",34
	if(p[8] != ',')	pInfo->IndexNum = GSM_StringToDec(p + 7, 2);	//短信索引可能是1位数,也有可能是2位数,通过判断后面是否为','
	else pInfo->IndexNum = GSM_StringToDec(p + 7, 1);;
				
	p = strstr((const char*)p, "\r\n");	//寻找短信PDU开始位置
	cnt = ((u32)p - (u32)pPDU) + 2;		//找到短信PDU开始的位置了
	if(p == NULL || cnt >= PDUSize)
	{
		pInfo->SMS_Size = 0;
		SIM900_debug("短信解析错误!\r\n");
		return FALSE;
	}
	
	//获取短信中心号码长度
	temp = GSM_StringToHex(&pPDU[cnt], 2);	//将16进制样式字符串转换为整型数
	cnt += 2;			//跳过前面的短信中心号码长度字节
	cnt += temp*2;		//跳过前面的短信中心信息
	
	//解析PDU数据  RT  UDHI  SRI -  -  MMS   MTI  MTI  //UDHI为1,代表用户数据有头部信息,用于标识短信拆分信息
	pInfo->PDU = GSM_StringToHex(&pPDU[cnt], 2);	//将16进制样式字符串转换为整型数//PDU数据
	cnt += 2;			//跳过PDU头数据字节

	//计算发送短信的号码的长度
	temp = GSM_StringToHex(&pPDU[cnt], 2);	//将16进制样式字符串转换为整型数
	cnt += 2;			//跳过电话号码长度字节
	cnt += 2;			//跳过地址类型,常为"91",一字节
	pInfo->NumLen = ChartoPhoneNum((char *)&pPDU[cnt], (char *)&(pInfo->NumBuff[0]), (temp > SMS_NUM_LEN_MAX - 2) ? (SMS_NUM_LEN_MAX - 2) : temp);	//转换发送号码
	pInfo->NumBuff[pInfo->NumLen] = 0;	//结束符
	//lcd_printf("pInfo->NumLen=%d\r\n",pInfo->NumLen);
	//uart_printf("%s\r\n",pInfo->NumBuff);
	cnt += (temp%2) ? (temp+1) : temp;	//跳过发送号码长度的字节数
	cnt+=2;	//跳过PID,2B
	pInfo->DSC = GSM_StringToHex(&pPDU[cnt], 2);	//获取DSC信息
	cnt+=2;	//跳过DSC,2B
	//cnt+=2;	//跳过VP,2B	//没有这个标志
	//cnt+=2;	//跳过UDL,2B//没有这个标志

	
	pInfo->Timer.Year = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');		cnt += 2;	//年
	pInfo->Timer.Month = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');	cnt += 2;	//年
	pInfo->Timer.Day = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');		cnt += 2;	//年
	pInfo->Timer.Hour = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');		cnt += 2;	//年
	pInfo->Timer.Minute = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');	cnt += 2;	//年
	pInfo->Timer.Second = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');	cnt += 2;	//年      	                       
   	cnt += 2;	//跳过时差2字节
	SMS_Size = GSM_StringToHex(&pPDU[cnt], 2);		//计算短信字符数量,不管英文,中文都算一个字符
	SIM900_debug("SMS_Size = GSM_StringToHex(&pPDU[cnt], 2) = %d\r\n",SMS_Size);
	cnt += 2;											//跳过短信长度字节,2B

	if(pInfo->PDU & 0x40)	//用户数据有头部信息,标识短信已经被分割为几条
	{
		cnt += 8;			//跳过前面8个数据,只要后面的4个,标识
		SMS_Size -= 12;		//短信长度减去偏移
		
		pInfo->AllNum = GSM_StringToHex(&pPDU[cnt], 2);//计算总分割数
		cnt += 2;		//跳过2B的总数
		pInfo->PreNum = GSM_StringToHex(&pPDU[cnt], 2);//计算当前位置
		cnt += 2;		//跳过2B的当前位置
		SIM900_debug("短信分割:%d/%d\r\n",pInfo->AllNum, pInfo->PreNum);
	}
	else
	{
		pInfo->AllNum = pInfo->PreNum = 0;	//短信没有被分割
	}
	
	//DCS 00:7BIT编码;08:UCS2编码;04:8bit编码
	switch((pInfo->DSC) & 0x0f)
	{
		case 0x00:	//7bit编码
		{
			SIM900_debug("短信为7bit编码(TEXT格式)\r\n");
			pInfo->SMS_Size = (SMS_Size > 160) ? 160 : SMS_Size;		//短信大小
			pInfo->TEXT_MODE = 1;	
			SMS_Size = (SMS_Size * 7 / 8) + (((SMS_Size * 7) % 8) ? 1 : 0);//计算短信占用空间大小
			pPDU += cnt;
			for(temp = 0;temp < SMS_Size;temp ++)				//将PDU数据转换为16进制数据
			{
				pPDU[temp] = GSM_StringToHex(&pPDU[temp << 1], 2);	//1B数据转换为PDU格式后占用2B
			}
			gsmDecode7bit((u8 *)pPDU, (char *)pSMS, SMS_Size);	//7bit->8bit,数据长度会发生变化
			//SIM900_debug("SMS:%s\r\n",pSMS);
		}break;
		case 0x04:	//8bit编码
		{
			SIM900_debug("短信为8bit编码(不支持)\r\n");
			return FALSE;
		}
		case 0x08:	//UCS2编码
		{
			SIM900_debug("短信为UCS2编码(PDU格式)\r\n");
			pInfo->TEXT_MODE = 0;	
			SMS_Size = (SMS_Size > 140) ? 140 : SMS_Size;		//短信字符限制为140B
			//UNICODE PDU转换为字符串 --> GBK,返回短信大小,每个短信字符占用2字节,每个字节转换为PDU后占用2B
			pInfo->SMS_Size = UnicodeStrToString((u8 *)pPDU+cnt,(char *)pSMS,SMS_Size<<1);		
		}break;
		default:SIM900_debug("未知短信编码格式!\r\n");return FALSE;
	}

	pSMS[pInfo->SMS_Size] = '\0';				//添加结束符		
	
	return TRUE;
}

/*************************************************************************************************************************
*函数        	:	SIM900_ERROR SIM900_ReadTextSMS(char *pSMS, SMS_INFO *pInfo, u16 IndexNum)
*功能        	:	读取一条TEXT格式短信
*参数        	:	pSMS:解析后的短信存放位置指针,注意存放的最大大小由_MAX_SMS_SIZE决定
* 					pInfo:短信信息指针
* 					IndexNum:短信索引号
*返回        	:	GSM_ERROR:状态
*依赖        	:	短信读取与解析
*作者        	:	cp1300@139.com
*时间        	:	20130408
*最后修改时间	:	20130408
*说明        	:	
*************************************************************************************************************************/
SIM900_ERROR SIM900_ReadTextSMS(char *pSMS, SMS_INFO *pInfo, u16 IndexNum)
{
	SIM900_ERROR error;
	u32 cnt;

	if(SIM900_TestAT(10) == FALSE)	//串口同步失败
	{
		SIM900_WaitSleep(1000);	//等待上一个操作完成
	}
	//配置短信为TEXT格式
	SIM900_SendATcom("AT+CMGF=1");	
	if(SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20) == AT_RETURN_OK)
	{
		sprintf((char *)SIM900_Buff, "AT+CMGR=%d", IndexNum);						//写入索引号
		SIM900_SendATcom((char *)SIM900_Buff);										//发送读取短信命令
		error = SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20);						//等待返回
		if(error == AT_RETURN_OK)
		{
			GSM_ParseTextSMS((char *)SIM900_Buff, pSMS, cnt, pInfo);				//解析TEXT格式短信
		}
	}
	SIM900_SendATcom("AT+CMGF=0");	//配置短信为PDU格式
	error = SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20);
	
	return error;
}

/*************************************************************************************************************************
*函数        	:	u32 GSM_ParseTextSMS(char *pText, char *pSMS, u32 TextSize, SMS_INFO *pInfo)
*功能        	:	解析一条TEXT格式短信
*参数        	:	pText:短信TEXT数据缓冲区指针
* 					pSMS:解析后的短信缓冲区指针
					TextSize:数据大小
* 					pInfo:短信信息指针
*返回        	:	TRUE:成功;FALSE:失败
*依赖        	:	无
*作者        	:	cp1300@139.com
*时间        	:	2013-04-30
*最后修改时间	:	2013-04-30
*说明        	:	需要先切换到TEXT格式,用于解析TEXT格式短信,之后会切换回PDU格式
					需要先解析为PDU后才知道是否为TEXT格式短信
*************************************************************************************************************************/
bool GSM_ParseTextSMS(char *pText, char *pSMS, u32 TextSize, SMS_INFO *pInfo)
{
	u16 cnt = 0;
//	u16 temp;
	char *p;
//	u16 SMS_Size;
	
	pText[TextSize] = '\0';						//添加结束符
	p = strstr((const char*)pText, "+CMGR:");
	p = strstr((const char*)p, "\r\n");	//寻找短信TEXT开始位置
	
	cnt = ((u32)p - (u32)pText) + 2;		//找到短信TEXT开始的位置了
	if(p == NULL || cnt >= TextSize)
	{
		SIM900_debug("TEXT短信解析错误!\r\n");
		return FALSE;
	}
	p +=2;	//跳到短信开始位置
	for(cnt = 0;cnt < pInfo->SMS_Size;cnt ++)	//复制短信
	{
		pSMS[cnt] = p[cnt];
	}
	pSMS[pInfo->SMS_Size] = 0;					//添加结束符
	
	return TRUE;
}

/*************************************************************************************************************************
*函数        	:	static u8 PhoneNumtoPDUChar(u8 *pNum, char *pCHAR,u8 NumLen)
*功能        	:	将电话号码字符转换为PDU要求的字符
*参数        	:	pNum:电话号码指针
* 					pChar:字符缓冲区指针
* 					NumLen:电话号码长度
*返回        	:	字符长度
*依赖        	:	底层宏定义
*作者        	:	cp1300@139.com
*时间        	:	2013-04-04
*最后修改时间	:	2013-10-17
*说明        	:	主要用于电话号码,短信中心号码转换
* 					如果长度为奇数,则将补成偶数,并在最后一个字符的高位保留位0xf;
* 					本函数不添加结束符
*************************************************************************************************************************/
static u8 PhoneNumtoPDUChar(u8 *pNum, char *pChar,u8 NumLen)
{
	u8 i;
	u8 temp;

	for(i = 0;i < NumLen;i ++)
	{
		temp = (pNum[i]+'0') & 0x0f;
		if(i % 2)	//位数为奇数
			pChar[i-1] = (temp > 9) ? ('a' + temp - 10) :( temp + '0');
		else		//位数为偶数
			pChar[i+1] = (temp > 9) ? ('a' + temp - 10) : (temp + '0');	
	}
	if(i % 2)
	{
		pChar[NumLen-1] = 'F';
		return (NumLen + 1);
	}
	
	return NumLen;
}

/*************************************************************************************************************************
*函数        	:	static u8 ChartoPhoneNum(char *pChar, char *pNum, u8 CharLen)
*功能        	:	将字符转换为电话号码
*参数        	:	pCHAR:字符缓冲区指针
* 					pNum:电话号码指针
* 					charLen:字符号码长度
*返回        	:	电话长度
*依赖        	:	底层宏定义
*作者        	:	cp1300@139.com
*时间        	:	2013-04-04
*最后修改时间	:	2013-10-17
*说明        	:	主要用于电话号码,短信中心号码转换
* 					如果电话长度为奇数,则将补成偶数,并在最后一个字符的高位保留位0xf;
* 					转换后为字符
*************************************************************************************************************************/
static u8 ChartoPhoneNum(char *pChar, char *pNum, u8 CharLen)
{
	u32 i;
	u8 temp;

	for(i = 0;i < CharLen;i ++)
	{
		temp = pChar[i];
		if(temp == 'F')	//还有一位就结束了
		{
			pNum[i] =   pChar[i+1];	
			return i + 1;
		}
		else if(temp > '9')	//非数字
		{
			return 0;	//电话号码格式错误
		}
		 
		else if(i % 2)	//位数为奇数
			pNum[i-1] =  temp;
		else	//位数为偶数
			pNum[i+1] = temp;	
	}
	return i;
}

/*************************************************************************************************************************
*函数        	:	static u32 StringToUnicodeStr(char *pStr, char *pucode,u32 SrtLen)
*功能        	:	将字符串转换为unicode,并存储为16进制样式的字符串
*参数        	:	pStr:字符缓冲区指针
* 					pucode:转换结果缓冲区
* 					SrtLen:字符串字节长度
*返回        	:	转换成为字符后的长度
*依赖        	:	u16 OneGBKtoUNICODE(u16 GBKCode)
*作者        	:	cp1300@139.com
*时间        	:	2013-04-04
*最后修改时间	:	2013-10-17
*说明        	:	用于将短信内容转换为PUD格式,本函数不添加字符串结束符
* 					如"a,b,c"--->"0,0,6,1,0,0,6,2,0,0,6,3"
* 					输出缓冲区至少为输入的4倍
*************************************************************************************************************************/
static u32 StringToUnicodeStr(char *pStr, char *pucode,u32 SrtLen)
{
	u32 i;
	u16 temp;
	u8 m;
	u8 chTmp= 0;
	u32 cnt = 0;
	
	for(i = 0;i < SrtLen;i ++)
	{
		if(pStr[i] < 0x80)	//ASCII
		{
			temp = pStr[i];
		}
		else				//GBK
		{
			temp = pStr[i ++]<< 8;
			temp |= pStr[i];
			temp = OneGBKtoUNICODE(temp);
		}

		for(m = 0; m <= 12; m+=4)
	    {
	      chTmp = (temp >> (12-m)) & 0x0F;			//先取高位
	      if(chTmp > 0x09)   //! 0x0A-0x0F
	    	  pucode[cnt ++] = chTmp-0x0A+'A';       //! 'A'-'F'
	      else                                 //! 0x00-0x09
	    	  pucode[cnt ++] = chTmp-0x00+'0';       //! '0'-'9'
	    }
	}
	return cnt;
}

/*************************************************************************************************************************
*函数        	:	u32 UnicodeStrToString(u8 *pucode,char *pStr,u32 SrtLen)
*功能        	:	将字符unicode转换为字符串
*参数        	:	pucode:转换结果缓冲区
* 					pStr:字符缓冲区指针
* 					SrtLen:字符串字节长度
*返回        	:	转换成为字符后的长度
*依赖        	:	u16 OneUNICODEtoGBK(u16 unicode);
*作者        	:	cp1300@139.com
*时间        	:	2013-04-04
*最后修改时间	:	2013-10-26
*说明        	:	用于将PUD格式短信解析,本函数不添加字符串结束符
					2013-10-26:解决短信中句号无法解析
*************************************************************************************************************************/
static u32 UnicodeStrToString(u8 *pucode,char *pStr,u32 SrtLen)
{
	u32 i;
	u16 temp;
	u32 cnt = 0;
	u8 H,L;

	for(i = 0;i < SrtLen;i+=4)
	{
		if(pucode[i] == '0')	//0
		{
			H = pucode[i+2];
			L = pucode[i+3];
			H = (H > '9') ? H - 'A' + 10 : H - '0';
			L = (L > '9') ? L - 'A' + 10 : L - '0';	
			pStr[cnt++] = (H << 4) + L;	
		}
		else
		{
			H = pucode[i];
			L = pucode[i+1];
			H = (H > '9') ? H - 'A' + 10 : H - '0';
			L = (L > '9') ? L - 'A' + 10 : L - '0';	
			temp = (H << 4) + L;
			temp <<= 8;
			H = pucode[i+2];
			L = pucode[i+3];
			H = (H > '9') ? H - 'A' + 10 : H - '0';
			L = (L > '9') ? L - 'A' + 10 : L - '0';	
			temp |= (H << 4) + L;
			//lcd_printf("temp1 = 0x%04X\r\n",temp);
			switch(temp)
			{
				case 0x3002:	//句号无法显示,转换为GBK编码句号
					temp = 0xA1A3;break;//'。';	break;
				default : 
					temp = OneUNICODEtoGBK(temp);break;	//编码转换
			}
			//lcd_printf("temp2 = 0x%04X\r\n",temp);
			pStr[cnt++] = temp >> 8 ;
			pStr[cnt++] = temp & 0xff;
		}
	}
	return cnt;
}

/*************************************************************************************************************************
*函数        	:	u32 GSM_StringToHex(char *pStr, u8 NumDigits)
*功能        	:	将16进制样式字符串转换为16进制整型数(必须保证字符串字母都是大写)
*参数        	:	pStr:字符串起始指针
* 					NumDigits:数字位数,16进制数字位数
*返回        	:	转换后的数字
*依赖        	:	无
*作者        	:	cp1300@139.com
*时间        	:	2013-04-30
*最后修改时间	:	2013-10-17
*说明        	:	比如字符串"A865"转换后为0xA865,位数为4位
					必须保证字符串字母都是大写
*************************************************************************************************************************/
static u32 GSM_StringToHex(char *pStr, u8 NumDigits)
{
	u8 temp;
	u32 HEX = 0;
	u8 i;
	
	NumDigits = (NumDigits > 8) ? 8 : NumDigits;	//最大支持8位16进制数
	
	for(i = 0;i < NumDigits;i ++)
	{
		HEX <<= 4;
		temp = pStr[i];
		temp = (temp > '9') ? temp - 'A' + 10 : temp - '0';
		HEX |= temp;
	}
	return HEX;
}

/*************************************************************************************************************************
*函数        	:	void GSM_HexToString(u32 HexNum,c har *pStr, u8 NumDigits)
*功能        	:	将整型数字转换为16进制样式字符串(字母为大写,不带结束符)
*参数        	:	HexNum:16进制数字
					pStr:字符缓冲区指针
* 					NumDigits:数字位数,16进制数字位数
*返回        	:	无
*依赖        	:	无
*作者        	:	cp1300@139.com
*时间        	:	2013-04-30
*最后修改时间	:	2013-04-30
*说明        	:	比如字符串0xA865转换后为"A865",位数为4位
*************************************************************************************************************************/
static void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits)
{
	u8 temp;
	u8 i;
	
	NumDigits = (NumDigits > 8) ? 8 : NumDigits;	//最大支持8位16进制数
	
	for(i = 0;i < NumDigits;i ++)
	{
		temp = 0x0f & (HexNum >> (4 * (NumDigits - 1 - i)));
		temp = (temp > 0x09) ? (temp - 0x0A + 'A') : (temp + '0');
		pStr[i] = temp;
	}
}

/*************************************************************************************************************************
*函数        	:	u32 GSM_StringToDec(char *pStr, u8 NumDigits)
*功能        	:	将10进制样式字符串转换为整型数(必须保证完全为数字字符)
*参数        	:	pStr:字符串起始指针
* 					NumDigits:数字位数,10进制数字位数
*返回        	:	转换后的数字
*依赖        	:	无
*作者        	:	cp1300@139.com
*时间        	:	2013-04-30
*最后修改时间	:	2013-04-30
*说明        	:	比如字符串"1865"转换后为1865,位数为4位
					必须保证完全为数字字符
*************************************************************************************************************************/
u32 GSM_StringToDec(char *pStr, u8 NumDigits)
{
	u32 temp;
	u32 DEC = 0;
	u8 i;
	u8 j;
	
	NumDigits = (NumDigits > 10) ? 10 : NumDigits;	//最大支持10位10进制数
	
	for(i = 0;i < NumDigits;i ++)
	{
		temp = pStr[i] - '0';
		if(temp > 9)			//只能是数字范围
			return 0;
		for(j = 1;j < (NumDigits - i);j ++)
		{
			temp *= 10;
		}
		DEC += temp;
	}
	return DEC;
}

/*************************************************************************************************************************
* 函数			:	SIM900_CALLS SIM900_TestCallStatus(void)
* 功能			:	SIM900 通话状态检测
* 参数			:	retry:重试次数
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	每隔20ms向SIM900发送一个"AT",等待响应返回
*************************************************************************************************************************/
SIM900_CALLS SIM900_TestCallStatus(void)
{
	u32 cnt;
	u8 retry = SIM900_RETRY;
	char *p;

	
	do
	{
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		SIM900_SendATcom("AT+CPAS");							
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))		//等待响应,超时200ms
		{
			p = strstr((const char*)SIM900_Buff, "+CPAS:");						//搜索字符"+CPAS"
			if(p != NULL) 				
			{	
				cnt = GSM_StringToDec(p + 7, 1);								//获取状态编码
				if(cnt > SIM900_CALL_CENTER)
					return SIM900_CALL_ERROR;
				else return (SIM900_CALLS)cnt;
			}
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	return SIM900_CALL_ERROR;
}

/*************************************************************************************************************************
* 函数			:	bool SIM900_HangUp(void)
* 功能			:	SIM900 挂掉电话
* 参数			:	无
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	
*************************************************************************************************************************/
bool SIM900_HangUp(void)
{
	u32 cnt;
	u8 retry = SIM900_RETRY;

	//检测模块存在
	do
	{
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		SIM900_SendATcom("ATH");			//挂机											
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200ms
		{
			return TRUE;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	return FALSE;
}

/*************************************************************************************************************************
* 函数			:	bool SIM900_GetServeNumber(PHONE_NUMBER *pServeNumber)
* 功能			:	获取短信服务中心号码
* 参数			:	pServeNumber:电话号码存储缓冲区指针
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	获取SIM卡内部的短信服务中心号码,一般在办理SIM卡的时候已经进行了设置.
					如果没有预置短信中心号码需要使用手机进行设置
*************************************************************************************************************************/
bool SIM900_GetServeNumber(PHONE_NUMBER *pServeNumber)
{
	u8 n;
	u32 cnt;
	char *p,*p1;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{	
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		//+CSCA: "+8613800270500",145
		SIM900_SendATcom("AT+CSCA?");			//发送"AT+CSCA",获取短信服务中心号码
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			p = strstr((const char*)SIM900_Buff, "+CSCA:");			//搜索字符"+CSCA:"
			if(p != NULL) 											//搜索成功
			{
				p = strstr(p+1, "+");	//搜索"+"
				if(p != NULL)
				{
					p1 = strstr(p+1, "\"");	//搜索"\""
					if(p1 != NULL)			
					{
						n = p1 - (p+1);	//计算电话号码长度
						pServeNumber->PhoneNumLen = (n > PHONE_NUMBER_MAX_LEN) ? PHONE_NUMBER_MAX_LEN : n;	//存储短信服务中心号码长度
						p ++;					//跳过前面的"+"
						for(n = 0;n < pServeNumber->PhoneNumLen;n ++)
						{
							pServeNumber->PhoneNumBuff
 = p
;	//复制电话号码
						}
						pServeNumber->PhoneNumBuff
 = '\0';		//添加结束符
						SIM900_debug("短信中心号码:%s(长度:%d)\r\n",pServeNumber->PhoneNumBuff,pServeNumber->PhoneNumLen);
						return TRUE;
					}
				}
			}
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	return FALSE;
}

/*************************************************************************************************************************
* 函数			:	bool SIM900_GetPhoneNumber(PHONE_NUMBER *pPhoneNumber)
* 功能			:	获取本机号码
* 参数			:	CenterPhone:电话号码存储缓冲区指针
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	cp1300@139.com
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	通常会预存本机号码到SIM卡,也可能没有
*************************************************************************************************************************/
bool SIM900_GetPhoneNumber(PHONE_NUMBER *pPhoneNumber)
{
	u8 n;
	u32 cnt;
	char *p,*p1;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{	
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		//+CNUM: "","15871750634",129,7,4
		SIM900_SendATcom("AT+CNUM");										//发送"AT++CNUM",获取号码
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			p = strstr((const char*)SIM900_Buff, "+CNUM:");					//搜索字符"+CNUM:"
			if(p != NULL) 													//搜索成功
			{
				p = strstr(p+1, "\",\"");	//搜索"",""
				if(p != NULL)
				{
					p1 = strstr(p+3, "\",");	//搜索"","
					if(p1 != NULL)			
					{
						n = p1 - (p+3);			//计算电话号码长度
						pPhoneNumber->PhoneNumLen = (n > PHONE_NUMBER_MAX_LEN) ? PHONE_NUMBER_MAX_LEN : n;	//存储号码长度
						p +=3;					//跳过前面的"\",\""
						for(n = 0;n < pPhoneNumber->PhoneNumLen;n ++)
						{
							pPhoneNumber->PhoneNumBuff
 = p
;	//复制电话号码
						}
						pPhoneNumber->PhoneNumBuff
 = '\0';		//添加结束符
						SIM900_debug("本机号码:%s(长度:%d)\r\n",pPhoneNumber->PhoneNumBuff,pPhoneNumber->PhoneNumLen);
						return TRUE;
					}
				}
			}
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	return FALSE;
}

/*************************************************************************************************************************
* 函数				:	int SIM900_GetSignal(void)
* 功能				:	获取信号强度
* 参数				:	无
* 返回				:	<0:获取失败;0-31:信号强度;
* 依赖				:	底层
* 作者				:	cp1300@139.com
* 时间				:	2013-10-21
* 最后修改时间 	: 	2013-10-21
* 说明				: 	无
*************************************************************************************************************************/
int SIM900_GetSignal(void)
{
	u8 temp;
	u32 cnt;
	char *p;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{	
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		//+CSQ: 27,0
		//+CSQ: 5,0
		SIM900_SendATcom("AT+CSQ");											//发送"AT++CSQ",获取号码
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			p = strstr((const char*)SIM900_Buff, "+CSQ:");					//搜索字符"+CSQ:"
			if(p != NULL) 													//搜索成功
			{
				if(p[7] == ',')	//信号强度为1位数
				{
					temp = GSM_StringToDec(&p[6], 1);
				}
				else
				{
					temp = GSM_StringToDec(&p[6], 2);
				}
				
				return temp;
			}
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	return -1;
}

/*************************************************************************************************************************
* 函数				:	SIM900_NETSTATUS SIM900_GetNetworkStatus(void)
* 功能				:	获取网络注册状态
* 参数				:	无
* 返回				:	SIM900_NETSTATUS
* 依赖				:	底层
* 作者				:	cp1300@139.com
* 时间				:	2013-10-29
* 最后修改时间 	: 	2013-10-29
* 说明				: 	无
*************************************************************************************************************************/
SIM900_NETSTATUS SIM900_GetNetworkStatus(void)
{
	u32 cnt;
	char *p;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{	
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		//+CREG: 0,1
		SIM900_SendATcom("AT+CREG?");											//发送"AT+CREG?",获取网络注册状态
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			p = strstr((const char*)SIM900_Buff, "+CREG:");					//搜索字符"+CSQ:"
			if(p != NULL) 													//搜索成功
			{
				return (SIM900_NETSTATUS)GSM_StringToDec(&p[9], 1);
			}
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	
	return SIM900_NET_ERROR;
}

//PDU模式短信限制长度,最大70个字符,不分中英文
//返回:限制之后的字符个数
u32 GSM_PDUStrRes(char *pStr)
{
	u32 n = 0;

	while(*pStr != 0)
	{
		n ++;
		if(n == 71)
		{
			SIM900_debug("PDU模式短信长度超出70B,强制为70B!\r\n");
			*pStr = 0;		//强制添加结束符
			return n;
		}
		if((u8)*pStr < 0x80)	//ASCII
		{
			pStr ++;
		}
		else if((u8)*pStr > 0x80)	//中文
		{			
			pStr += 2;
		}
		
	}
	
	return n;
}

//发送一条短信
//短信电话号码长度按照字节算但是短信中心号码按照半字节算
//0891683108100005F0 1100 0D 91685156525310F30008AA0C 9E3F9E4475355B5079D16280
/*************************************************************************************************************************
*函数        	:	bool GSM_SendOneSMS(char *pSMS, u8 *pPDU, char *pServeNumber, char *pPhoneNumber)
*功能        	:	发送一条普通短信,正常长度
*参数        	:	pSMS:短信内容缓冲区指针,内容为文本文档,并且字符串需要结束符
* 					pPDU:PDU数据缓冲区指针
					pServeNumber:短信中心号码
					pPhoneNumber:目标手机号码结构指针
*返回        	:	TRUE:短信发送成功;FALSE:短信发送失败
*依赖        	:	底层
*作者        	:	cp1300@139.com
*时间        	:	2013-04-04
*最后修改时间	:	201310-23
*说明        	:	短信文本需要添加结束符
					电话号码必须以86等国际区号开头
					PDU可以发送中文,但是text只能发送英文
*************************************************************************************************************************/
bool GSM_SendOneSMS(char *pSMS, u8 *pPDU, char *pServeNumber, char *pPhoneNumber)
{
	SIM900_ERROR error;
	u16 OffsetCnt = 0;		//缓冲区偏移计数器
	u32 cnt;
	u16 temp;
	char ComBuff[16];
	u16  nSMSCenterLen= 0, nSMSPduLen = 0;
	u16 SMSLen = 0;			//短信字符长度
	FunctionalState EnableU2S = DISABLE;	//使能U2S编码模式,默认为7BIT编码模式
	u8 *p = (u8 *)pSMS;
	
	while(*p != 0)
	{
		if(*p >= 0x80)		//有汉字
		{
			EnableU2S = ENABLE;	//使能U2S编码模式
			SIM900_debug("需要发送的短信为PDU格式\r\n");
			break;
		}
		p ++;
	}
	
				
	if(EnableU2S == ENABLE)			//使能了U2S编码模式
	{
		SMSLen = GSM_PDUStrRes(pSMS);	//限制PDU短信长度,计算短信长度
	}
	else 							//TEXT模式短信
	{
		SMSLen = strlen(pSMS);		//计算短信长度
		if(SMSLen > 160)		//短信长度大于160个字符
		{
			pSMS[160] = 0;			//添加结束符,限制长度
			SMSLen = 160;
		}
	}
	
	//计算短信中心号码长度,+91,+86,短信中心号码必须由86开头,并且要加上91,长度为每个数字半字节,不足补F
	temp = (strlen(pServeNumber) + 2 + 1) / 2;	
	GSM_HexToString(temp, (char *)(pPDU+OffsetCnt), 2);	//短信中心号码长度转换为16进制样式字符串
	OffsetCnt += 2;										//跳过短信中心号码长度字节
	
	pPDU[OffsetCnt++] = '9';	//服务中心类型
	pPDU[OffsetCnt++] = '1';
	OffsetCnt += PhoneNumtoPDUChar((u8 *)pServeNumber,(char *)(pPDU+OffsetCnt),strlen(pServeNumber));	//短信中心号码
	nSMSCenterLen = OffsetCnt / 2;
	//! PDU
	pPDU[OffsetCnt++] = '1';
	pPDU[OffsetCnt++] = '1';
	//! For MR
	pPDU[OffsetCnt++] = '0';
	pPDU[OffsetCnt++] = '0';
	//! For DA
	
	//计算电话号码长度,+86,发送短信的电话号码由86开头,电话号码长度为字符个数
	GSM_HexToString(strlen(pPhoneNumber), (char *)(pPDU+OffsetCnt), 2);	//手机号码长度转换为16进制样式字符串
	OffsetCnt += 2;	//跳过手机号码长度字节
	
	pPDU[OffsetCnt++] = '9';	//服务中心类型
	pPDU[OffsetCnt++] = '1';
	OffsetCnt += PhoneNumtoPDUChar((u8 *)pPhoneNumber,(char *)(pPDU+OffsetCnt),strlen(pPhoneNumber));	//短信发送号码
	//! For PID
	pPDU[OffsetCnt++] = '0';
	pPDU[OffsetCnt++] = '0';
	//! For DCS
	if(EnableU2S == ENABLE)			//U2S
	{
		pPDU[OffsetCnt++] = '0';
		pPDU[OffsetCnt++] = '8';
	}
	else 							//7BIT
	{
		pPDU[OffsetCnt++] = '0';
		pPDU[OffsetCnt++] = '0';
	}
	
	//! For VP
	pPDU[OffsetCnt++] = 'A';
	pPDU[OffsetCnt++] = 'A';
	
	//! For UDL AND UD
	  //! 注意,此处先将用户数据长度设置为00,并
	  //! 记录此时的缓冲区位置,然后等编码完成, 
	  //! 确定了用户数据长度后再修改为实际长度
	  cnt = OffsetCnt;
	  pPDU[OffsetCnt++] = '0';
	  pPDU[OffsetCnt++] = '0'; 	
	
	//短信内容
	if(EnableU2S == ENABLE)			//U2S
	{
		temp = StringToUnicodeStr(pSMS,(char *)&pPDU[OffsetCnt], strlen(pSMS));//将短信数据转换为字符数据
		OffsetCnt += temp;
		GSM_HexToString(temp/2, (char *)&pPDU[cnt], 2);
		//! PDU串的长度,后面AT+CMGS要用到此长度
		nSMSPduLen = OffsetCnt / 2 -nSMSCenterLen;
	}
	else 							//7bit
	{
		u8 buff[140];				//TEXT短信缓冲区
		
		temp = gsmEncode7bit(pSMS, buff);						//将ASCII转换为7bit编码
		GSM_HexToString(SMSLen, (char *)&pPDU[cnt], 2);
		
		for(cnt = 0;cnt < temp;cnt ++)
		{
			GSM_HexToString(buff[cnt], (char *)&pPDU[OffsetCnt+cnt*2], 2);	//7bit编码转换为16进制格式字符串
		}
		OffsetCnt += (temp << 1);
		//! PDU串的长度,后面AT+CMGS要用到此长度
		nSMSPduLen = OffsetCnt / 2 -nSMSCenterLen;
	}
	
						//短信内容长度转换为16进制样式字符串,存储短信长度
	
	//end
	pPDU[OffsetCnt++] = 0x1A;
	pPDU[OffsetCnt++] = 0x00;
	
	SIM900_debug("\r\n%s\r\n",pPDU);
	
	//! 下面是发送过程
	//! AT
	if(SIM900_TestAT(10) == FALSE)	//串口同步失败
	{
		SIM900_WaitSleep(1000);	//等待上一个操作完成
	}

	//! ATE0
	SIM900_SendATcom("ATE0");
	if(AT_RETURN_OK != SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
	{
		return FALSE;
	}

	//! AT+CMGF
	SIM900_SendATcom("AT+CMGF=0");
	if(AT_RETURN_OK != SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
	{
		return FALSE;
	}

	
	//! AT+CMGS//////////////////////////////////////////
	sprintf(ComBuff, "AT+CMGS=%d", nSMSPduLen);
	SIM900_debug("AT+CMGS=%d\r\n", nSMSPduLen);
	SIM900_SendATcom(ComBuff);
	if(AT_RETURN_ERROR == SIM900_GetATResp(SIM900_Buff, &cnt, ">", 10, 20))	//等待响应,超时200MS
	{  
		return FALSE;
	}

	//PDU Content
	SIM900_ClearRxCnt();				//清除接收缓冲区
	SIM900_SendString((char *)pPDU);	//发送字符串
	error = SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 50);
	if(error == AT_RETURN_ERROR)		//返回错误
	{  
		return FALSE;
	}
	else
	{
		temp = 30;							//等待短信接收成功,最大等待30S
		SIM900_ClearRxCnt();				//清除接收缓冲区
		
		do
		{
			GSM_DelaySer(1);				//延时1S
			error = SIM900_GetATResp(SIM900_Buff, &cnt, "+CMGS", 10, 20);	//查询发送成功提示
			SIM900_ClearRxCnt();			//清除接收缓冲区
			if(error == AT_RETURN_OK)
			{
				SIM900_debug("短信已发送成功,对方已经接收!\r\n");
				break;
			}
			else if(error == AT_RETURN_ERROR)
			{
				SIM900_debug("短信发送失败!很有可能是欠费了!\r\n");
				return FALSE;
			}
			if(temp == 0)
			{
				SIM900_debug("短信发送超时!\r\n");
				return FALSE;
			}
		}while(temp --);	
	}
	
	//测试短信
	//0891683108200705F011000D91685172910098F40008AA086D4B8BD577ED4FE1
	return TRUE;
}

/*************************************************************************************************************************
*函数        	:	SIM900_CALLS SIM900_MakingCall(const char *pPhoneNumber, u8 TimeOut)
*功能        	:	拨打指定电话号码
*参数        	:	pPhoneNumber:电话号码字符串指针
					TimeOut:接听超时,1-255S
*返回        	:	SIM900_CALLS:拨打电话状态
*依赖        	:	底层
*作者        	:	cp1300@139.com
*时间        	:	2013-10-24
*最后修改时间	:	2013-10-24
*说明        	:	拨打电话
*************************************************************************************************************************/
SIM900_CALLS SIM900_MakingCall(const char *pPhoneNumber, u8 TimeOut)
{
	u32 cnt;
	u8 retry = SIM900_RETRY;		//重试次数
	char buff[32];
	SIM900_ERROR error;
	
	if(strlen(pPhoneNumber) > 26)	return SIM900_CALL_ERROR;	//电话号码太长了
	sprintf(buff, "ATD%s;", pPhoneNumber);
	

	if(SIM900_TestAT(10) == FALSE)	//串口同步失败
	{
		SIM900_WaitSleep(1000);	//等待上一个操作完成
	}
	do
	{	
		SIM900_SendATcom("AT+MORING=1");									//发送"AT+MORING=1",设置拨号提示
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0) return SIM900_CALL_ERROR;
	
	//拨打电话
	/*
AT+MORING=1
OK
ATD15271900894;
OK

MO RING

MO CONNECTED

+CDRIND: 0

NO CARRIER
*/
	SIM900_SendATcom(buff);												//拨号
	error = SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20);				//等待响应,超时200MS
	if(error == AT_RETURN_ERROR)		//返回错误
	{  
		return SIM900_CALL_ERROR;
	}
	else
	{
		do
		{
			GSM_DelaySer(1);											//延时1S
			error = SIM900_GetATResp(SIM900_Buff, &cnt, "MO RING", 10, 1);	//查询拨打成功提示
			if(error == AT_RETURN_OK)
			{
				SIM900_debug("呼叫成功,对方振铃中...\r\n");
				return SIM900_CALL_RING;
			}
			error = SIM900_GetATResp(SIM900_Buff, &cnt, "MO CONNECTED", 10, 1);	//查询接通标志
			if(error == AT_RETURN_OK)
			{
				SIM900_debug("对方已经接听电话!\r\n");
				return SIM900_CALL_PUT;
			}
			
			error = SIM900_GetATResp(SIM900_Buff, &cnt, "BUSY", 10, 1);	//查询接通标志
			if(error == SIM900_CALL_BUSY)
			{
				SIM900_debug("对方占线!\r\n");
				return SIM900_CALL_PUT;
			}
			SIM900_ClearRxCnt();			//清除接收缓冲区
			TimeOut --;	
		}while(TimeOut);
		if(TimeOut == 0)
		{
			SIM900_debug("拨打电话超时!\r\n");
			return SIM900_CALL_TIMEOUT;
		}
	}
	return SIM900_CALL_ERROR;
}

/*************************************************************************************************************************
*函数        	:	SIM900_CALLS SIM900_WaitGetThrough(u8 TimeOut)
*功能        	:	电话拨打成功后等待对方接听
*参数        	:	TimeOut:接听超时,1-255S
*返回        	:	SIM900_CALLS:电话接通状态
*依赖        	:	底层
*作者        	:	cp1300@139.com
*时间        	:	2013-10-26
*最后修改时间	:	2013-10-26
*说明        	:	拨打电话成功后,等待对方接通,或不接
*************************************************************************************************************************/
SIM900_CALLS SIM900_WaitGetThrough(u8 TimeOut)
{
	u32 cnt;
	SIM900_ERROR error;
	
	while(TimeOut --)
	{
		SIM900_ClearRxCnt();											//清除接收缓冲区
		GSM_DelaySer(1);												//延时1S
		error = SIM900_GetATResp(SIM900_Buff, &cnt, "MO CONNECTED", 10, 1);	//查询接通标志
		if(error == AT_RETURN_OK)
		{
			SIM900_debug("对方已经接听电话!\r\n");
			return SIM900_CALL_PUT;
		}
		error = SIM900_GetATResp(SIM900_Buff, &cnt, "NO ANSWER", 10, 1);	//查询一直未接听标志
		if(error == AT_RETURN_OK)
		{
			SIM900_debug("对方无人接听!\r\n");
			return SIM900_CALL_NO_ANSWER;
		}
		error = SIM900_GetATResp(SIM900_Buff, &cnt, "NO CARRIER", 10, 1);	//电话已经挂断
		if(error == AT_RETURN_OK)
		{
			SIM900_debug("对方拒接电话,对方已经挂断!\r\n");
			return SIM900_CALL_NO_CARRIER;
		}
	}
	SIM900_debug("对方接听电话超时!\r\n");
	return SIM900_CALL_TIMEOUT;
}

/*************************************************************************************************************************
*函数        	:	SIM900_CALLS SIM900_WaitHangUP(u8 TimeOut)
*功能        	:	电话接通后等待对方挂电话
*参数        	:	TimeOut:接听超时,1-255S
*返回        	:	SIM900_CALLS:电话接通状态
*依赖        	:	底层
*作者        	:	cp1300@139.com
*时间        	:	2013-10-26
*最后修改时间	:	2013-10-26
*说明        	:	等待对方挂电话
*************************************************************************************************************************/
SIM900_CALLS SIM900_WaitHangUP(u8 TimeOut)
{
	u32 cnt;
	SIM900_ERROR error;
	
	while(TimeOut --)
	{
		SIM900_ClearRxCnt();											//清除接收缓冲区
		GSM_DelaySer(1);												//延时1S
		error = SIM900_GetATResp(SIM900_Buff, &cnt, "NO CARRIER", 10, 1);	//电话已经挂断
		if(error == AT_RETURN_OK)
		{
			SIM900_debug("对方电话已经挂断!\r\n");
			return SIM900_CALL_NO_CARRIER;
		}
	}
	SIM900_debug("对方挂电话超时!\r\n");
	return SIM900_CALL_TIMEOUT;
}

/*************************************************************************************************************************
*函数        	:	bool SIM900_TestCall(void)
*功能        	:	查询模块是否可以拨打电话
*参数        	:	无
*返回        	:	TRUE:成功;FALSE:失败
*依赖        	:	底层
*作者        	:	cp1300@139.com
*时间        	:	2013-10-24
*最后修改时间	:	2013-10-24
*说明        	:	用于检查模块是否准备好拨打电话
*************************************************************************************************************************/
bool SIM900_TestCall(void)
{
	u32 cnt;
	u8 retry = SIM900_RETRY;		//重试次数
	
	do
	{	
		if(SIM900_TestAT(10) == FALSE)	//串口同步失败
		{
			SIM900_WaitSleep(1000);	//等待上一个操作完成
		}
		SIM900_SendATcom("AT+CCALR?");									//发送"AT+CCALR?",查询模块是否准备好
		if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "OK", 10, 20))	//等待响应,超时200MS
		{
			if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "+CCALR: 1", 10, 1))
			{
				return TRUE;
			}
			if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, "+CCALR: 0", 10, 1))
			{
				return FALSE;
			}
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0) return FALSE;
	
	return FALSE;
}

// 7-bit编码
// pSrc: 源字符串指针
// pDst: 目标编码串指针
// nSrcLength: 源字符串长度
// 返回: 目标编码串长度
static int gsmEncode7bit(const char* pSrc,u8* pDst)
{
	int nSrc;        // 源字符串的计数值
	int nDst;        // 目标编码串的计数值
	int nChar;       // 当前正在处理的组内字符字节的序号,范围是0-7
	unsigned char nLeft=0;    // 上一字节残余的数据
	int nSrcLength = strlen(pSrc);

	// 计数值初始化
	nSrc = 0;
	nDst = 0;

	// 将源串每8个字节分为一组,压缩成7个字节
	// 循环该处理过程,直至源串被处理完
	// 如果分组不到8字节,也能正确处理
	while(nSrc<nSrcLength)
	{
		// 取源字符串的计数值的最低3位
		nChar = nSrc & 7;

		// 处理源串的每个字节
		if(nChar == 0)
		{
			// 组内第一个字节,只是保存起来,待处理下一个字节时使用
			nLeft = *pSrc;
		}
		else
		{
			// 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
			*pDst = (*pSrc << (8-nChar)) + nLeft;

			// 将该字节剩下的左边部分,作为残余数据保存起来
			nLeft = *pSrc >> nChar;
			// 修改目标串的指针和计数值 pDst++;
			//SIM900_debug("%c",*pDst);
			pDst++;  nDst++;
		}
		// 修改源串的指针和计数值
		pSrc++; nSrc++;
	}

	//Nleft还有剩余,需要一个自己保留。
	nChar = nSrc & 7;
	if(nChar != 0)
	{
		*pDst=nLeft;
		nDst++; 
		pDst++;
	}
	//*pDst='\0';

	// 返回目标串长度
	return nDst;
}

    
// 7-bit解码
// pSrc: 源编码串指针,7bit编码
// pDst: 目标字符串指针
// nSrcLength: 源编码串长度
// 返回: 目标字符串长度
static int gsmDecode7bit(const u8 *pSrc, char *pDst, int nSrcLength)
{
    int nSrc;        // 源字符串的计数值
    int nDst;        // 目标解码串的计数值
    int nByte;       // 当前正在处理的组内字节的序号,范围是0-6
    unsigned char nLeft;    // 上一字节残余的数据
    
	
	
    // 计数值初始化
    nSrc = 0;
    nDst = 0;
    
    // 组内字节序号和残余数据初始化
    nByte = 0;
    nLeft = 0;
    
    // 将源数据每7个字节分为一组,解压缩成8个字节
    // 循环该处理过程,直至源数据被处理完
    // 如果分组不到7字节,也能正确处理
	
    while(nSrc<nSrcLength)
    {
        // 将源字节右边部分与残余数据相加,去掉最高位,得到一个目标解码字节
        *pDst = (((*pSrc) << nByte) | nLeft) & 0x7f;
        // 将该字节剩下的左边部分,作为残余数据保存起来
        nLeft = (*pSrc) >> (7-nByte);
    
        // 修改目标串的指针和计数值
        pDst++;
        nDst++;
    
        // 修改字节计数值
        nByte++;
    
        // 到了一组的最后一个字节
        if(nByte == 7)
        {
            // 额外得到一个目标解码字节
            *pDst = nLeft;
    
            // 修改目标串的指针和计数值
            pDst++;
            nDst++;
    
            // 组内字节序号和残余数据初始化
            nByte = 0;
            nLeft = 0;
        }
    
        // 修改源串的指针和计数值
        pSrc++;
        nSrc++;
    }
    
    *pDst = 0;	//添加结束符
    
    // 返回目标串长度
    return nDst;
}



/*************************************************************************************************************
 * 文件名:		SIM900.h
 * 功能:		STM32 SIM900底层驱动函数
 * 作者:		cp1300@139.com
 * 创建时间:		2013-04-03
 * 最后修改时间:	2013-10-16
 * 详细:		GSM_CDMA发送短信等
*************************************************************************************************************/
#ifndef SIM900_H_
#define SIM900_H_
#include "system.h"

//GSM模块相关定义
/*#define SIM900_RESET		//PBout(6)	//PB6
#define SIM900_PORON		PBout(5)	//PB5
#define GSM_STATUS_IN		PDin(2)		//PD2
#define GSM_BUZZ			PCout(12)	//PC12*/
#define SIM900_UART_CH		UART_CH3	//串口3
//GSM底层操作宏
/*#define GSM_RESET_H()	(GSM_RESET=1)
#define GSM_RESET_L()	(GSM_RESET=0)
#define GSM_PORON_H()	(GSM_PORON=1)
#define GSM_PORON_L()	(GSM_PORON=0)
#define GSM_STATUS()	(GSM_STATUS_IN)
#define GSM_BUZZ_H()	(GSM_BUZZ=1)
#define GSM_BUZZ_L()	(GSM_BUZZ=0)
#define GSM_Delay_MS(x)	Delay_MS(x)	//CDMA GSM操作延时,单位MS*/
//GSM/CDMA模块UART相关接口		
#define SIM900_SendATcom(x)				UARTx_ClearRxCnt(SIM900_UART_CH);UARTx_SendString(SIM900_UART_CH,x);UARTx_SendString(SIM900_UART_CH,"\r\n")		//调用串口发送一个AT命令,并且先清除接收计数器
#define SIM900_SendData(data,len)		UARTx_SendData(SIM900_UART_CH, data, len);	//发送指定长度数据
#define SIM900_SendString(x)			UARTx_SendString(SIM900_UART_CH, x)			//发送字符串
#define SIM900_GetRxCnt()				UARTx_GetRxCnt(SIM900_UART_CH);				//获取新数据计数器
#define SIM900_ClearRxCnt()				UARTx_ClearRxCnt(SIM900_UART_CH);			//清除新数据计数器
#define SIM900_UartInit()				UARTx_Init(SIM900_UART_CH, 115200, ENABLE)	//初始化串口,波特率115200,开启接收中断
#define SIM900_SetRxBuff(pBuff, size)	UARTx_SetRxBuff(SIM900_UART_CH, pBuff,size)	//设置串口接收缓冲区

#define GSM_DelayMS(x)					OSTimeDlyHMSM(0,0,0,x)					//延时ms,最大延时999ms
#define GSM_Delay10MS()					OSTimeDlyHMSM(0,0,0,10)					//延时10ms
#define GSM_Delay100MS()				OSTimeDlyHMSM(0,0,0,100)				//延时100ms
#define GSM_DelaySer(x)					OSTimeDlyHMSM(0,0,x,0)					//S延时,最大59S

//SIM900返回错误
typedef enum
{
	AT_RETURN_OK			=		0,		//返回成功
	AT_RETURN_ERROR			=		1,		//返回错误
	AT_RETURN_UNKNOWN		=		2,		//返回结果未知
	AT_RETURN_TIME_OUT		=		0xf,	//等待返回超时
}SIM900_ERROR;

//短信发送日期,使用字符格式
typedef __packed struct
{
	u8	Year;		//年20xx年
	u8	Month;		//月
	u8	Day;		//日
	u8	Hour;		//小时
	u8	Minute;		//分钟
	u8	Second;		//秒
	u8	Reserve1;	//保留
	u8	Reserve2;	//保留
}SMS_TIMER ;

//短信解析相关//注意要保证数据对齐
#define SMS_NUM_LEN_MAX		16		//电话号码最大长度16位
typedef __packed struct
{
	SMS_TIMER		Timer;						//短信发送的时间	
	char			NumBuff[SMS_NUM_LEN_MAX];	//电话号码缓冲区,使用的是字符模式				
	u8				NumLen;						//电话号码长度
	u8				SMS_Size;					//短信有效内容长度,最大140B
	u8				TEXT_MODE;					//1:短信为TEXT模式;0:短信为PDU模式
	u8				PDU;						//PDU数据,用于区分是否有短信头部信息
	u8				DSC;						//DSC数据,用于区分是否为字符模式(0),PDU模式(0X08)
	u8				AllNum;						//当前短信总分割数
	u8				PreNum;						//当前位置
	u8				IndexNum;					//当前索引位置1-50
}SMS_INFO ;

//GSM/CDMA模块型号
typedef enum
{
	GSM_MG323	=	0,		//GSM_CDMA模块型号,MG323
	CDMA_MC323	=	1,		//GSM_CDMA模块型号,MC323
	GSM_SIM900A	=	2,		//GSM_CDMA模块SIM900A
	GSM_UNKNOWN	=	0xff	//未知模块
}GSM_TYPE;

//SIM900删除短信选择
typedef enum
{
	DEL_READ_SMS	=	1,	//删除所有已读短信
	DEL_UNREAD_SMS	=	2,	//删除所有未读短信
	DEL_SENT_SMS	=	3,	//删除所有已经发送的短信
	DEL_UNSENT_SMS	=	4,	//删除所有未发送短信
	DEL_INBOX_SMS	=	5,	//删除所有接收短信
	DEL_ALL_SMS		=	6,	//删除所有短信
}SIM900_DEL;

//通话状态
typedef enum
{
	SIM900_CALL_READY	=	0,	//准备就绪,当前空闲
	SIM900_CALL_UNKNOWN	=	1,	//未知响应指令
	SIM900_CALL_RING	=	2,	//振铃,准备好可以接通
	SIM900_CALL_CENTER	=	3,	//呼叫进行中
	SIM900_CALL_TIMEOUT	=	4,	//拨打电话超时
	SIM900_CALL_PUT		=	5,	//拨打的电话对方已经接通
	SIM900_CALL_NO_ANSWER=	6,	//对方无人接听
	SIM900_CALL_NO_CARRIER=	7,	//对方已经挂断
	SIM900_CALL_BUSY	=	8,	//占线
	SIM900_CALL_ERROR	=	0xff//其他错误
}SIM900_CALLS;

//网络注册状态
typedef enum
{
	SIM900_NET_NOT = 0,	//未注册
	SIM900_NET_YES = 1,	//已经注册
	SIM900_NET_SEA = 2,	//未注册,正在搜索
	SIM900_NET_TUR = 3,	//注册被拒绝
	SIM900_NET_UNK = 4,	//未知
	SIM900_NET_ROA = 5,	//已经注册,但是漫游
	SIM900_NET_ERROR=0XFF//错误
}SIM900_NETSTATUS;

//SIM900通信缓冲区
#define SIM900_BUFF_SIZE	2048			//2KB
extern u8	SIM900_Buff[SIM900_BUFF_SIZE];	//缓冲区

#define PDU_BUFF_SIZE	1024*10				//20KB	可以一次读取50条未读短信
extern u8	SmsPduBuff[PDU_BUFF_SIZE];		//PDU数据缓冲区

//相关控制引脚
#define SIM900_GetRI()			PBin(14)			//RI PB14
#define SIM900_SetDTR(x)		(PBout(13)=x)		//DTR PB13
#define SIM900_SetRESET(x)		(PBout(15)=x)		//RESET PB15
#define SIM900_SetPWR(x)		(PBout(12)=x)		//PWR	PB12

//电话号码结构
#define PHONE_NUMBER_MAX_LEN	24-2		//电话号码最大长度
typedef __packed struct
{
	u8		PhoneNumLen;		//电话号码长度
	char	PhoneNumBuff[PHONE_NUMBER_MAX_LEN + 1];//电话号码缓冲区,电话号码前面的2位为地区编号,中国为86,打电话需要跳过前面的2位数字
}PHONE_NUMBER;

//最大重试次数,防止AT指令操作失败
#define SIM900_RETRY	2 

//API
#define SIM900_Ready()	if(SIM900_TestAT(10) == FALSE){SIM900_WaitSleep(1000);}	//让SIM900就绪,防止卡住//串口同步失败,等待上一个操作完成
void SIM900_HardwarePowerUP(void);//SIM900硬件开机
void SIM900_HardwarePowerDOWN(void);//SIM900硬件关机
void SIM900_HardwareReset(void);//SIM900硬件复位
bool GSM_SendSMS(char *pSMS, char *pPhoneNumber);//发送短信
void SIM900_HardwareInit(void);	//初始化SIM900相关的硬件
bool SIM900_ModuleInit(void);	//初始化SIM900模块
bool SIM900_TestAT(u32 retry);	//检测模块响应
bool SIM900_HangUp(void);		//挂掉电话
SIM900_CALLS SIM900_TestCallStatus(void);//检测电话通话状态
SIM900_ERROR SIM900_GetATResp(u8 *pRxBuff, u32 *pLen, const char *pKeyword, u32 ByteTime, u32 TimeOut);//获取SIM900的AT指令响应
int SIM900_GetSmsNum(void);	//获取SIM卡存储的短信数量
bool GSM_ParsePDUSMS(char *pPDU, char *pSMS, u32 PDUSize, SMS_INFO *pInfo);//解析一条PDU格式短信
SIM900_ERROR SIM900_GetUnreadSMS(u8 *pUnreadSMSBuff, u32 BuffSize, u32 *pPDUCnt);//读取SIM900所有的未读短信
SIM900_ERROR SIM900_ReadTextSMS(char *pSMS, SMS_INFO *pInfo, u16 IndexNum);//用text格式读取短信
bool GSM_ParseTextSMS(char *pText, char *pSMS, u32 TextSize, SMS_INFO *pInfo);//解析一条TEXT格式短信
bool SIM900_DelMultiSMS(SIM900_DEL DelStatus);	//批量删除SIM900短信
bool SIM900_GetServeNumber(PHONE_NUMBER *pServeNumber);	//获取短信服务中心号码
bool SIM900_GetPhoneNumber(PHONE_NUMBER *pPhoneNumber);	//获取本机号码
bool GSM_SendOneSMS(char *pSMS, u8 *pPDU, char *pServeNumber, char *pPhoneNumber);	//发送一条短信
int SIM900_GetSignal(void);	//获取信号强度
SIM900_CALLS SIM900_MakingCall(const char *pPhoneNumber, u8 TimeOut);//拨打电话
bool SIM900_TestCall(void);//检查是否可以拨打电话
void SIM900_SetSMSServeNumber(char *pSMSServeNumber,u8 NumLen);//设置短信中心号码
bool SIM900_WaitSleep(u32 TimeOut);	//等待模块空闲
SIM900_CALLS SIM900_WaitGetThrough(u8 TimeOut);//等待对方接听电话
SIM900_CALLS SIM900_WaitHangUP(u8 TimeOut);		//等待对方挂电话
SIM900_NETSTATUS SIM900_GetNetworkStatus(void);	//获取网络注册状态

u32 GSM_StringToDec(char *pStr, u8 NumDigits);				//将10进制样式字符串转换为整型数(必须保证完全为数字字符

#endif /*SIM900A_H_*/


/*************************************************************************************************************
 * 文件名:	unicode_gbk.c
 * 功能:		汉字编码转换
 * 作者:		cp1300@139.com
 * 创建时间:	2013-04-03
 * 最后修改时间:2013-04-03
 * 详细:		需要码表支持
*************************************************************************************************************/
#include "system.h"
#include "unicode_gbk.h"

#define GBK_UNICODE_IS_SDCARD	0	//GBK,UNICODE编码表在SD卡或其它存储器中

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//码表在SD卡中
#if GBK_UNICODE_IS_SDCARD

#include "ff.h"
#define GtoU	"0:/GtoU.sys" 		//GBK 转 UCICODE 编码表位置
#define UtoG	"0:/UtoG.sys"		//UCICODE 转 GBK 编码表位置

static 	FIL   GtoU_File;			//GtoU 文件工作区
static 	FIL   UtoG_File;			//UtoG 文件工作区

/*************************************************************************************************************************
* 函数	:	u8 GBK_UNICODE_Init(void)
* 功能	:	初始化GBK,UNICODE编码表
* 参数	:	无	
* 返回	:	0:初始化成功;其它:初始化失败
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	2013-04-18
* 最后修改时间 : 2013-04-18
* 说明	: 	无
*************************************************************************************************************************/ 
u8 GBK_UNICODE_Init(void)
{
 	FRESULT status;

	status = f_open(&UtoG_File, UtoG, FA_OPEN_EXISTING | FA_READ);	//以只读方式打开UNICODEtoGBK码表,打开失败返回错误
	if(status != FR_OK)	//打开失败
	{
		lcd_printf("open %s error (%d)!\r\n",UtoG, status);
		return 1;
	}

	status = f_open(&GtoU_File, GtoU, FA_OPEN_EXISTING | FA_READ);	//以只读方式打开GBKtoUNICODE码表,打开失败返回错误
	if(status != FR_OK)	//打开失败
	{
		lcd_printf("open %s error (%d)!\r\n",GtoU, status);
		return 1;
	}

	return 0;
}

/*************************************************************************************************************************
* 函数	:	u16 OneGBKtoUNICODE(u16 GBKCode)
* 功能	:	将GBK编码转换为unicode编码
* 参数	:	GBK	
* 返回	:	unicode
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneGBKtoUNICODE(u16 GBKCode)
{
	u8 ch,cl;
	UINT bw;
	u16 data;

	ch = GBKCode >> 8;
	cl = GBKCode & 0x00ff;

	ch -= 0x81;
    cl -= 0x40;
	
	f_lseek(&GtoU_File, (ch*0xbf+cl)*2);						//文件指针调到偏移位置
	if(f_read(&GtoU_File, (u8 *)&data, 2, &bw) != FR_OK)		//读取2字节
	{
	   return 0x1fff;
	}
	
    return (ch<=0x7d && cl<=0xbe) ? data : 0x1fff;

   /*	ch = GBKCode >> 8;
	cl = GBKCode & 0x00ff;

	ch -= 0x81;
    cl -= 0x40;	
    return (ch<=0x7d && cl<=0xbe) ? wUnicodes[ch*0xbf+cl] : 0x1fff;	   */

}

/*************************************************************************************************************************
* 函数	:	u16 OneUNICODEtoGBK(u16 unicode)
* 功能	:	将unicode编码转换为GBK编码
* 参数	:	unicode
* 返回	:	GBK	
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneUNICODEtoGBK(u16 unicode)  //用二分查找算法
{
	u32 offset;
	u16 temp;
	UINT bw;
	u8 buff[2];

	if(unicode<=0X9FA5)
	{
		if(unicode>=0X4E00)
			offset=unicode-0X4E00;//0x1b87		//0X4E00,汉字偏移起点
		else
			return 0x2020;		//不能显示的字符就给两个空格填充,否则乱码
	}	
	else if(unicode>0X9FA5)//是标点符号
	{
		if(unicode<0XFF01||unicode>0XFF61)
			return 0x2020;//没有对应编码	//不能显示的字符就给两个空格填充,否则乱码
		offset=unicode-0XFF01+0X9FA6-0X4E00;    
	}
	offset *= 2;

	f_lseek(&UtoG_File, offset);						//文件指针调到偏移位置
	if(f_read(&UtoG_File, buff, 2, &bw) != FR_OK)	//读取2字节
	{
	   return 0x2020;
	}

	temp = buff[0];
	temp <<= 8;
	temp += buff[1];
	return temp;	//返回找到的编码				 
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else								//码表直接在代码中
#include "unicode_gbk_code.h"

/*************************************************************************************************************************
* 函数	:	u8 GBK_UNICODE_Init(void)
* 功能	:	初始化GBK,UNICODE编码表
* 参数	:	无	
* 返回	:	0:初始化成功;其它:初始化失败
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	2013-04-18
* 最后修改时间 : 2013-04-18
* 说明	: 	无
*************************************************************************************************************************/ 
u8 GBK_UNICODE_Init(void)
{
	return 0;
}

/*************************************************************************************************************************
* 函数	:	u16 OneGBKtoUNICODE(u16 GBKCode)
* 功能	:	将GBK编码转换为unicode编码
* 参数	:	GBK	
* 返回	:	unicode
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneGBKtoUNICODE(u16 GBKCode)
{
	u8 ch,cl;

	ch = GBKCode >> 8;
	cl = GBKCode & 0x00ff;

	ch -= 0x81;
    cl -= 0x40;
    return (ch<=0x7d && cl<=0xbe) ? wUnicodes[ch*0xbf+cl] : 0x1fff;

}

/*************************************************************************************************************************
* 函数	:	u16 OneUNICODEtoGBK(u16 unicode)
* 功能	:	将unicode编码转换为GBK编码
* 参数	:	unicode
* 返回	:	GBK	
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneUNICODEtoGBK(u16 unicode)  //用二分查找算法
{
	u32 offset;
	u16 temp;

	if(unicode<=0X9FA5)
	{
		if(unicode>=0X4E00)
			offset=unicode-0X4E00;//0x1b87		//0X4E00,汉字偏移起点
		else
			return 0x2020;		//不能显示的字符就给两个空格填充,否则乱码
	}	
	else if(unicode>0X9FA5)//是标点符号
	{
		if(unicode<0XFF01||unicode>0XFF61)
			return 0x2020;//没有对应编码	//不能显示的字符就给两个空格填充,否则乱码
		offset=unicode-0XFF01+0X9FA6-0X4E00;    
	}
	offset *= 2;
	
	temp = wGBKs[offset];
	temp <<= 8;
	temp += wGBKs[offset+1];
	return temp;	//返回找到的编码				 
}

#endif //GBK_UNICODE_IS_SDCARD

/*************************************************************************************************************************
* 函数	:	void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt)
* 功能	:	将多个GBK编码转换为UNICODE
* 参数	:	pGBK:GBK编码缓冲区
* 			pUnicode:UNCODE编码缓冲区
* 			cnt:转换编码个数
* 返回	:	无	
* 依赖	:	OneGBKtoUNICODE
* 作者	:	cp1300@139.com
* 时间	:	20130403
* 最后修改时间 : 20130403
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt)
{
	while(cnt --)
	{
		*pUnicode = OneGBKtoUNICODE(*pGBK ++);
		pUnicode ++;
	}
}

/*************************************************************************************************************************
* 函数	:	void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt)
* 功能	:	将多个UNICODE编码转换为GBK
* 参数	:	pUnicode:UNCODE编码缓冲区
* 			pGBK:GBK编码缓冲区
* 			cnt:转换编码个数
* 返回	:	无	
* 依赖	:	OneUNICODEtoGBK
* 作者	:	cp1300@139.com
* 时间	:	20130403
* 最后修改时间 : 20130403
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt)
{
	while(cnt --)
	{
		*pGBK = OneUNICODEtoGBK(*pUnicode ++);
		pGBK ++;
	}
}


/*************************************************************************************************************
 * 文件名:	unicode_gbk.c
 * 功能:		汉字编码转换
 * 作者:		cp1300@139.com
 * 创建时间:	2013-04-03
 * 最后修改时间:2013-04-03
 * 详细:		需要码表支持
*************************************************************************************************************/
#include "system.h"
#include "unicode_gbk.h"

#define GBK_UNICODE_IS_SDCARD	0	//GBK,UNICODE编码表在SD卡或其它存储器中

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//码表在SD卡中
#if GBK_UNICODE_IS_SDCARD

#include "ff.h"
#define GtoU	"0:/GtoU.sys" 		//GBK 转 UCICODE 编码表位置
#define UtoG	"0:/UtoG.sys"		//UCICODE 转 GBK 编码表位置

static 	FIL   GtoU_File;			//GtoU 文件工作区
static 	FIL   UtoG_File;			//UtoG 文件工作区

/*************************************************************************************************************************
* 函数	:	u8 GBK_UNICODE_Init(void)
* 功能	:	初始化GBK,UNICODE编码表
* 参数	:	无	
* 返回	:	0:初始化成功;其它:初始化失败
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	2013-04-18
* 最后修改时间 : 2013-04-18
* 说明	: 	无
*************************************************************************************************************************/ 
u8 GBK_UNICODE_Init(void)
{
 	FRESULT status;

	status = f_open(&UtoG_File, UtoG, FA_OPEN_EXISTING | FA_READ);	//以只读方式打开UNICODEtoGBK码表,打开失败返回错误
	if(status != FR_OK)	//打开失败
	{
		lcd_printf("open %s error (%d)!\r\n",UtoG, status);
		return 1;
	}

	status = f_open(&GtoU_File, GtoU, FA_OPEN_EXISTING | FA_READ);	//以只读方式打开GBKtoUNICODE码表,打开失败返回错误
	if(status != FR_OK)	//打开失败
	{
		lcd_printf("open %s error (%d)!\r\n",GtoU, status);
		return 1;
	}

	return 0;
}

/*************************************************************************************************************************
* 函数	:	u16 OneGBKtoUNICODE(u16 GBKCode)
* 功能	:	将GBK编码转换为unicode编码
* 参数	:	GBK	
* 返回	:	unicode
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneGBKtoUNICODE(u16 GBKCode)
{
	u8 ch,cl;
	UINT bw;
	u16 data;

	ch = GBKCode >> 8;
	cl = GBKCode & 0x00ff;

	ch -= 0x81;
    cl -= 0x40;
	
	f_lseek(&GtoU_File, (ch*0xbf+cl)*2);						//文件指针调到偏移位置
	if(f_read(&GtoU_File, (u8 *)&data, 2, &bw) != FR_OK)		//读取2字节
	{
	   return 0x1fff;
	}
	
    return (ch<=0x7d && cl<=0xbe) ? data : 0x1fff;

   /*	ch = GBKCode >> 8;
	cl = GBKCode & 0x00ff;

	ch -= 0x81;
    cl -= 0x40;	
    return (ch<=0x7d && cl<=0xbe) ? wUnicodes[ch*0xbf+cl] : 0x1fff;	   */

}

/*************************************************************************************************************************
* 函数	:	u16 OneUNICODEtoGBK(u16 unicode)
* 功能	:	将unicode编码转换为GBK编码
* 参数	:	unicode
* 返回	:	GBK	
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneUNICODEtoGBK(u16 unicode)  //用二分查找算法
{
	u32 offset;
	u16 temp;
	UINT bw;
	u8 buff[2];

	if(unicode<=0X9FA5)
	{
		if(unicode>=0X4E00)
			offset=unicode-0X4E00;//0x1b87		//0X4E00,汉字偏移起点
		else
			return 0x2020;		//不能显示的字符就给两个空格填充,否则乱码
	}	
	else if(unicode>0X9FA5)//是标点符号
	{
		if(unicode<0XFF01||unicode>0XFF61)
			return 0x2020;//没有对应编码	//不能显示的字符就给两个空格填充,否则乱码
		offset=unicode-0XFF01+0X9FA6-0X4E00;    
	}
	offset *= 2;

	f_lseek(&UtoG_File, offset);						//文件指针调到偏移位置
	if(f_read(&UtoG_File, buff, 2, &bw) != FR_OK)	//读取2字节
	{
	   return 0x2020;
	}

	temp = buff[0];
	temp <<= 8;
	temp += buff[1];
	return temp;	//返回找到的编码				 
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else								//码表直接在代码中
#include "unicode_gbk_code.h"

/*************************************************************************************************************************
* 函数	:	u8 GBK_UNICODE_Init(void)
* 功能	:	初始化GBK,UNICODE编码表
* 参数	:	无	
* 返回	:	0:初始化成功;其它:初始化失败
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	2013-04-18
* 最后修改时间 : 2013-04-18
* 说明	: 	无
*************************************************************************************************************************/ 
u8 GBK_UNICODE_Init(void)
{
	return 0;
}

/*************************************************************************************************************************
* 函数	:	u16 OneGBKtoUNICODE(u16 GBKCode)
* 功能	:	将GBK编码转换为unicode编码
* 参数	:	GBK	
* 返回	:	unicode
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneGBKtoUNICODE(u16 GBKCode)
{
	u8 ch,cl;

	ch = GBKCode >> 8;
	cl = GBKCode & 0x00ff;

	ch -= 0x81;
    cl -= 0x40;
    return (ch<=0x7d && cl<=0xbe) ? wUnicodes[ch*0xbf+cl] : 0x1fff;

}

/*************************************************************************************************************************
* 函数	:	u16 OneUNICODEtoGBK(u16 unicode)
* 功能	:	将unicode编码转换为GBK编码
* 参数	:	unicode
* 返回	:	GBK	
* 依赖	:	底层读写函数
* 作者	:	cp1300@139.com
* 时间	:	20120602
* 最后修改时间 : 20120602
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
u16 OneUNICODEtoGBK(u16 unicode)  //用二分查找算法
{
	u32 offset;
	u16 temp;

	if(unicode<=0X9FA5)
	{
		if(unicode>=0X4E00)
			offset=unicode-0X4E00;//0x1b87		//0X4E00,汉字偏移起点
		else
			return 0x2020;		//不能显示的字符就给两个空格填充,否则乱码
	}	
	else if(unicode>0X9FA5)//是标点符号
	{
		if(unicode<0XFF01||unicode>0XFF61)
			return 0x2020;//没有对应编码	//不能显示的字符就给两个空格填充,否则乱码
		offset=unicode-0XFF01+0X9FA6-0X4E00;    
	}
	offset *= 2;
	
	temp = wGBKs[offset];
	temp <<= 8;
	temp += wGBKs[offset+1];
	return temp;	//返回找到的编码				 
}

#endif //GBK_UNICODE_IS_SDCARD

/*************************************************************************************************************************
* 函数	:	void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt)
* 功能	:	将多个GBK编码转换为UNICODE
* 参数	:	pGBK:GBK编码缓冲区
* 			pUnicode:UNCODE编码缓冲区
* 			cnt:转换编码个数
* 返回	:	无	
* 依赖	:	OneGBKtoUNICODE
* 作者	:	cp1300@139.com
* 时间	:	20130403
* 最后修改时间 : 20130403
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt)
{
	while(cnt --)
	{
		*pUnicode = OneGBKtoUNICODE(*pGBK ++);
		pUnicode ++;
	}
}

/*************************************************************************************************************************
* 函数	:	void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt)
* 功能	:	将多个UNICODE编码转换为GBK
* 参数	:	pUnicode:UNCODE编码缓冲区
* 			pGBK:GBK编码缓冲区
* 			cnt:转换编码个数
* 返回	:	无	
* 依赖	:	OneUNICODEtoGBK
* 作者	:	cp1300@139.com
* 时间	:	20130403
* 最后修改时间 : 20130403
* 说明	: 	需要flash中的码表支持
			GBK码范围,高8位:0x81~0xfe;低8位:0x40~0xfe
*************************************************************************************************************************/ 
void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt)
{
	while(cnt --)
	{
		*pGBK = OneUNICODEtoGBK(*pUnicode ++);
		pGBK ++;
	}
}


/*************************************************************************************************************
 * 文件名:	unicode_gbk.h
 * 功能:		汉字编码转换
 * 作者:		cp1300@139.com
 * 创建时间:	2013-04-03
 * 最后修改时间:2013-04-03
 * 详细:		需要码表支持
*************************************************************************************************************/
#ifndef UNICODE_GBK_H_
#define UNICODE_GBK_H_
#include "system.h"

u8 GBK_UNICODE_Init(void);
u16 OneGBKtoUNICODE(u16 GBKCode);
u16 OneUNICODEtoGBK(u16 unicode);

void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt);	//将多个GBK编码转换为UNICODE
void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt);	//将多个UNICODE编码转换为GBK

#endif /*UNICODE_GBK_H_*/


短信接收

if(SIM900_GetSmsNum() > 0)	//有消息
				{
					uart_printf("有短信需要读取!\r\n");
					SIM900_TestAT(100);
					error = SIM900_GetUnreadSMS(SmsPduBuff, PDU_BUFF_SIZE, &cnt);		//读取SIM900所有的未读短信					
					if(error == AT_RETURN_OK)
					{
						p = (char *)SmsPduBuff;						
						while(1)														//循环解析所有短信
						{
							p = (char *)strstr(p, "+CMGL:");
							if(p == NULL) break;	
							else
							{
								if(GSM_ParsePDUSMS(p, SMS_Buff,cnt-((u32)p - (u32)SmsPduBuff) , &SMS_Info) ==TRUE)
								{
									uart_printf("\r\n***************************************************\r\n");
									uart_printf("短信索引:%d\r\n",SMS_Info.IndexNum);			//打印短信索引
									uart_printf("电话号码:%s\r\n",SMS_Info.NumBuff);			//打印电话号码
									uart_printf("发送时间:20%d-%d-%d %d:%d:%d\r\n", SMS_Info.Timer.Year, SMS_Info.Timer.Month, SMS_Info.Timer.Day, SMS_Info.Timer.Hour, SMS_Info.Timer.Minute, SMS_Info.Timer.Second);				//打印发送时间
									uart_printf("短信长度:%d\r\n",SMS_Info.SMS_Size);			//打印发送时间	
									uart_printf("短信内容:%s\r\n",SMS_Buff);					//短信内容
									uart_printf("***************************************************\r\n\r\n");


转载地址:http://blog.csdn.net/cp1300/article/details/28850709
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: