当前位置:首页 > 芯闻号 > 充电吧
[导读]实现了收发短信,并且支持字符短信和PDU格式短信,支持电话拨打与接听长期工作稳定//SIM900.C/*************************************************

实现了收发短信,并且支持字符短信和PDU格式短信,支持电话拨打与接听

长期工作稳定


//SIM900.C


/*************************************************************************************************************
 * 文件名:			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] = '';		//添加结束符
	SIM900_debug("设置短信中心号码为:%srn",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("模块进入空闲模式失败!rn");
		return FALSE;
	}
	GSM_Delay100MS();						//延时100ms
	
	SIM900_debug("模块进入空闲模式成功!rn");
	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("由于短信中心号码设置失败,导致短信无法发送!rn");
		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("发送短信成功!rn");
			
			
		}
		else
		{
			SIM900_debug("发送短信失败!rn");
			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("rn关闭AT回显模式成功!rn");
			break;
		}
		
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("rn关闭AT回显模式失败!rn");
		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("rn设置短消息格式为PDU格式成功!rn");
			break;
		}
		
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("rn设置短消息格式为PDU格式失败!rn");
		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("rn启动RI引脚提示成功!rn");
			break;
		}
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("rn启动RI引脚提示失败!rn");
		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("rn设置SLEEP成功!rn");
			break;
		}
		
		SIM900_Ready();	//等待就绪
		retry --;
	}while(retry);
	if(retry == 0)
	{
		SIM900_debug("rn设置SLEEP失败!rn");
		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
* 说明				: 	本函数会在接收缓冲区字符串结束添加''
						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("rnAT指令返回超时rn");
		return AT_RETURN_TIME_OUT;			//返回超时错误
	}
	//数据接收完毕
	*pLen = cnt2;							//返回接收数据长度
	pRxBuff[cnt2]	= '';					//将数据结尾添加结束字符串
	
	SIM900_debug("%srn",pRxBuff);			//打印返回信息

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


/*************************************************************************************************************************
* 函数			:	int SIM900_GetSmsNum(void)
* 功能			:	获取SIM卡存储的短信数量
* 参数			:	无
* 返回			:	IndexNum = GSM_StringToDec(p + 7, 2);	//短信索引可能是1位数,也有可能是2位数,通过判断后面是否为','
	else pInfo->IndexNum = GSM_StringToDec(p + 7, 1);;
				
	p = strstr((const char*)p, "rn");	//寻找短信PDU开始位置
	cnt = ((u32)p - (u32)pPDU) + 2;		//找到短信PDU开始的位置了
	if(p == NULL || cnt >= PDUSize)
	{
		pInfo->SMS_Size = 0;
		SIM900_debug("短信解析错误!rn");
		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=%drn",pInfo->NumLen);
	//uart_printf("%srn",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) = %drn",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/%drn",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格式)rn");
			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:%srn",pSMS);
		}break;
		case 0x04:	//8bit编码
		{
			SIM900_debug("短信为8bit编码(不支持)rn");
			return FALSE;
		}
		case 0x08:	//UCS2编码
		{
			SIM900_debug("短信为UCS2编码(PDU格式)rn");
			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<SMS_Size] = '';				//添加结束符		
	
	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] = '';						//添加结束符
	p = strstr((const char*)pText, "+CMGR:");
	p = strstr((const char*)p, "rn");	//寻找短信TEXT开始位置
	
	cnt = ((u32)p - (u32)pText) + 2;		//找到短信TEXT开始的位置了
	if(p == NULL || cnt >= TextSize)
	{
		SIM900_debug("TEXT短信解析错误!rn");
		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)) & 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 < '9') ? H - 'A' + 10 : H - '0';
			L = (L > '9') ? L - 'A' + 10 : L - '0';	
			temp |= (H << 4) + L;
			//lcd_printf("temp1 = 0x%04Xrn",temp);
			switch(temp)
			{
				case 0x3002:	//句号无法显示,转换为GBK编码句号
					temp = 0xA1A3;break;//'。';	break;
				default : 
					temp = OneUNICODEtoGBK(temp);break;	//编码转换
			}
			//lcd_printf("temp2 = 0x%04Xrn",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 < '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(u
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

电子数据的存储与共享在我们生活中占据越来越重要的地位,而传统的硬盘存储已然难以满足人们日益增长的数据存储需求,为此网络附加存储(NAS)则以其便捷、高效的特点,逐渐受到广大用户的青睐。但是提到NAS,很多人可能会觉得它是...

关键字: 存储 铁威马NAS 硬盘存储

4月25日,以“分享鸿蒙技术特性,交流鸿蒙生态共建”为主题的HDD·行业沙龙在江西武功山成功举行。华为产品专家们现场带来了诸多精彩分享,吸引了来自政务、金融、新闻资讯等多个行业的四十余家软件服务商到场参加。

关键字: 鸿蒙 华为 智能设备

4月25日,2024(第十八届)北京国际汽车展览会拉开序幕,车展以“新时代·新汽车”为主题,一直持续到5月4日。本次车展将有全球首发车117台(其中跨国公司全球首发车30台),41款概念车及278款新能源车型展出。

关键字: 北京车展 新能源汽车 电动汽车

LED驱动模块RSC6218A 5W-18W迷你高效驱动电源应用,小功率、小体积、高效率

关键字: LED驱动模块 驱动电源应用 LED电源芯片

业内消息,近日台积电在北美技术研讨会上宣布,正在研发 CoWoS 封装技术的下个版本,可以让系统级封装(SiP)尺寸增大两倍以上,实现 120x120mm 的超大封装,功耗可以达到千瓦级别。

关键字: CoWoS 台积电 封装

据外媒报道,字节正在内部探索出售TikTok美国业务多数股权,并援引内部人士披露的信息称 “沃尔玛或为最理想买家”。报道还称,讨论中的一种情况是字节出售美国50%以上TikTok股份,但保留少数股权。

关键字: 字节跳动 TikTok

业内消息,HMD 正在计划重启一些经典的诺基亚功能手机。今年 3 月初,该公司预告了将于 5 月发布的一款功能手机。现在该机的身份已经曝光,新款诺基亚 3210 的谍照已经泄露,展现了新机部分新特性。

关键字: 诺基亚 功能机 HMD

业内消息,近日有一位网友在各大社交媒体发文表示,自己离职后,公司将自己所有的期权全部作废。

关键字: 期权 微博

业内消息,在昨天的中关村论坛未来人工智能先锋论坛上,生数科技联合清华大学正式发布中国首个长时长、高一致性、高动态性视频大模型——Vidu。Vidu是自Sora发布之后全球率先取得重大突破的视频大模型,性能全面对标Sora...

关键字: Sora 清华 AI Vidu

近日,2024中关村论坛年会发布了10项重大科技成果名单,其中“转角氮化硼光学晶体原创理论与材料”备受关注。

关键字: 激光
关闭
关闭