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