- /*************************************************************************************************************
- * 文件名: 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[n] = p[n]; //复制电话号码
- }
- pServeNumber->PhoneNumBuff[n] = '\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[n] = p[n]; //复制电话号码
- }
- pPhoneNumber->PhoneNumBuff[n] = '\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.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[n] = p[n]; //复制电话号码 } pServeNumber->PhoneNumBuff[n] = '\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[n] = p[n]; //复制电话号码 } pPhoneNumber->PhoneNumBuff[n] = '\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_*/
/*************************************************************************************************************
* 文件名: 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.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_*/
/*************************************************************************************************************
* 文件名: 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
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");