SIM900/SIM900A 模块实现收发短信,打电话
扫描二维码
随时随地手机看文章
实现了收发短信,并且支持字符短信和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 




