SIM800/SIM900/SIM7000/SIM7600底层操作接口_句柄方式完全分离通信底层

使用SIMCOM公司通信模块已经好几年了,周末抽空把底层重新写了,将底层的通信与应用完全进行了分离,便于移植。

SIMCOM.h //定义了相关的结构体与类型。

SIMCOM_AT.c//定义了底层的AT接口

SIMCOM_GSM.c//需要的模块GSM相关命令

SIMCOM_GPRS.c//上网相关-未移植

SIMCOM_SMS.c//短信收发相关-未移植

SIMCOM_USER.c//用户最终接口

//需要自己实现数据收发相关接口,DCD,DTR,PWRKEY,STATUS相关IO接口,需要一个ms延时支持


//SIMCOM.h

/*************************************************************************************************************
 * 文件名:			SIMCOM.h
 * 功能:			SIMCOM 底层定义
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			注意:底层通信接口使用的是回调函数,但是必须提供系统延时函数 void SYS_DelayMS(u32 ms);
*************************************************************************************************************/
#ifndef _SIMCOM_H_
#define _SIMCOM_H_
#include "system.h"


//SIMCOM通信模块定义	
typedef enum
{
	SIMCOM_SIM900	=	0	,		//默认为SIM900
	SIMCOM_SIM800	=	1	,		//SIM800
	SIMCOM_SIM2000	=	2	,		//SIM2000
	SIMCOM_SIM7600	=	3	,		//SIM7600
	SIMCOM_SIM868	=	4	,		//SIM868
	SIMCOM_SIM7000C	=	5	,		//SIM7000C
	LYNQ_L700		=	10	,		//LYNQ_L700
	SIMCOM_INVALID	=	0XFF	,	//无效则默认
}SIMCOM_MODE_TYPE;	

//网络注册状态
typedef enum
{
	SIMCOM_NET_NOT = 0,		//未注册
	SIMCOM_NET_YES = 1,		//已经注册
	SIMCOM_NET_SEA = 2,		//未注册,正在搜索
	SIMCOM_NET_TUR = 3,		//注册被拒绝
	SIMCOM_NET_UNK = 4,		//未知
	SIMCOM_NET_ROA = 5,		//已经注册,但是漫游
	SIMCOM_NET_ERROR=0XFF	//错误
}SIMCOM_NETSTATUS;



//SIMCOM网络制式
typedef enum
{
	SIMCOM_NETMODE_NOT 			= 	0,	//未注册
	SIMCOM_NETMODE_GSM			=	1,	//GSM
	SIMCOM_NETMODE_GPRS			=	2,	//GPRS
	SIMCOM_NETMODE_EGPRS		=	3,	//EGPRS (EDGE)
	SIMCOM_NETMODE_WCDMA		=	4,	//WCDMA
	SIMCOM_NETMODE_HSDPA		=	5,	//HSDPA only(WCDMA)
	SIMCOM_NETMODE_HSUPA		=	6,	//HSUPA only(WCDMA)
	SIMCOM_NETMODE_HSPA			=	7,	//HSPA (HSDPA and HSUPA, WCDMA)
	SIMCOM_NETMODE_LTE			=	8,	//LTE
	SIMCOM_NETMODE_TDS_CDMA		=	9,	//TDS-CDMA
	SIMCOM_NETMODE_TDS_HSDPA	=	10,	//TDS-HSDPA only(SIM7000C 电信NB也是这个)
	SIMCOM_NETMODE_TDS_HSUPA	=	11,	//TDS-HSUPA only
	SIMCOM_NETMODE_TDS_HSPA		=	12,	//TDS- HSPA (HSDPA and HSUPA)
	SIMCOM_NETMODE_CDMA			=	13,	//CDMA
	SIMCOM_NETMODE_EVDO			=	14,	//EVDO
	SIMCOM_NETMODE_HYBRID		=	15,	//HYBRID (CDMA and EVDO)
	SIMCOM_NETMODE_1XLTE		=	16,	//1XLTE(CDMA and LTE)
	SIMCOM_NETMODE_NULL			=	0xff,	//未知
}SIMCOM_NETMODE_TYPE;


//SIM卡就绪状态
typedef enum
{
	SIM_READY			=	0,	//SIM卡就绪
	SIM_NOT_READY		=	1,	//SIM卡未就绪
	SIM_UNKNOWN			=	2	//SIM卡状态未知
}SIM_CARD_STATUS;

//控制IO电平定义
#define SIMCOM_H_LEVEL		1	//高电平
#define SIMCOM_L_LEVEL		0	//低电平

//DCD状态定义
#define DCD_DATA_MODE		0	//数据透传模式
#define DCD_AT_MODE			1	//AT指令模式

//相关信息长度限制
#define SIMCOM_INFO_SIZE	24	//信息长度
#define SIMCOM_VER_SIZE		24	//软件版本长度定义

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


//SIMCOM模块相关信息
typedef struct
{
	char Manu[SIMCOM_INFO_SIZE+1];					//制造商
	char Model[SIMCOM_INFO_SIZE+1];					//型号
	char Ver[SIMCOM_VER_SIZE+1];					//软件版本
	char IMEI[SIMCOM_INFO_SIZE+1];					//序列号
}SIMCOM_INFO;


//NBIOT模式定义
typedef enum
{
	NB_IOT_MODE = 0,		//NBIOT模式
	CAT_M_MODE = 1,			//CAT-M模式
}NBIOT_MODE_TYPE;

//网络模式设置
typedef struct
{
	SIMCOM_MODE_TYPE	ModeType;					//模块型号
	NBIOT_MODE_TYPE 	NB_Mode;					//NB模式
	s8 NB_EnableMode;								//NB模式使能模式,-1:无需设置;0:关闭NB,使能GSM模式;1:使能NB模式
	bool isNB_ScarEnable;							//NB模式扰码使能
}NETWORK_CONFIG_TYPE;



//SIMCOM通信模块句柄
typedef struct
{
	//所需变量
	SIMCOM_MODE_TYPE	SimcomModeType;				//模块型号
	char TelecomCarr[SIMCOM_INFO_SIZE+1];			//运营商名称
	SIMCOM_INFO SIMCOM_Info;						//SIMCOM通信模块相关信息结构体
	NETWORK_CONFIG_TYPE NetworkConfig;				//网络模式设置
	SIMCOM_NETMODE_TYPE NetworkMode;				//当前网络制式
	u8 Singal;										//网络信号强度
	char LocalPhoneNumber[16];						//本机电话号码
	char ServiceCenterPhoneNumber[16];				//短信中心电话号码
	char SIM_CIMI[16];								//SIM卡唯一CIMI号码
		
	//底层通信接口
	bool (* pSendData)(u8 *pDataBuff, u16 DataLen);											//发送数据接口,如果发送失败,返回FALSE,成功返回TRUE;
	int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay);	//接收数据接口,返回数据长度,如果失败返回<=0,成功,返回数据长度
	void (*pClearRxData)(void);																//清除接收缓冲区函数,用于清除接收数据缓冲区数据
	void (*pSetDTR_Pin)(u8 Level);															//DTR引脚电平控制-用于控制sleep模式或者退出透传模式
	void (*pSetPWRKEY_Pin)(u8 Level);														//PWRKEY开机引脚电平控制-用于开机
	u8 (*pGetSTATUS_Pin)(void);																//获取STATUS引脚电平-用于指示模块上电状态
	u8 (*pGetDCD_Pin)(void);																//获取DCD引脚电平-高电平AT指令模式,低电平为透传模式
	//系统接口
	void (*pDelayMS)(u32 ms);																//系统延时函数
	void (*pIWDG_Feed)(void);																//清除系统看门狗(可以为空)
	//内部状态定义
	bool s_isInitStatus;																	//用于记录模块初始化状态,复位或上电后变为无效
}SIMCOM_HANDLE;



#endif /*_SIMCOM_H_*/

//SIMCOM_AT.c

/*************************************************************************************************************
 * 文件名:			SIMCOM_AT.c
 * 功能:			SIMCOM底层AT指令接口
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			
*************************************************************************************************************/
#include "system.h"
#include "usart.h"
#include "SIMCOM_AT.h"
#include "SIMCOM.h"
#include "string.h"
#include "ucos_ii.h"

bool g_SIMC0M_AT_Debug = TRUE;	//底层AT指令调试状态

//调试开关
#define SIMCOM_DBUG		1
#if SIMCOM_DBUG
	#include "system.h"
	#define SIMCOM_debug(format,...)	{if(g_SIMC0M_AT_Debug){uart_printf(format,##__VA_ARGS__);}}
#else
	#define SIMCOM_debug(format,...)	/\
/
#endif	//SIMCOM_DBUG


/*************************************************************************************************************************
* 函数				:	bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr)
* 功能				:	发送一个AT指令(会添加结束符\r\n),不会等待响应
* 参数				:	pHandle:SIMCOM句柄;pStr:指令字符串
* 返回				:	接口发送状态
* 依赖				:	无
* 作者				:	[email protected]
* 时间				:	2018-03-23
* 最后修改时间 		: 	2018-03-23
* 说明				: 	用于底层AT指令发送
*************************************************************************************************************************/
bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr)
{
	pHandle->pSendData((u8 *)pStr, strlen(pStr));	//发送指令
	return pHandle->pSendData((u8 *)"\r\n", 2);		//发送结束符
}





/*************************************************************************************************************************
* 函数			:	bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry)
* 功能			:	SIMCOM AT 命令通信测试
* 参数			:	pHandle:SIMCOM句柄;retry:重试次数
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2013-10-20
* 最后修改时间 : 	2018-03-23
* 说明			: 	每隔100ms向SIMCOM通信模块发送一个"AT",等待响应返回
*************************************************************************************************************************/
bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry)
{
	u32 cnt;
	u8 *pRxBuff;
	
	//检测模块存在
	do
	{
		SIMCOM_SendAT(pHandle, "AT");															//发送"AT",同步波特率,并且等待应答
		pHandle->pClearRxData();																//清除计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pRxBuff, &cnt, "OK", 10, 150))			//等待响应,超时150ms
		{
			pHandle->pDelayMS(100);
			return TRUE;
		}
		retry --;
	}while(retry);
	
	pHandle->pDelayMS(100);
	return FALSE;
}


/*************************************************************************************************************************
* 函数				:	bool SIMCOM_WaitSleep(SIMCOM_HANDLE *pHandle, u32 TimeOutMs)
* 功能				:	等待模块空闲,并重新唤醒
* 参数				:	pHandle:句柄;TimeOut:等待超时,时间单位ms
* 返回				:	TRUE:成功;FALSE:超时
* 依赖				:	无
* 作者				:	[email protected]
* 时间				:	2013-10-25
* 最后修改时间 		: 	2018-03-24
* 说明				: 	用于等待操作完成,防止快速操作造成模块不响应
*************************************************************************************************************************/
bool SIMCOM_WaitSleep(SIMCOM_HANDLE *pHandle, u32 TimeOutMs)
{
	u32 i;
	u32 cnt;
	u8 *pData;
	
	if(TimeOutMs < 100) TimeOutMs = 100;		//最少100ms
	pHandle->pSetDTR_Pin(SIMCOM_H_LEVEL);		//等待模块空闲后进入SLEEP模式
	
	//循环发送命令,直到命令超时了则认为进入了sleep模式
	for(i = 0;i < (TimeOutMs/100);i ++)
	{
		pHandle->pDelayMS(100);			//延时100ms
		SIMCOM_SendAT(pHandle, "AT");			//发送"AT",同步波特率,并且等待应答
		pHandle->pClearRxData();				//清除接收计数器
		if(AT_RETURN_TIME_OUT == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 100))	//等待响应,超时100ms
		{
			break;
		}
	}
	pHandle->pSetDTR_Pin(SIMCOM_L_LEVEL);		//唤醒
	
	if(i == (TimeOutMs/100)) 
	{
		SIMCOM_debug("模块进入空闲模式失败!\r\n");
		pHandle->pClearRxData();				//清除接收计数器
		
		return FALSE;
	}
	pHandle->pDelayMS(100);				//延时100ms
	
	SIMCOM_debug("模块进入空闲模式成功!\r\n");
	SIMCOM_TestAT(pHandle, 10);
	pHandle->pClearRxData();				//清除接收计数器
	
	return TRUE;
}







/*************************************************************************************************************************
* 函数				:	SIMCOM_AT_ERROR SIMCOM_GetATResp(SIMCOM_HANDLE *pHandle, u8 **pRxBuff, u32 *pLen, const char *pKeyword, u8 ByteTimeOutMs, u16 TimeOutMs)
* 功能				:	获取SIMCOM的AT指令响应
* 参数				:	pHandle:句柄
						pRxBuff:接收缓冲区指针(输出);pLen:接收到的数据大小(输出),
						pKeyword:关键字,为字符串,比如"OK",如果在接收到的字符串中有OK字符,就返回成功,否则失败(输入)
						ByteTimeOutMs:字节超时时间,单位ms最大255ms
						TimeOutMs:等待超时时间,单位毫秒
* 返回				:	SIM900_ERROR
* 依赖				:	无
* 作者				:	[email protected]
* 时间				:	2018-03-24
* 最后修改时间 		: 	2018-03-24
* 说明				: 	本函数会在接收缓冲区字符串结束添加'\0'
						本函数不能清除缓冲区
*************************************************************************************************************************/
SIMCOM_AT_ERROR SIMCOM_GetATResp(SIMCOM_HANDLE *pHandle, u8 **pRxBuff, u32 *pLen, const char *pKeyword, u8 ByteTimeOutMs, u16 TimeOutMs)
{
	int len;
	u16 ReceiveDelay;

	if(ByteTimeOutMs < 1) ByteTimeOutMs = 1;
	len = pHandle->pReadData(pRxBuff, ByteTimeOutMs, TimeOutMs, &ReceiveDelay);	//调用回调接口,读取数据
	//等待超时
	if(len == 0)
	{
		return AT_RETURN_TIME_OUT;												//返回超时错误
	}
	//数据接收完毕
	*pLen = len;																//返回接收数据长度
	if((*pRxBuff)[len-1] != 0)
	{
		(*pRxBuff)[len]	= '\0';													//将数据结尾添加结束字符串
	}
	
	SIMCOM_debug("\r\nSIMCOM(%dB)->%s\r\n",len, *pRxBuff);						//打印返回信息
	if(strstr((const char*)(*pRxBuff), pKeyword) != NULL) 	//搜索关键字
	{
		SIMCOM_debug("%s 返回成功!\r\n",pKeyword);
	    return AT_RETURN_OK;
	}
	else if(strstr((const char*)(*pRxBuff), "ERROR") != NULL)
	{
		SIMCOM_debug("%s 返回错误!\r\n",pKeyword);
		return AT_RETURN_ERROR;
	}
	else
	{
		SIMCOM_debug("%s 返回未知!\r\n",pKeyword);
		return AT_RETURN_UNKNOWN;
	}
}




/*************************************************************************************************************************
* 函数				:	bool SIM900_SetParametersReturnBool(char *pATCom, u8 retry, u16 TimeOutx10MS, const char *pErrorDebug)
* 功能				:	设置SIM900一个参数,返回一个bool状态
* 参数				:	pATCom:AT命令;retry:重试次数;TimeOut:命令超时时间,单位10ms;pErrorDebug:失败后提示的调试信息
* 返回				:	TRUE:执行成功了,返回了OK,FALSE:执行失败了,返回了ERROR或其它
* 依赖				:	SIM900
* 作者				:	[email protected]
* 时间				:	2014-12-19
* 最后修改时间 	: 	2014-12-19
* 说明				: 	用于简化命名发送,防止代码重复
*************************************************************************************************************************/
bool SIMCOM_SetParametersReturnBool(SIMCOM_HANDLE *pHandle, char *pATCom, u8 retry, u16 TimeOutMs, const char *pErrorDebug)
{
	u32 cnt;
	u8 *pData;
			
	retry += 1;		//重试次数
	do
	{	
		SIMCOM_SendAT(pHandle,pATCom);			//发送AT命令
		pHandle->pClearRxData();				//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, TimeOutMs))	//等待响应,超时10s
		{
			pHandle->pClearRxData();			//清除接收计数器
			return TRUE;
		}
		
		SIMCOM_Ready(pHandle);					//等待就绪
		retry --;
	}while(retry);
	
	if(pErrorDebug!=NULL) 
	{
		uart_printf("%s",pErrorDebug);			//输出调试信息
	}
	pHandle->pClearRxData();					//清除接收计数器
	
	return FALSE;
}




/*************************************************************************************************************************
*函数        	:	u32 GSM_StringToHex(char *pStr, u8 NumDigits)
*功能        	:	将16进制样式字符串转换为16进制整型数(必须保证字符串字母都是大写)
*参数        	:	pStr:字符串起始指针
* 					NumDigits:数字位数,16进制数字位数
*返回        	:	转换后的数字
*依赖        	:	无
*作者        	:	[email protected]
*时间        	:	2013-04-30
*最后修改时间	:	2013-10-17
*说明        	:	比如字符串"A865"转换后为0xA865,位数为4位
					必须保证字符串字母都是大写
*************************************************************************************************************************/
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进制数字位数
*返回        	:	无
*依赖        	:	无
*作者        	:	[email protected]
*时间        	:	2013-04-30
*最后修改时间	:	2013-04-30
*说明        	:	比如字符串0xA865转换后为"A865",位数为4位
*************************************************************************************************************************/
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进制数字位数
*返回        	:	转换后的数字
*依赖        	:	无
*作者        	:	[email protected]
*时间        	:	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;
}

//SIMCOM_AT.h

/*************************************************************************************************************
 * 文件名:			SIMCOM_AT.h
 * 功能:			SIMCOM底层AT指令接口
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			
*************************************************************************************************************/
#ifndef _SIMCOM_AT_H_
#define _SIMCOM_AT_H_
#include "system.h"
#include "SIMCOM.h"

extern bool g_SIMC0M_AT_Debug;	//底层AT指令调试状态



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




//相关接口
bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr);																						//发送一个AT指令(会添加结束符\r\n),不会等待响应
SIMCOM_AT_ERROR SIMCOM_GetATResp(SIMCOM_HANDLE *pHandle, u8 **pRxBuff, u32 *pLen, const char *pKeyword, u8 ByteTimeOutMs, u16 TimeOutMs);	//获取SIMCOM的AT指令响应
bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr);																						//发送一个AT指令(会添加结束符\r\n),不会等待响应
bool SIMCOM_WaitSleep(SIMCOM_HANDLE *pHandle, u32 TimeOutMs);																				//等待模块空闲,并重新唤醒
bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry);																						//SIMCOM AT 命令通信测试
#define SIMCOM_Ready(pHandle)  if(SIMCOM_TestAT(pHandle, 5) == FALSE){SIMCOM_WaitSleep(pHandle, 1000);}										//让SIMCOM就绪,防止卡住//串口同步失败,等待上一个操作完成
bool SIMCOM_SetParametersReturnBool(SIMCOM_HANDLE *pHandle, char *pATCom, u8 retry, u16 TimeOutMs, const char *pErrorDebug);				//设置SIM900一个参数,返回一个bool状态



//通用工具
u32 GSM_StringToHex(char *pStr, u8 NumDigits);				//将16进制样式字符串转换为16进制整型数(必须保证字符串字母都是大写)
u32 GSM_StringToDec(char *pStr, u8 NumDigits);				//将10进制样式字符串转换为整型数(必须保证完全为数字字符)
void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits);	//将整型数字转换为16进制样式字符串(字母为大写,不带结束符)

#endif /*SIMCOM_AT*/

//SIMCOM_GSM.c //通用的底层操作

/*************************************************************************************************************
 * 文件名:			SIMCOM_GSM.c
 * 功能:			SIMCOM GSM相关接口
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			
*************************************************************************************************************/
#include "system.h"
#include "usart.h"
#include "SIMCOM_GSM.h"
#include "SIMCOM_AT.h"
#include "string.h"
#include "SIMCOM.h"
#include <stdlib.h>

bool g_SIMC0M_GSM_Debug = TRUE;	//底层AT指令调试状态

//调试开关
#define SIMCOM_GSM_DBUG		1
#if SIMCOM_GSM_DBUG
	#include "system.h"
	#define SIMCOM_GSM_debug(format,...)	{if(g_SIMC0M_GSM_Debug){uart_printf(format,##__VA_ARGS__);}}
#else
	#define SIMCOM_GSM_debug(format,...)	/\
/
#endif	//SIMCOM_GSM_DBUG




/*************************************************************************************************************************
* 函数			:	bool SIMCOM_NetworkConfig(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, SIMCOM_SIM_SELECT SIM_Select)
* 功能			:	SIMCOM网络配置
* 参数			:	pHandle:句柄;ModeType:通信模块型号;SIM_Select:SIM卡选择;
* 返回			:	TRUE:成功,FALSE:失败	
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2018-01-17
* 最后修改时间	: 	2018-03-24
 * 详细			:
*************************************************************************************************************************/ 
bool SIMCOM_NetworkConfig(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, NETWORK_CONFIG_TYPE *pConfig)	
{
	char buff[16];
	
	pConfig->ModeType = ModeType;					//记录通信模块型号
	if(ModeType == SIMCOM_SIM7000C)					//SIM7000C需要选择工作模式
	{	
		switch(pConfig->NB_EnableMode)
		{
			case 0: //GSM模式
			{
				uart_printf("[DTU]设置GSM网络模式!\r\n");
				if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMP=13", SIMCOM_DEFAULT_RETRY, 200, "\r\n设置SIM7000C GSM模式失败!\r\n") == FALSE) return FALSE; //GSM模式
			}break;
			case 1://NB模式
			{
				uart_printf("[DTU]设置NBIOT网络模式!\r\n");
				if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMP=38", SIMCOM_DEFAULT_RETRY, 200, "\r\n设置SIM7000C LTE NB模式失败!\r\n") == FALSE) return FALSE; //LTE only(使用NB-IOT网络时CNMP需要设置为38)
				//CAT NB模式设置
				switch(pConfig->ModeType)
				{
					case CAT_M_MODE: //CAT模式
					{
						sprintf(buff,"AT+CMNB=%d",1); //cat模式
					}break;
					default: 
					{
						sprintf(buff,"AT+CMNB=%d",2); //NBIOT模式
					}break;
				}
				if(SIMCOM_SetParametersReturnBool(pHandle, buff, SIMCOM_DEFAULT_RETRY, 200, "\r\n设置SIM7000C CAT NB模式失败!\r\n") == FALSE) return FALSE; //1: CAT-M 2: NB-IOT
				//扰码设置
				if(pConfig->isNB_ScarEnable) //开启扰码
				{
					sprintf(buff,"AT+NBSC=%d",1); 
				}
				else
				{
					sprintf(buff,"AT+NBSC=%d",0); 
				}
				if(SIMCOM_SetParametersReturnBool(pHandle, buff, SIMCOM_DEFAULT_RETRY, 200, "\r\n设置SIM7000C NB 扰码模式失败!\r\n") == FALSE) return FALSE; 
			}break;
			default:return TRUE;					//忽略,无需设置
		}
	}
	return TRUE;
}




/*************************************************************************************************************************
* 函数				:	SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle)
* 功能				:	获取SIM卡状态
* 参数				:	无
* 返回				:	FALSE:失败;TRUE:成功
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2014-06-26
* 最后修改时间 		: 	2014-06-26
* 说明				: 	2017-09-05 : 增加SIM卡状态为3种状态
*************************************************************************************************************************/
SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle)
{
	u32 cnt;
	char *p;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	int status;
	u8 *pData;
	
	do
	{	
		//+CPIN: READY
		SIMCOM_SendAT(pHandle, "AT+CPIN?");											
		pHandle->pClearRxData();												//清除接收计数器
		status = SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200);		//等待响应,超时200MS
		if(AT_RETURN_OK == status)												//返回OK
		{
			p = strstr((const char*)pData, "+CPIN: READY");						//搜索字符"+CPIN: READY"
			if(p != NULL) 														//搜索成功
			{
				return SIM_READY;												//SIM卡就绪
			}
			break;
		}
		else if(AT_RETURN_ERROR == status)										//返回ERROR
		{
			p = strstr((const char*)pData, "ERROR");							//搜索卡未准备就绪标志
			if(p != NULL) 														//搜索成功
			{
				return SIM_NOT_READY;											//SIM卡未就绪
			}
			break;
		}
		
		SIMCOM_Ready(pHandle);													//等待就绪
		pHandle->pDelayMS(1000);												//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return SIM_UNKNOWN;															//SIM卡未知
}



/*************************************************************************************************************************
* 函数				:	SIMCOM_NETSTATUS SIM900_GetGSMNetworkStatus(SIMCOM_HANDLE *pHandle)
* 功能				:	获取GSM网络注册状态
* 参数				:	pHandle:句柄
* 返回				:	SIMCOM_NETSTATUS
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2013-10-29
* 最后修改时间 		: 	2018-03-24
* 说明				: 	当网络注册后,可能被拒绝,如果被拒绝,获取网络注册状态会提示
						注册成功的,但是通过发送AT 后再去查询,会发现网络注册失败
*************************************************************************************************************************/
SIMCOM_NETSTATUS SIM900_GetGSMNetworkStatus(SIMCOM_HANDLE *pHandle)
{
	u32 cnt;
	char *p;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	
	do
	{	
		//+CREG: 0,1
		SIMCOM_SendAT(pHandle, "AT+CREG?");											//发送"AT+CREG?",获取网络注册状态
		pHandle->pClearRxData();													//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200))	//等待响应,超时200MS
		{
			p = strstr((const char*)pData, "+CREG:");								//搜索字符"+CREG:"
			if(p != NULL) 															//搜索成功
			{
				SIMCOM_TestAT(pHandle, 1);
				return (SIMCOM_NETSTATUS)GSM_StringToDec(&p[9], 1);
			}
			break;
		}
		
		SIMCOM_Ready(pHandle);														//等待就绪
		pHandle->pDelayMS(1000);													//失败延时1秒后重试
		retry --;
	}while(retry);
	
	SIMCOM_TestAT(pHandle, 2);
	return SIMCOM_NET_ERROR;
}




/*************************************************************************************************************************
* 函数				:	SIMCOM_NETSTATUS SIMCOM_GetDataNetworkStatus(SIMCOM_HANDLE *pHandle)
* 功能				:	获取数据网络注册状态
* 参数				:	pHandle:句柄
* 返回				:	SIMCOM_NETSTATUS
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2013-10-29
* 最后修改时间 		: 	2018-03-24
* 说明				: 	用于获取NB数据网络或GPRS数据网络注册状态
*************************************************************************************************************************/
SIMCOM_NETSTATUS SIMCOM_GetDataNetworkStatus(SIMCOM_HANDLE *pHandle)
{
	u32 cnt;
	char *p;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	
	do
	{	
		//+CGREG: 0,1
		SIMCOM_SendAT(pHandle, "AT+CGREG?");										//发送"AT+CGREG?",获取网络注册状态
		pHandle->pClearRxData();													//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200))	//等待响应,超时200MS
		{
			p = strstr((const char*)pData, "+CGREG:");								//搜索字符"+CGREG:"
			if(p != NULL) 															//搜索成功
			{
				SIMCOM_TestAT(pHandle, 1);
				return (SIMCOM_NETSTATUS)GSM_StringToDec(&p[10], 1);
			}
			break;
		}
		
		SIMCOM_Ready(pHandle);														//等待就绪
		pHandle->pDelayMS(1000);													//失败延时1秒后重试
		retry --;
	}while(retry);
	
	SIMCOM_TestAT(pHandle, 2);
	return SIMCOM_NET_ERROR;
}



/*************************************************************************************************************************
* 函数				:	bool SIM900_SetGPRS_PackDatatSize(SIMCOM_HANDLE *pHandle)
* 功能				:	设置SIM900/SIM800 GPRS发送数据缓冲区
* 参数				:	pHandle:句柄
* 返回				:	FALSE:失败;TRUE:成功
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2014-09-11
* 最后修改时间 		: 	2014-09-11
* 说明				: 	按照最大数据包1460B设置
*************************************************************************************************************************/
bool SIM900_SetGPRS_PackDatatSize(SIMCOM_HANDLE *pHandle)
{
	char buff[36];

	//先开启透传模式才能设置
	SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPMODE=1", SIMCOM_DEFAULT_RETRY, 2000, "开启透传模式失败!\r\n");	//开启透传模式
	
	//设置GPRS传输数据包大小
	//AT+CIPCCFG=3,2,1024,1 //设置透传参数 //3-重传次数为3次,2-等待数据输入时间为 //2*200ms,1024-数据缓冲区为1024个字节 //1-支持转义退出透传
	sprintf(buff,"AT+CIPCCFG=3,2,%d,1",1460);
	return SIMCOM_SetParametersReturnBool(pHandle, buff, SIMCOM_DEFAULT_RETRY, 200, "GPRS发送数据缓冲区设置失败!\r\n");	//发送	
}



/*************************************************************************************************************************
* 函数				:	bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle)
* 功能				:	初始化SIMCOM模块基本配置(不允许失败)
* 参数				:	pHandle:句柄
* 返回				:	FALSE:初始化失败;TRUE:初始化成功
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2013-10-16
* 最后修改时间 		: 	2018-03-24
* 说明				: 	必须先上电,并获取模块型号,根据不同的型号模块分别进行初始化
*************************************************************************************************************************/
bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle)
{
	u8 retry = 5;							//重试次数
	
	pHandle->pSetDTR_Pin(SIMCOM_L_LEVEL);	//DTR=0,退出低功耗模式
	//检测模块存在,并保证通信正常
	SIMCOM_Ready(pHandle);
	SIMCOM_TestAT(pHandle, 20);
	
	switch(pHandle->SimcomModeType)			//不同的芯片存在不一样的初始化
	{
		case SIMCOM_SIM2000:				//SIM2000需要先关闭URC,否则会提示Call Ready
		{
			SIMCOM_SetParametersReturnBool(pHandle, "AT+CIURC=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n关闭Call Ready显示失败!\r\n");
		}break;
		default:break;
	}
	//设置关闭回显
	if(SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "\r\n关闭AT回显模式失败!\r\n") == FALSE)
	{
		return FALSE;
	}
	//设置短消息格式为PDU格式
	if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CMGF=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n设置短消息格式为PDU格式失败!\r\n") == FALSE)
	{
		uart_printf("\r\n设置DCD功能模式失败!\r\n");
		return FALSE;
	}
	//设置DCD功能模式,DCD线只在数据载波存在时为ON。
	if(SIMCOM_SetParametersReturnBool(pHandle, "AT&C1", SIMCOM_DEFAULT_RETRY, 110, "\r\n设置DCD功能模式失败!\r\n") == FALSE)
	{
		uart_printf("\r\n设置DCD功能模式失败!\r\n");
		//return FALSE;
	}
	//设置 DTR 功能模式,DTR 由ON至OFF:TA在保持当前数据通话的同时,切换至命令模式
	if(SIMCOM_SetParametersReturnBool(pHandle, "AT&D1", SIMCOM_DEFAULT_RETRY, 110, "\r\n设置DTR功能模式失败!\r\n") == FALSE)
	{
		uart_printf("\r\n设置DTR功能模式失败!\r\n");
		//return FALSE;
	}
	
//	//使能RI引脚提示
//	if(SIM900_SetParametersReturnBool("AT+CFGRI=1", SIMCOM_DEFAULT_RETRY, 11, "\r\n启动RI引脚提示失败!\r\n") == FALSE)
//	{
//		return FALSE;
//	}
	
	//设置模块sleep模式使能//发送"AT+CSCLK",启动SLEEP模式;0:关闭;1:手动;2:自动空闲5S钟后休眠
	if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CSCLK=1", SIMCOM_DEFAULT_RETRY, 110, "\r\n设置SLEEP失败!\r\n") == FALSE)
	{
		return FALSE;
	}
	


	//检查卡是否就绪
	retry = 8;					//重试次数
	do
	{
		if(SIMCOM_GetCPIN(pHandle)==SIM_READY)
		{
			uart_printf("\r\nSIM卡准备就绪!\r\n");
			break;
		}
		else
		{
			uart_printf("\r\nSIM卡未准备就绪!\r\n");
		}
		
		SIMCOM_Ready(pHandle);						//等待就绪
		pHandle->pDelayMS(1000);					//失败延时1秒后重试
		retry --;
	}while(retry);
	if(retry == 0)
	{
		uart_printf("\r\nSIM卡未准备就绪!\r\n");
		pHandle->pClearRxData();					//清除接收计数器
		return FALSE;
	}
	
//	//上电删除所有短信
//	retry = SIMCOM_DEFAULT_RETRY;						//重试次数
//	do
//	{
//		if(SIM900_DelMultiSMS(DelSMS) == TRUE)//删除短信
//		{
//			//uart_printf("上电删除短信成功!\r\n");
//			break;
//		}
//		SIM900_Ready();	//等待就绪
//		retry --;
//	}while(retry);
//	if(retry == 0)
//	{
//		uart_printf("上电删除短信失败!\r\n");
//		SIM900_ClearRxCnt();				//清除计数器
//		return FALSE;
//	}
	
	//2016-09-20:设置等待消息上报超时时间为1分钟,因为西宁项目卡出现超时情况
	switch(pHandle->SimcomModeType)	//不同的芯片存在不一样的初始化
	{
		case SIMCOM_SIM800:			//SIM800需要等待就绪时间长一些
		{
			retry = 65;
		}break;
		default:retry=35;break;
	}
	
	//关闭新消息自动上报
	while(retry)
	{
		if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMI=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n关闭新消息自动上报失败!\r\n") == FALSE)
		{
			//return FALSE;
		}
		else break;
		pHandle->pDelayMS(1000);				//延时1秒
		retry --;
	}
	if(retry == 0) return FALSE;

	
	switch(pHandle->SimcomModeType)	//不同的芯片存在不一样的初始化
	{
		case LYNQ_L700: break;
		case SIMCOM_SIM7600:
		{
			//设置TCP收发相关
			retry = SIMCOM_DEFAULT_RETRY;		//重试次数
			while(retry)
			{
				//设置重试次数为3次,并且发送延时为120ms
				if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPCCFG=3,100,,1,0,,1000", SIMCOM_DEFAULT_RETRY, 110, "\r\n配置TCP/IP失败!\r\n") == FALSE)
				{
					//return FALSE;
				}
				else break;
				pHandle->pDelayMS(1000);				//延时1秒
				retry --;
			}
			if(retry == 0)
			{
				uart_printf("\r\n设置TCP重发次数以及发送延时失败!\r\n");
				pHandle->pClearRxData();				//清除接收计数器
				return FALSE;
			}
			//设置不用等到发送响应
			retry = SIMCOM_DEFAULT_RETRY;			//重试次数
			while(retry)
			{
				//设置重试次数为3次,并且发送延时为120ms
				if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPSENDMODE=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n不用等待发送ACK设置失败!\r\n") == FALSE)
				{
					//return FALSE;
				}
				else break;
				pHandle->pDelayMS(1000);				//延时1秒
				retry --;
			}
			if(retry == 0)
			{
				uart_printf("\r\n设置不用等待发送ACK失败!\r\n");
				pHandle->pClearRxData();				//清除接收计数器
			}
			
			//显示接收数据长度
			retry = SIMCOM_DEFAULT_RETRY;			//重试次数
			while(retry)
			{
				//设置重试次数为3次,并且发送延时为120ms
				if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPHEAD=1", SIMCOM_DEFAULT_RETRY, 110, "\r\n显示接收数据长度设置失败!\r\n") == FALSE)
				{
					//return FALSE;
				}
				else break;
				pHandle->pDelayMS(1000);				//延时1秒
				retry --;
			}
			if(retry == 0)
			{
				uart_printf("\r\n设置显示接收数据长度失败!\r\n");
				pHandle->pClearRxData();				//清除接收计数器
				return FALSE;
			}
			
			//不显示接收数据IP头
			retry = SIMCOM_DEFAULT_RETRY;		//重试次数
			while(retry)
			{
				//设置重试次数为3次,并且发送延时为120ms
				if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPSRIP=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n不显示接收数据IP头设置失败!\r\n") == FALSE)
				{
					//return FALSE;
				}
				else break;
				pHandle->pDelayMS(1000);				//延时1秒
				retry --;
			}
			if(retry == 0)
			{
				uart_printf("\r\n不显示接收数据IP头失败!\r\n");
				pHandle->pClearRxData();				//清除接收计数器
				return FALSE;
			}
			
		}break;
		default:	//2G模块均需要进行设置的	
		{
			//设置GPRS发送数据缓冲区大小
			retry = SIMCOM_DEFAULT_RETRY;			//重试次数
			do
			{
				if(SIM900_SetGPRS_PackDatatSize(pHandle) == TRUE)
				{
					break;
				}
				retry --;
			}while(retry);
			if(retry == 0)
			{
				uart_printf("\r\n设置GPRS传输大小失败!\r\n");
				pHandle->pClearRxData();				//清除接收计数器
				return FALSE;
			}
		}break;
	}
	

	pHandle->s_isInitStatus = TRUE;					//模块成功初始化
	pHandle->pClearRxData();						//清除接收计数器
	
	return TRUE;
}


/*************************************************************************************************************************
* 函数				:	bool SIMCOM_GetModuleInfo(SIMCOM_HANDLE *pHandle, SIMCOM_INFO *pInfo)
* 功能				:	获取模块的相关信息
* 参数				:	pHandle:句柄;pInfo:信息结构体指针
* 返回				:	FALSE:失败;TRUE:成功
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2014-07-29
* 最后修改时间 		: 	2014-10-08
* 说明				: 	SIMCOM_INFO_SIZE:限制最大长度
						SIMCOM_VER_SIZE:软件版本长度限制
						2014-10-08:在个别模块上面遇到发送AT+GMI后返回了AT+GMI,导致获取失败,如果发现返回了AT+则重新获取,可以避免此问题
						2016-12-07:修改获取模块型号指令为AT+CGMM,用于兼容SIM7600
*************************************************************************************************************************/
bool SIMCOM_GetModuleInfo(SIMCOM_HANDLE *pHandle, SIMCOM_INFO *pInfo)
{
	u32 i,cnt;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	char *p;
	u8 *pData;
	
	//清空缓冲区
	pInfo->Manu[0] = 0;
	pInfo->Model[0] = 0;
	pInfo->Ver[0] = 0;
	pInfo->IMEI[0] = 0;
	
	retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	//获取制造商信息
	do
	{
		SIMCOM_TestAT(pHandle, 10);
		SIMCOM_SendAT(pHandle, "AT+GMI");												//请求制造商身份
		
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200))		//等待响应,超时200MS
		{
			//uart_printf("%s\r\n",pData);
			if(strstr((const char*)pData, "AT+") == NULL) 								//搜索关键字
			{
				for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++)
				{
					if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break;
					pInfo->Manu[i] = pData[2+i];
				}
				pInfo->Manu[i] = 0;
				break;
			}
		}	
		SIMCOM_Ready(pHandle);															//等待就绪
		pHandle->pDelayMS(1000);														//失败延时1秒后重试
		retry --;
	}while(retry);
	if(retry == 0) return FALSE;
	
	retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	//获取型号
	do
	{
		SIMCOM_SendAT(pHandle, "AT+CGMM");	
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200))		//等待响应,超时200MS
		{
			for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++)
			{
				if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break;
				pInfo->Model[i] = pData[2+i];
			}
			pInfo->Model[i] = 0;
			break;
		}
		SIMCOM_Ready(pHandle);															//等待就绪
		pHandle->pDelayMS(1000);														//失败延时1秒后重试
		retry --;
	}while(retry);
	if(retry == 0) return FALSE;
	
	retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	//获取软件版本
	do
	{
		SIMCOM_SendAT(pHandle, "AT+GMR");
		pHandle->pClearRxData();														//清除接收计数器	
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200))		//等待响应,超时200MS
		{
			p = strstr((char *)pData, "+GMR: ");
			if(p != NULL) 
			{
				p+= strlen("+GMR: ");	//SIM7600前面会有 +GMR:  ,跳过即可
				for(i = 0;i < (SIMCOM_VER_SIZE-1);i ++)
				{
					if((p[i] == '\r') || (p[i] == '\n') || (p[i] == '\0')) break;
					pInfo->Ver[i] = p[i];
				}
				pInfo->Ver[i] = 0;
			}
			else 
			{
				for(i = 0;i < (SIMCOM_VER_SIZE-1);i ++)
				{
					if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break;
					pInfo->Ver[i] = pData[2+i];
				}
				pInfo->Ver[i] = 0;
			}
			
			break;
		}
		SIMCOM_Ready(pHandle);															//等待就绪
		pHandle->pDelayMS(1000);														//失败延时1秒后重试
		retry --;
	}while(retry);
	if(retry == 0) return FALSE;
	
	retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	//获取序列号
	do
	{
		SIMCOM_SendAT(pHandle, "AT+GSN");	
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200))		//等待响应,超时200MS
		{
			for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++)
			{
				if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break;
				pInfo->IMEI[i] = pData[2+i];
			}
			pInfo->IMEI[i] = 0;
			break;
		}
		SIMCOM_Ready(pHandle);															//等待就绪
		pHandle->pDelayMS(1000);														//失败延时1秒后重试
		retry --;
	}while(retry);
	
	
	return TRUE;									
}



/*************************************************************************************************************************
* 函数				:	bool SIMCOM_COPS(SIMCOM_HANDLE *pHandle, char pCOPS_Buff[SIMCOM_INFO_SIZE])
* 功能				:	获取运营商名称
* 参数				:	pHandle:句柄;pCOPS_Buff:运营商名称
* 返回				:	FALSE:失败;TRUE:成功
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2014-07-29
* 最后修改时间 		: 	2018-03-24
* 说明				: 	SIMCOM_INFO_SIZE 限制最大长度
*************************************************************************************************************************/
bool SIMCOM_COPS(SIMCOM_HANDLE *pHandle, char pCOPS_Buff[SIMCOM_INFO_SIZE])
{
	u32 i,cnt;
	u8 retry = 5;						//重试次数
	char *p;
	u8 *pData;
	
	//清空缓冲区
	pCOPS_Buff[0] = 0;
	
	switch(pHandle->SimcomModeType)		//不同的芯片存在不一样的初始化
	{
		case SIMCOM_SIM2000:			//SIM2000需要多次读取,等待的时间比较长
		{
			retry = 28;
		}break;
		default:break;
	}
	
	//获取运营商
	do
	{
		SIMCOM_SendAT(pHandle, "AT+COPS?");											//显示模块当前注册的网络运营商
		pHandle->pClearRxData();													//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 150))	//等待响应,超时300MS
		{
			p = strstr((const char*)pData, "\"");
			if(p != NULL)
			{
				p ++;
				for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++)
				{
					if((p[i] == '\r') || (p[i] == '\n') || (p[i] == '\0') || (p[i] == '\"')) break;
					pCOPS_Buff[i] = p[i];
				}
				pCOPS_Buff[i] = 0;
				return TRUE;
			}
		}
		
		SIMCOM_Ready(pHandle);													//等待就绪
		pHandle->pDelayMS(1000);											//延时1秒
		retry --;
	}while(retry);
	
	
	return FALSE;																//超时//错误	
}



/*************************************************************************************************************************
* 函数				:	SIMCOM_NETMODE_TYPE SIM7XXX_GetNetworkMode(SIMCOM_HANDLE *pHandle)
* 功能				:	获取SIM7XXX系列模块网络制式
* 参数				:	pHandle:句柄
* 返回				:	SIMCOM_NETMODE_TYPE
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2016-12-29
* 最后修改时间 		: 	2018-03-24
* 说明				: 	用于从SIM7600模块网络制式
						必须在网络注册成功后进行获取,正常返回
						+CNSMOD: 0,15
						用于SIM7000系列获取网制式
*************************************************************************************************************************/
SIMCOM_NETMODE_TYPE SIM7XXX_GetNetworkMode(SIMCOM_HANDLE *pHandle)
{
	u32 cnt;
	u8 retry = 3;
	char *p;
	int temp;
	u8 *pData;
	
	//获取型号
	do
	{
		SIMCOM_SendAT(pHandle, "AT+CNSMOD?");	
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200))		//等待响应,超时200MS
		{
			p = strstr((char *)pData, "+CNSMOD: 0,");
			if(p==NULL) p = strstr((char *)pData, "+CNSMOD: 1,");
			p += strlen("+CNSMOD: 0,");
			temp = atoi(p);
			if(temp > 16) continue; 
			else return (SIMCOM_NETMODE_TYPE)temp;
		}
		

		SIMCOM_Ready(pHandle);													//等待就绪
		pHandle->pDelayMS(1000);												//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return SIMCOM_NETMODE_NULL;
}




/*************************************************************************************************************************
* 函数				:	bool SIMCOM_HardwarePowerUP(SIMCOM_HANDLE *pHandle, bool isTest)
* 功能				:	SIMCOM模块硬件开机
* 参数				:	pHandle:句柄;isTest:是否检测开机是否成功,通过STATUS脚变为高电平可以检测是否开机成功
* 返回				:	开机是否成功
* 依赖				:	无
* 作者				:	[email protected]
* 时间				:	2013-10-29
* 最后修改时间 		: 	2018-03-24
* 说明				: 	用于SIM900模块开机,拉低PWR
						2016-12-07:修改动态监测是否上电成功,增加SIM7600CE兼容
*************************************************************************************************************************/
bool SIMCOM_HardwarePowerUP(SIMCOM_HANDLE *pHandle, bool isTest)
{	
	u8 i,j;
	
	pHandle->pSetDTR_Pin(SIMCOM_L_LEVEL);	//DTR=0,退出低功耗模式
	pHandle->s_isInitStatus = FALSE;		//模块没有初始化,需要重新初始化
	if(isTest)								//需要检测是否开机成功
	{
		if(pHandle->pGetSTATUS_Pin() == SIMCOM_H_LEVEL)				//开机脚已经是高电平了
		{
			return TRUE;
		}			
		for(i = 0;i < 2;i ++)
		{
			pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL);	//拉低1200ms开机
			pHandle->pDelayMS(1200);
			pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL);	//恢复高电平
			for(j = 0;j < 6;j ++)
			{
				pHandle->pDelayMS(1000);
				if(pHandle->pGetSTATUS_Pin() == SIMCOM_H_LEVEL)				//开机脚已经是高电平了
				{
					return TRUE;
				}
			}
		}
		
		return FALSE;
	}
	else	//无需检测是否开机成功
	{
		pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL);	//拉低1200ms开机
		pHandle->pDelayMS(1200);
		pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL);	//恢复高电平
		pHandle->pDelayMS(3000);;					//延时3S等待开机完毕	
		
		return TRUE;
	}
}



/*************************************************************************************************************************
* 函数				:	bool SIMCOM_HardwarePowerDOWN(SIMCOM_HANDLE *pHandle, bool isTest)
* 功能				:	SIMCOM模块硬件关机
* 参数				:	pHandle:句柄;isTest:是否检测开机是否成功,通过STATUS脚变为高电平可以检测是否关机成功
* 返回				:	关机是否成功
* 依赖				:	无
* 作者				:	[email protected]
* 时间				:	2013-10-29
* 最后修改时间 		: 	2018-03-24
* 说明				: 	用于SIM900模块关机机,拉低PWR大于1S小于5S
						2016-12-07:优化关机,兼容SIM7600
						一定要先获取模块型号,不同模块关机时间不一样
*************************************************************************************************************************/
bool SIMCOM_HardwarePowerDOWN(SIMCOM_HANDLE *pHandle, bool isTest)
{
	u8 i,j;
	
	pHandle->s_isInitStatus = FALSE;		//模块没有初始化,需要重新初始化
	if(isTest)								//需要检测是否开机成功
	{
		if(pHandle->pGetSTATUS_Pin() == SIMCOM_L_LEVEL)				//开机脚已经是低电平了
		{
			return TRUE;
		}
		for(i = 0;i < 2;i ++)
		{
			pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL);				//拉低1200ms关机
			switch(pHandle->SimcomModeType)
			{
				case SIMCOM_SIM7600:
				{
					pHandle->pDelayMS(3000);						//SIM7600关机至少2.5S
				}break;
				default:
				{
					pHandle->pDelayMS(1000);
				}break;
			}
				
			pHandle->pDelayMS(200);
			pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL);				//恢复高电平
			for(j = 0;j < 5;j ++)
			{
				pHandle->pDelayMS(3000);							//延时3S等待关机完毕	
				if(pHandle->pGetSTATUS_Pin() == SIMCOM_L_LEVEL)		//开机脚已经是低电平了
				{
					return TRUE;
				}
			}
		}
		
		return FALSE;
	}
	else	//无需检测是否开机成功
	{
		pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL);	//拉低1200ms关机
		pHandle->pDelayMS(1200);
		pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL);	//恢复高电平
		pHandle->pDelayMS(3000);;					//延时3S等待关机完毕	
		
		return TRUE;
	}
}


/*************************************************************************************************************************
* 函数				:	SIMCOM_MODE_TYPE SIMCOM_GetMode(SIMCOM_HANDLE *pHandle)
* 功能				:	获取SIMCOM模块的型号
* 参数				:	pHandle:句柄
* 返回				:	型号,见SIMCOM_MODE_TYPE
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2015-09-12
* 最后修改时间 		: 	2015-09-12
* 说明				: 	用于识别型号,对应初始化
						2016-12-07:修改指令为AT+CGMM,兼容SIM7600,(旧指令:AT+GOI)
*************************************************************************************************************************/
SIMCOM_MODE_TYPE SIMCOM_GetMode(SIMCOM_HANDLE *pHandle)
{
	u32 cnt;
	u8 retry = SIMCOM_DEFAULT_RETRY+1;
	u8 *pData;
	
	//获取型号
	do
	{
		SIMCOM_SendAT(pHandle, "AT+CGMM");	
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200))		//等待响应,超时200MS
		{
			if(strstr((char *)pData, "SIM900") != NULL)  return SIMCOM_SIM900;
			else if(strstr((char *)pData, "SIM800") != NULL)  return SIMCOM_SIM800;
			else if(strstr((char *)pData, "SIM2000") != NULL)  return SIMCOM_SIM2000;
			else if(strstr((char *)pData, "SIM7600") != NULL)  return SIMCOM_SIM7600;
			else if(strstr((char *)pData, "SIMCOM_SIM868") != NULL)  return SIMCOM_SIM868;
			else if(strstr((char *)pData, "SIMCOM_SIM7000C") != NULL)  return SIMCOM_SIM7000C;
			else if(strstr((char *)pData, "LYNQ_L700") != NULL)  return LYNQ_L700;			
			else 
			{
				uart_printf("未知通信模块:%s\r\n",pData);
				return SIMCOM_INVALID;
			}
		}
		

		SIMCOM_Ready(pHandle);													//等待就绪
		pHandle->pDelayMS(1000);												//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return SIMCOM_INVALID;
}


/*************************************************************************************************************************
* 函数			:	bool SIMCOM_GetServeNumber(PHONE_NUMBER *pServeNumber)
* 功能			:	获取短信服务中心号码(会去掉前面的86,限制长度15位,不能用于SIM7000,SIM2000以及电信卡)
* 参数			:	pServeNumber:电话号码存储缓冲区指针
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2013-10-20
* 最后修改时间 	: 	2013-10-20
* 说明			: 	获取SIM卡内部的短信服务中心号码,一般在办理SIM卡的时候已经进行了设置.
					如果没有预置短信中心号码需要使用手机进行设置
					2014-07-12:只要返回OK则认为成功,因为有可能没有设置短信中心号码
					2016-01-26:自动选择是否跳过+86
*************************************************************************************************************************/
bool SIMCOM_GetServeNumber(SIMCOM_HANDLE *pHandle,  char pPhoneNumber[16])
{
	u8 i,n;
	u32 cnt;
	char *p,*p1;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	
	do
	{	
		//+CSCA: "+8613800270500",145
		SIMCOM_SendAT(pHandle, "AT+CSCA?");												//发送"AT+CSCA",获取短信服务中心号码
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 30, 600))		//等待响应,超时600MS
		{
			p = strstr((const char*)pData, "+CSCA:");									//搜索字符"+CSCA:"
			if(p != NULL) 																//搜索成功
			{
				p = strstr(p+1, "+");	//搜索"+"
				if(p != NULL)
				{
					p1 = strstr(p+1, "\"");	//搜索"\""
					if(p1 != NULL)			
					{
						if(p[0] == '+')			//如果是+开头,则跳过加号
						{
							p+=3;				//跳过+86
						}						
						else if(p[0]=='8' && p[1] == '6') //跳过86
						{
							p+=2;
						}
						n = p1 - p;			//计算电话号码长度
						if(n > 15) n = 15;	//限制号码长度为15字节
						for(i = 0;i < n;i ++)
						{
							pPhoneNumber[i] = p[i];	//复制电话号码
						}
						pPhoneNumber[i] = '\0';		//添加结束符

						SIMCOM_GSM_debug("短信中心号码:%s\r\n",pPhoneNumber);
						
						return TRUE;
					}
				}
			}
			else
			{
				pPhoneNumber[0] = '\0';
				SIMCOM_GSM_debug("短信中心号码:为空,没有设置\r\n");
				
				return TRUE;
			}
		}
		SIMCOM_Ready(pHandle);					//等待就绪
		pHandle->pDelayMS(1000);				//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return FALSE;
}


/*************************************************************************************************************************
* 函数			:	bool SIMCOM_GetPhoneNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16])
* 功能			:	获取本机号码(会去掉前面的86,限制长度15位,不能用于SIM7000,SIM2000以及电信卡)
* 参数			:	pHandle:句柄;pPhoneNumber:号码缓冲区
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2013-10-20
* 最后修改时间 	: 	2018-03-24
* 说明			: 	通常会预存本机号码到SIM卡,也可能没有(不能用于SIM7000,SIM2000C,不能用于电信卡)
					2014-07-12:只要返回OK则认为成功,因为有可能没有设置电话号码
					2016-01-26:修改字节超时,否则某些卡会出现超时,没有收到OK
								自动选择是否跳过+86
*************************************************************************************************************************/
bool SIMCOM_GetPhoneNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16])
{
	u8 n;
	u8 i;
	u32 cnt;
	char *p,*p1;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	

	do
	{	
		//+CNUM: "","15871750634",129,7,4
		SIMCOM_SendAT(pHandle, "AT+CNUM");												//发送"AT++CNUM",获取号码
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 30, 600))		//等待响应,超时600MS
		{
			p = strstr((const char*)pData, "+CNUM:");									//搜索字符"+CNUM:"		
			if(p != NULL) 																//搜索成功
			{
				p = strstr(p+1, "\",\"");		//搜索","	//开始
				if(p != NULL)
				{
					p1 = strstr(p+3, "\",");	//搜索",//结束
					if(p1 != NULL)			
					{
						p+=3;	//跳过","
						if(p[0] == '+')			//如果是+开头,则跳过加号
						{
							p+=3;				//跳过+86
						}						
						else if(p[0]=='8' && p[1] == '6') //跳过86
						{
							p+=2;
						}
						
						n = p1 - p;			//计算电话号码长度
						if(n > 15) n = 15;	//限制号码长度为15字节
						for(i = 0;i < n;i ++)
						{
							pPhoneNumber[i] = p[i];	//复制电话号码
						}
						pPhoneNumber[i] = '\0';		//添加结束符
						SIMCOM_GSM_debug("本机号码:%s\r\n",pPhoneNumber);
						
						return TRUE;
					}
				}
			}
			else
			{
				pPhoneNumber[0] = '\0';
				
				SIMCOM_GSM_debug("本机号码:为空,没有设置\r\n");
				return TRUE;
			}
		}
		
		SIMCOM_Ready(pHandle);				//等待就绪
		pHandle->pDelayMS(1000);			//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return FALSE;
}


/*************************************************************************************************************************
* 函数			:	bool SIMCOM_GetBookNumber(SIMCOM_HANDLE *pHandle, u8 index, char pPhoneNumber[16])
* 功能			:	从电话簿获取一个电话号码(不能用于SIM7000)
* 参数			:	pHandle:句柄;index:电话号码所有,1-255;CenterPhone:电话号码存储缓冲区指针
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2013-10-20
* 最后修改时间 	: 	2016-06-15
* 说明			: 	用于从电话簿读取一个电话号码,常用语电信卡SIM2000C模块存储本机号码到第一个索引
*************************************************************************************************************************/
bool SIMCOM_GetBookNumber(SIMCOM_HANDLE *pHandle, u8 index, char pPhoneNumber[16])
{
	u8 i,n;
	u32 cnt;
	char *p,*p1;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	char buff[32];
	
	if(index < 1) return FALSE;				//索引从1开始
	do
	{	
		//+CPBR: 1,"152778787878",129,"Phone"
		sprintf(buff,"AT+CPBR=%d",index);
		SIMCOM_SendAT(pHandle, buff);													//发送"AT+CPBR=1",获取号码
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 30, 600))		//等待响应,超时600MS
		{
			p = strstr((const char*)pData, "+CPBR:");					//搜索字符"+CPBR:"		
			if(p != NULL) 													//搜索成功
			{
				p = strstr(p+1, ",\"");	//搜索,"	//开始
				if(p != NULL)
				{
					p1 = strstr(p+2, "\",");	//搜索",//结束
					if(p1 != NULL)			
					{
						p+=2;	//跳过,"
						if(p[0] == '+')	//如果是+开头,则跳过加号
						{
							p+=3;	//跳过+86
						}
						else if(p[0]=='8' && p[1] == '6') //跳过86
						{
							p+=2;
						}
						
						n = p1 - p;			//计算电话号码长度
						if(n > 15) n = 15;	//限制号码长度为15字节
						for(i = 0;i < n;i ++)
						{
							pPhoneNumber[i] = p[i];	//复制电话号码
						}
						pPhoneNumber[i] = '\0';		//添加结束符
						
						SIMCOM_GSM_debug("号码:%s\r\n",pPhoneNumber);
						return TRUE;
					}
				}
			}
			else
			{
				pPhoneNumber[0] = '\0';
				SIMCOM_GSM_debug("号码:为空\r\n");
				
				return TRUE;
			}
		}
		SIMCOM_Ready(pHandle);					//等待就绪
		pHandle->pDelayMS(1000);				//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return FALSE;
}


/*************************************************************************************************************************
* 函数				:	int SIMCOM_GetSignal(SIMCOM_HANDLE *pHandle)
* 功能				:	获取信号强度
* 参数				:	pHandle:句柄
* 返回				:	<0:获取失败;0-31:信号强度;
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2013-10-21
* 最后修改时间 		: 	2013-10-21
* 说明				: 	无
*************************************************************************************************************************/
int SIMCOM_GetSignal(SIMCOM_HANDLE *pHandle)
{
	u8 temp;
	u32 cnt;
	char *p;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	
	do
	{	
		//+CSQ: 27,0
		//+CSQ: 5,0
		//+CSQ: 16,99
		SIMCOM_SendAT(pHandle,"AT+CSQ");												//发送"AT++CSQ",获取号码
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 400))		//等待响应,超时400MS
		{
			p = strstr((const char*)pData, "+CSQ:");									//搜索字符"+CSQ:"
			if(p != NULL) 																//搜索成功
			{
				if(p[7] != ',' && p[8] != ',') p[8] = '\0';
				temp = atoi(&p[6]);
				
				return temp;
			}
			break;
		}
		SIMCOM_Ready(pHandle);					//等待就绪
		pHandle->pDelayMS(1000);				//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return -1;
}





/*************************************************************************************************************************
* 函数			:	bool SIMCOM_GetCIMI(SIMCOM_HANDLE *pHandle, char pCIMI[16])
* 功能			:	获取SIM卡CIMI号码(SIM卡唯一id,必须存在)
* 参数			:	pHandle:句柄;pCIMI:CIMI缓冲区,长15字节
* 返回			:	FALSE:通信失败;TRUE:通信成功
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2017-11-16
* 最后修改时间 	: 	2018-03-24
* 说明			: 	用于获取卡唯一CIMI编号,防止某些卡无法读取本机号码,这个与卡号一一对应
*************************************************************************************************************************/
bool SIMCOM_GetCIMI(SIMCOM_HANDLE *pHandle, char pCIMI[16])
{
	u32 cnt;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	
	do
	{	
		//460041037206894
		SIMCOM_SendAT(pHandle, "AT+CIMI");												//发送"AT+CIMI"
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200))		//等待响应,超时200MS
		{
			if(pData[0]!='\r' || pData[1]!='\n') continue;
			memcpy(pCIMI, &pData[2], 15);	//跳过前面\r\n
			pCIMI[15] = 0;		//添加结束符
			
			SIMCOM_GSM_debug("获取CIMI成功:%s\r\n", pCIMI);
			return TRUE;
		}
		
		SIMCOM_Ready(pHandle);															//等待就绪
		pHandle->pDelayMS(1000);														//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return FALSE;
}





/*************************************************************************************************************************
* 函数				:	bool SIM7000C_GetNB_APN(SIMCOM_HANDLE *pHandle, char pAPN[17])
* 功能				:	获取SIM7000C NBIOT 接入点
* 参数				:	pHandle:句柄;pAPN:接入点缓冲区
* 返回				:	TRUE:成功;FALSE:失败
* 依赖				:	底层
* 作者				:	[email protected]
* 时间				:	2018-01-16
* 最后修改时间 		: 	2018-01-16
* 说明				: 	必须是NBIOT模式才能使用
*************************************************************************************************************************/
bool SIM7000C_GetNB_APN(SIMCOM_HANDLE *pHandle, char pAPN[17])
{
	u32 cnt;
	char *p;
	u8 retry = SIMCOM_DEFAULT_RETRY;		//重试次数
	u8 *pData;
	u8 i;

	do
	{	
		//+CGNAPN: 1,"ctnb"
		SIMCOM_SendAT(pHandle, "AT+CGNAPN");											//发送AT指令
		pHandle->pClearRxData();														//清除接收计数器
		if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 2000))		//等待响应,超时2000MS
		{
			p = strstr((const char*)pData, "+CGNAPN: 1,\"");							//搜索字符+CGNAPN: 1,"
			if(p != NULL) 																//搜索成功
			{
				p += strlen("+CGNAPN: 1,\"");
				for(i = 0;i < 17;i ++)
				{
					if(p[i] == '\"')											//结束符号位 ”
					{
						pAPN[i] = 0;
						if(i == 0) break;										//太短了
						return TRUE;
					}
					pAPN[i] = p[i];
				}
			}
		}
		
		SIMCOM_Ready(pHandle);													//等待就绪
		pHandle->pDelayMS(1000);												//失败延时1秒后重试
		retry --;
	}while(retry);
	
	return FALSE;
}

//SIMCOM_GSM.h

/*************************************************************************************************************
 * 文件名:			SIMCOM_GSM.h
 * 功能:			SIMCOM GSM相关接口
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			
*************************************************************************************************************/
#ifndef _SIMCOM_GSM_H_
#define _SIMCOM_GSM_H_
#include "system.h"
#include "simcom.h"

bool SIMCOM_NetworkConfig(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, NETWORK_CONFIG_TYPE *pConfig);		//SIMCOM网络配置
SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle);															//获取SIM卡状态
SIMCOM_NETSTATUS SIM900_GetGSMNetworkStatus(SIMCOM_HANDLE *pHandle);											//获取GSM网络注册状态
SIMCOM_NETSTATUS SIMCOM_GetDataNetworkStatus(SIMCOM_HANDLE *pHandle);											//获取数据网络注册状态
bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle);																	//初始化SIMCOM模块基本配置(不允许失败)
bool SIMCOM_GetModuleInfo(SIMCOM_HANDLE *pHandle, SIMCOM_INFO *pInfo);											//获取模块的相关信息
bool SIMCOM_COPS(SIMCOM_HANDLE *pHandle, char pCOPS_Buff[SIMCOM_INFO_SIZE]);									//获取运营商名称
SIMCOM_NETMODE_TYPE SIM7XXX_GetNetworkMode(SIMCOM_HANDLE *pHandle);												//获取SIM7XXX系列模块网络制式
bool SIMCOM_HardwarePowerUP(SIMCOM_HANDLE *pHandle, bool isTest);												//SIMCOM模块硬件开机
bool SIMCOM_HardwarePowerDOWN(SIMCOM_HANDLE *pHandle, bool isTest);												//SIMCOM模块硬件关机
SIMCOM_MODE_TYPE SIMCOM_GetMode(SIMCOM_HANDLE *pHandle);														//获取SIMCOM模块的型号
int SIMCOM_GetSignal(SIMCOM_HANDLE *pHandle);																	//获取信号强度
bool SIMCOM_GetBookNumber(SIMCOM_HANDLE *pHandle, u8 index, char pPhoneNumber[16]);								//从电话簿获取一个电话号码(不能用于SIM7000)
bool SIMCOM_GetPhoneNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16]);										//获取本机号码(会去掉前面的86,限制长度15位,不能用于SIM7000,SIM2000以及电信卡)
bool SIMCOM_GetServeNumber(SIMCOM_HANDLE *pHandle,  char pPhoneNumber[16]);										//获取短信服务中心号码(会去掉前面的86,限制长度15位,不能用于SIM7000,SIM2000以及电信卡)
bool SIMCOM_GetCIMI(SIMCOM_HANDLE *pHandle, char pCIMI[16]);													//获取SIM卡CIMI号码(SIM卡唯一id,必须存在)
bool SIM7000C_GetNB_APN(SIMCOM_HANDLE *pHandle, char pAPN[17]);													//获取SIM7000C NBIOT 接入点

#endif /*_SIMCOM_GSM_H_*/

//SIMCOM_USER.c

/*************************************************************************************************************
 * 文件名:			SIMCOM_USER.c
 * 功能:			SIMCOM用户层函数
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			
*************************************************************************************************************/
#include "system.h"
#include "usart.h"
#include "string.h"
#include "ucos_ii.h"
#include "SIMCOM_USER.h"
#include "SIMCOM_GSM.h"
#include "SIMCOM_GPRS.h"
#include "SIMCOM_AT.h"
#include "SIMCOM.h"

bool g_SIMC0M_USER_Debug = TRUE;	//应用层指令调试状态

//调试开关
#define SIMCOM_USER_DBUG		1
#if SIMCOM_USER_DBUG
	#include "system.h"
	#define SIMCOM_USER_debug(format,...)	{if(g_SIMC0M_USER_Debug){uart_printf(format,##__VA_ARGS__);}}
#else
	#define SIMCOM_USER_debug(format,...)	/\
/
#endif	//SIMCOM_USER_DBUG
	
const char  *const SIMCOM_NETWORK_NAME[18] = {"未注册","GSM","GPRS","EGPRS (EDGE)","WCDMA","HSDPA only(WCDMA)","HSUPA only(WCDMA)","HSPA (HSDPA and HSUPA, WCDMA)",
"LTE","TDS-CDMA","TDS-HSDPA only","TDS-HSUPA only","TDS- HSPA (HSDPA and HSUPA)","CDMA","EVDO","HYBRID (CDMA and EVDO)","1XLTE(CDMA and LTE)","未知,错误"};



/*************************************************************************************************************************
* 函数				:	bool SIMCOM_Init(SIMCOM_HANDLE *pHandle,
							bool (* pSendData)(u8 *pDataBuff, u16 DataLen),											
							int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay),	
							void (*pClearRxData)(void),																
							void (*pSetDTR_Pin)(u8 Level),															
							void (*pSetPWRKEY_Pin)(u8 Level),														
							u8 (*pGetSTATUS_Pin)(void),	
							u8 (*pGetDCD_Pin)(void),
							void (*pDelayMS)(u32 ms),																
							void (*pIWDG_Feed)(void)
* 功能				:	初始化SIMCOM句柄接口
* 参数				:	pSl651_Handle:句柄;
						pSendCallBack:发送回调函数(pDataBuff:发送数据缓冲区,DataLen:发送数据长度)
						pReadCallBack:接收数据回调函数,会等待直到数据被写入到接收缓冲区(pDataBuff:接收数据缓冲区,ByteTimeOut:等待的字节超时时间,单位ms,TimeOut:数据包超时时间,单位ms)
						pClearRxData:清除接收缓冲区函数,用于清除接收数据缓冲区数据
						pSetDTR_Pin:DTR引脚电平控制-用于控制sleep模式或者退出透传模式
						pSetPWRKEY_Pin:PWRKEY开机引脚电平控制-用于开机
						pGetSTATUS_Pin:获取STATUS引脚电平-用于指示模块上电状态
						pGetDCD_Pin:获取DCD引脚电平-高电平AT指令模式,低电平为透传模式
						pDelayMS:系统延时函数
						pIWDG_Feed:清除系统看门狗(可以为空)
* 返回				:	无
* 依赖				:	TRUE:成功,FALSE:失败
* 作者				:	[email protected]
* 时间				:	2018-03-24
* 最后修改时间 		: 	2018-03-24
* 说明				: 	除pIWDG_Feed接口可以为空,其余接口均不能为空,否则程序会崩溃
*************************************************************************************************************************/
bool SIMCOM_Init(SIMCOM_HANDLE *pHandle,
		bool (* pSendData)(u8 *pDataBuff, u16 DataLen),											//发送数据接口,如果发送失败,返回FALSE,成功返回TRUE;
		int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay),	//接收数据接口,返回数据长度,如果失败返回<=0,成功,返回数据长度
		void (*pClearRxData)(void),																//清除接收缓冲区函数,用于清除接收数据缓冲区数据
		void (*pSetDTR_Pin)(u8 Level),															//DTR引脚电平控制-用于控制sleep模式或者退出透传模式
		void (*pSetPWRKEY_Pin)(u8 Level),														//PWRKEY开机引脚电平控制-用于开机
		u8 (*pGetSTATUS_Pin)(void),																//获取STATUS引脚电平-用于指示模块上电状态
		u8 (*pGetDCD_Pin)(void),																//获取DCD引脚电平-高电平AT指令模式,低电平为透传模式
		void (*pDelayMS)(u32 ms),																//系统延时函数
		void (*pIWDG_Feed)(void)																//清除系统看门狗(可以为空)
	)
{
	if(pHandle == NULL) 
	{
		DEBUG("无效的句柄!\r\n");
		return FALSE;
	}
	//所需变量
	pHandle->SimcomModeType = SIMCOM_INVALID;							//模块型号
	pHandle->TelecomCarr[0] = 0;										//运营商名称
	memset(&pHandle->SIMCOM_Info, 0, sizeof(SIMCOM_INFO));				//SIMCOM通信模块相关信息结构体
	memset(&pHandle->NetworkConfig, 0, sizeof(NETWORK_CONFIG_TYPE));	//网络模式设置
	pHandle->NetworkMode = SIMCOM_NETMODE_NULL;							//当前网络制式
	
	
	//底层通信接口
	pHandle->pSendData = pSendData;										//发送数据接口,如果发送失败,返回FALSE,成功返回TRUE;
	pHandle->pReadData = pReadData;										//接收数据接口,返回数据长度,如果失败返回<=0,成功,返回数据长度
	pHandle->pClearRxData = pClearRxData;								//清除接收缓冲区函数,用于清除接收数据缓冲区数据
	pHandle->pSetDTR_Pin = pSetDTR_Pin;									//DTR引脚电平控制-用于控制sleep模式或者退出透传模式
	pHandle->pSetPWRKEY_Pin = pSetPWRKEY_Pin;							//PWRKEY开机引脚电平控制-用于开机
	pHandle->pGetSTATUS_Pin = pGetSTATUS_Pin;							//获取STATUS引脚电平-用于指示模块上电状态
	pHandle->pGetDCD_Pin = pGetDCD_Pin;									//获取DCD引脚电平-高电平AT指令模式,低电平为透传模式
	//系统接口
	pHandle->pDelayMS = pDelayMS;										//系统延时函数
	pHandle->pIWDG_Feed = pIWDG_Feed;									//清除系统看门狗(可以为空)
	//内部状态定义
	pHandle->s_isInitStatus = FALSE;									//用于记录模块初始化状态,复位或上电后变为无效
	//检查是否有接口为空
	if(pHandle->pSendData==NULL || pHandle->pReadData==NULL || pHandle->pClearRxData==NULL || pHandle->pSetDTR_Pin==NULL || pHandle->pSetPWRKEY_Pin==NULL || 
		pHandle->pGetSTATUS_Pin==NULL || pHandle->pGetDCD_Pin==NULL || pHandle->pDelayMS==NULL)
	{
		DEBUG("错误,有回调接口为空!\r\n");
		return FALSE;
	}
	
	return TRUE;
}



/*************************************************************************************************************************
* 函数			:	void SIMCOM_PrintfModel(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, const char **pModeInof)
* 功能			:	显示并打印模块型号
* 参数			:	pHandle:句柄;ModeType:模块型号;pModeInof:返回模块型号信息(不需要可以为空)
* 返回			:	无
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2017-10-17
* 最后修改时间	: 	2018-03-24
* 说明			: 	
*************************************************************************************************************************/ 
void SIMCOM_PrintfModel(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, const char **pModeInof)
{
	switch(ModeType)
	{
		case SIMCOM_SIM900 :	//默认为SIM900
		{
			if(pModeInof!=NULL) *pModeInof = "SIM900系列";//通信模块型号	
			uart_printf("[DTU]通信模块为SIM900\r\n");	
		}break;
		case SIMCOM_SIM800 :	//SIM800
		{
			if(pModeInof!=NULL) *pModeInof = "SIM800系列";			//通信模块型号
			uart_printf("[DTU]通信模块为SIM800\r\n");
		}break;
		case SIMCOM_SIM2000	:	//SIM2000
		{
			
			if(pModeInof!=NULL) *pModeInof = "SIM2000系列";			//通信模块型号
			uart_printf("[DTU]通信模块为SIM2000\r\n");
		}break;
		case SIMCOM_SIM7600	:	//SIM7600
		{
			if(pModeInof!=NULL) *pModeInof = "SIM7600系列";			//通信模块型号
			uart_printf("[DTU]通信模块为SIM7600\r\n");
		}break;
		case SIMCOM_SIM868:		//SIM868
		{
			if(pModeInof!=NULL) *pModeInof = "SIM868系列";			//通信模块型号
			uart_printf("[DTU]通信模块为SIM868模块\r\n");
		}break;
		case SIMCOM_SIM7000C:	//SIM7000C
		{
			if(pModeInof!=NULL) *pModeInof = "SIM7000C系列";		//通信模块型号
			uart_printf("[DTU]通信模块为SIM7000C\r\n");
		}break;
		case LYNQ_L700:		//LYNQ_L700
		{
			if(pModeInof!=NULL) *pModeInof = "L700系列";			//通信模块型号
			uart_printf("[DTU]通信模块为L700模块\r\n");
		}break;
		case SIMCOM_INVALID	:	//无效则默认
		{
			if(pModeInof!=NULL) *pModeInof = "未知";				//通信模块型号
			uart_printf("[DTU]通信模块未知!\r\n");
		}break;
	}
}





/*************************************************************************************************************************
* 函数			:	SIMCOM_USER_ERROR SIMCOM_RegisNetwork(SIMCOM_HANDLE *pHandle, u16 Retry, u16 NetworkDelay,const char **pModeInof)
* 功能			:	SIMCOM模块上电初始化并注册网络
* 参数			:	pHandle:句柄;Retry:初始化重试次数>0;NetworkDelay:注册网络延时时间,单位S;pModeInof:返回模块型号信息(不需要可以为空)
* 返回			:	SIMCOM_USER_ERROR	
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2014-08-18
* 最后修改时间	: 	2018-03-24
* 说明			: 	用于通信模块上电并初始化操作		
*************************************************************************************************************************/ 
SIMCOM_USER_ERROR SIMCOM_RegisNetwork(SIMCOM_HANDLE *pHandle, u16 Retry, u16 NetworkDelay,const char **pModeInof)
{
	SIMCOM_NETSTATUS NetStatus;
	SIMCOM_MODE_TYPE ModeType = SIMCOM_INVALID;					//初始化模块型号无效
	SIMCOM_NETMODE_TYPE NetworkMode = SIMCOM_NETMODE_NULL;		//初始化为未知模式
	SIMCOM_USER_ERROR Error = SIMCOM_NULL_ERROR;				//初始化状态
	
	u16 pcnt,cnt;
	u8 NotCnt,SeaCnt,TurCnt,UnkCnt,ErrCnt;
	bool isCart = FALSE;
	u8 SIM_NotReadyCnt = 0;										//SIM卡未准备就绪计数器
	
	Retry += 1;													//重试次数至少1次
	//模块上电
	for(pcnt = 0;pcnt < Retry;pcnt ++)							//上电循环
	{
		SIM_NotReadyCnt = 0;									//SIM卡未准备就绪计数器复位
		if(pHandle->pIWDG_Feed!=NULL) pHandle->pIWDG_Feed();	//喂狗

		if(pHandle->pGetSTATUS_Pin()==SIMCOM_L_LEVEL)			//模块没有上电	
		{
			pHandle->s_isInitStatus = FALSE;					//模块没有初始化
			SIMCOM_USER_debug("[SIMCOM]:模块没有上电!\r\n");
			if(SIMCOM_HardwarePowerUP(pHandle, TRUE) == TRUE)	//上电
			{
				SIMCOM_USER_debug("[SIMCOM]:开机成功!\r\n");
				if(SIMCOM_TestAT(pHandle, 50) != TRUE)					//发送AT测试命令
				{
					if(pModeInof!=NULL) *pModeInof = "模块未知";
					SIMCOM_USER_debug("[SIMCOM]:通信错误,串口错误!\r\n");
				}
			}
			else
			{
				if(pModeInof!=NULL) *pModeInof = "模块未知";
				SIMCOM_USER_debug("[SIMCOM]:开机失败!\r\n");
				Error = SIMCOM_POWER_UP_ERROR;					//开机失败
			}
			
		}
		
		//上电完毕后初始化模块
		if(pHandle->pGetSTATUS_Pin() == SIMCOM_H_LEVEL)		
		{
			//模块初始化网络
			if(NetworkDelay == 0) NetworkDelay = 0xffff;				//为0,一直等待	
			NotCnt=SeaCnt=TurCnt=UnkCnt=ErrCnt=0;						//初始化注册状态计数器为0

			//获取模块型号
			if(ModeType == SIMCOM_INVALID)
			{
				SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "\r\n关闭AT回显模式失败!\r\n");
				pHandle->pDelayMS(500);
				ModeType = SIMCOM_GetMode(pHandle);						//获取模块型号
				SIMCOM_PrintfModel(pHandle, ModeType, pModeInof);		//打印显示通信模块型号		
			}
			//型号获取成功了,更新信息
			if(ModeType!=SIMCOM_INVALID)
			{
				pHandle->SimcomModeType = ModeType;						//上电初始化设置通信模块型号	
			}
			
			//根据模块类型进行初始化,如果是SIM7000C,需要选择工作在GSM模式还是NBIOT模式
			if(SIMCOM_NetworkConfig(pHandle, ModeType, &pHandle->NetworkConfig)==FALSE)
			{
				uart_printf("[DTU]初始化通信模块网络模式失败了!\r\n");	
			}
			
			//初始化获取网络信息
			for(cnt = 0;cnt < NetworkDelay;cnt ++)
			{
				if(pHandle->pGetSTATUS_Pin()==SIMCOM_L_LEVEL) 
				{
					Error = SIMCOM_POWER_UP_ERROR;			//异常断电
					uart_printf("[DTU]异常断电了,请检查供电是否稳定!\r\n");	
					break;									//模块没有上电,初始化
				}
				
				if(ModeType == SIMCOM_INVALID)
				{
					SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "\r\n关闭AT回显模式失败!\r\n");
					pHandle->pDelayMS(500);
					ModeType = SIMCOM_GetMode(pHandle);								//获取模块型号
					pHandle->SimcomModeType = ModeType;								//上电初始化设置通信模块型号	
					SIMCOM_PrintfModel(pHandle, ModeType, pModeInof);				//打印显示通信模块型号
				}
				
				if(isCart == FALSE)													//卡未检测到,则一直重新检测
				{
					if(SIMCOM_GetCPIN(pHandle)==SIM_READY)
					{
						isCart = TRUE;	//卡检测成功
						uart_printf("\r\nSIM卡准备就绪!\r\n");
					}
					else
					{
						uart_printf("\r\nSIM卡未准备就绪!\r\n");
						Error = SIMCOM_SIM_NOT_REALYE;								//卡未就绪
					}
				}
				
				
				//2018-01-18 增加SIM7000C NB模式网络注册状态获取支持
				if((ModeType == SIMCOM_SIM7000C) && (pHandle->NetworkConfig.NB_EnableMode==1)) //如果是SIM7000C,并且开启了NB模式
				{
					NetStatus = SIMCOM_GetDataNetworkStatus(pHandle);				//获取数据网络网络注册状态
				}
				else
				{
					NetStatus = SIM900_GetGSMNetworkStatus(pHandle);				//获取GSM网络注册状态
				}

				SIMCOM_USER_debug("[DTU]网络注册状态%d!\r\n",NetStatus);
				//一直出现网络未注册以及注册拒绝,重启,有些卡会先出现拒绝,然后出现注册成功
				switch(NetStatus)
				{
					case SIMCOM_NET_NOT	:	
					{
						NotCnt++;
						//2017-09-09 增加如果连续15次未检测到卡,并且未注册,则直接退出,返回未插卡
						if(SIMCOM_GetCPIN(pHandle)==SIM_NOT_READY)
						{
							Error = SIMCOM_SIM_NOT_REALYE;	//卡未就绪
							SIM_NotReadyCnt ++;				//SIM卡未准备就绪计数器增加
						}
						else
						{
							SIM_NotReadyCnt = 0;			//SIM卡未就绪计数器复位
						}
					}break;	//未注册
					case SIMCOM_NET_ROA	:					//已经注册,但是漫游
					case SIMCOM_NET_YES	:					//已经注册
					{
						SIM_NotReadyCnt = 0;				//SIM卡未就绪计数器复位
						if(pHandle->s_isInitStatus == FALSE)//模块没有初始化
						{
							if(SIMCOM_ModuleInit(pHandle) == FALSE)						//上电后初始化模块基本配置
							{
								SIMCOM_USER_debug("[DTU]初始化失败!\r\n");	
								if(isCart==TRUE) Error = SIMCOM_INIT_ERROR;				//卡初始化成功了,才返回初始化错误
								goto reset;
							}
						}
						
						//获取模块信息
						if( SIMCOM_GetModuleInfo(pHandle, &pHandle->SIMCOM_Info) == TRUE)		//获取模块的相关信息
						{
							SIMCOM_USER_debug("\r\n制造商:%s\r\n",pHandle->SIMCOM_Info.Manu);	
							SIMCOM_USER_debug("模块型号:%s\r\n",pHandle->SIMCOM_Info.Model);
							SIMCOM_USER_debug("软件版本:%s\r\n",pHandle->SIMCOM_Info.Ver);
							SIMCOM_USER_debug("模块序列号:%s\r\n",pHandle->SIMCOM_Info.IMEI);
						}
						else
						{
							SIMCOM_USER_debug("\r\n获取模块信息失败!\r\n");
						}
						//获取运营商信息
						if(SIMCOM_COPS(pHandle, pHandle->TelecomCarr) == TRUE)		//获取运营商名称
						{
							SIMCOM_USER_debug("运营商信息:%s\r\n", pHandle->TelecomCarr);	
						}
						else
						{
							SIMCOM_USER_debug("获取运营商信息失败!\r\n");
						}
						
						//如果是SIM7600 SIM7000C模块,则需要获取网络制式
						switch(ModeType)
						{
							case SIMCOM_SIM7600:
							case SIMCOM_SIM7000C:
							{
								NetworkMode = SIM7XXX_GetNetworkMode(pHandle);			//获取SIM7XXX系列模块网络制式
								pHandle->NetworkMode = NetworkMode;						//记录全局网络制式,必须在获取短信中心号码之前进行获取,因为电信卡无短信中心号码用于初始化
								if(NetworkMode > 16)
								{
									SIMCOM_USER_debug("网络制式:获取失败\r\n");
								}
								else
								{
									SIMCOM_USER_debug("网络制式:%s\r\n",SIMCOM_NETWORK_NAME[NetworkMode]);
								}
							}break;
							default: //2G
							{
								pHandle->NetworkMode = SIMCOM_NETMODE_GSM;				//其它2G模块默认GSM网络
							}break;
						}
						
						Error = SIMCOM_INIT_OK;							//初始化成功
						return Error;									//已经注册并初始化了
					}
					case SIMCOM_NET_SEA	:	SeaCnt++;break;	//未注册,正在搜索
					case SIMCOM_NET_TUR	:	TurCnt++;break;	//注册被拒绝
					case SIMCOM_NET_UNK	:	UnkCnt++;break;	//未知
					default				:	ErrCnt++;break;	//错误
				}
				
				if((TurCnt > 60) || (UnkCnt > 20) || (ErrCnt > 20)) 		//注册被拒绝,或者错误
				{
					if(isCart==TRUE) Error = SIMCOM_REG_ERROR;				//卡初始化成功了,才返回初注册失败
					SIMCOM_USER_debug("[DTU]模块重启!\r\n");
					if(SIMCOM_HardwarePowerDOWN(pHandle, TRUE) == FALSE)
					{
						SIMCOM_USER_debug("[DTU]:关机失败!\r\n");
					}
					break;
				}
				
				//SIM卡未就绪次数过多
				if(SIM_NotReadyCnt > 16)
				{
					
					uart_printf("[DTU]:多次检测到卡未就绪!模块重启!\r\n");
					if(SIMCOM_HardwarePowerDOWN(pHandle, TRUE) == FALSE)
					{
						SIMCOM_USER_debug("[DTU]:关机失败!\r\n");
					}
					break;
				}
							
				//延时
				pHandle->pDelayMS(800);
				if(pHandle->pIWDG_Feed!=NULL) pHandle->pIWDG_Feed();	//喂狗
				
			}	
			//网络注册失败或模块初始化失败
			
reset:			
			if(SIMCOM_HardwarePowerDOWN(pHandle, TRUE) == TRUE)				//关闭电源
			{
				uart_printf("[DTU]:网络初始化失败,模块关机成功!\r\n");
			}
			else
			{
				uart_printf("[DTU]:网络初始化失败,模块关机失败!\r\n");
			}
		}
		else
		{
			Error = SIMCOM_POWER_UP_ERROR;							//开机失败
		}
	}
	
	//显示错误信息
	switch(Error)
	{
		case SIMCOM_INIT_OK				:	//初始化成功	
		{
			uart_printf("[DTU]:模块上电或初始成功!\r\n");
		}break;
		case SIMCOM_POWER_UP_ERROR		:	//上电错误
		{
			uart_printf("[DTU]:模块上电错误!\r\n");
		}break;
		case SIMCOM_REG_ERROR			:	//注册出错(超时)
		{
			uart_printf("[DTU]:模块注册网络出错(超时)!\r\n");
		}break;
		case SIMCOM_INIT_ERROR			:	//初始化配置错误
		{
			uart_printf("[DTU]:模块初始化配置出错!\r\n");
		}break;
		case SIMCOM_SIM_NOT_REALYE		:	//SIM卡未就绪导致上电失败
		{
			uart_printf("[DTU]:模块SIM卡未就绪!\r\n");
		}break;
		default: 
		{
			uart_printf("[DTU]:未知的错误!\r\n");
		}break;
	}
	
	
	return Error;	
}





/*************************************************************************************************************************
* 函数			:	bool SIMCOM_PhoneMessageNumberInitialize(SIMCOM_HANDLE *pHandle, u8 retry)
* 功能			:	SIMCOM 初始化获取短信中心号码以及本机号码,信号强度,CIMI(结果存放在句柄pHandle中)
* 参数			:	pHandle:句柄;Retry:初始化重试次数>0
* 返回			:	TRUE成功,FALSE:失败	
* 依赖			:	底层
* 作者			:	[email protected]
* 时间			:	2014-08-18
* 最后修改时间	: 	2018-03-24
* 说明			: 	用于网络初始化之后进行初始化获取相关信息,需要提前初始化网络模块型号以及网络制式
					短信中心号码存放在:pHandle->ServiceCenterPhoneNumber;	
					电话号码存放在:pHandle->LocalPhoneNumber;	
					信号强度存放在:pHandle->Singal;
					SIM卡CIMI号码存放在pHandle->SIM_CIMI;
					2016-06-15:SIM2000C使用电信SIM卡时,过快读取本机号码会失败,增加延时,确保读取成功
					2016-11-16:增加获取短信中心号码延时
					2017-12-05:NBIO 模块不读取电话号码
*************************************************************************************************************************/ 
bool SIMCOM_PhoneMessageNumberInitialize(SIMCOM_HANDLE *pHandle, u8 retry)
{
	u8 i;				//重试计数器
	int Singal;
	bool status;
	bool isReadServerNumber = TRUE;	//是否需要获取短信中心号码,电信卡无需获取

	//测试AT指令
	SIMCOM_Ready(pHandle);
	if(SIMCOM_TestAT(pHandle, 20) != TRUE)
	{
		
		return FALSE;
	}
	
	
	retry += 1;
	//获取短信中心号码
	if(pHandle->SimcomModeType == SIMCOM_SIM2000)			//电信模块无需获取短信中心号码
	{
		isReadServerNumber = FALSE;
	}
	else if(pHandle->SimcomModeType == LYNQ_L700)			//L700 NBIOT 无需获取短信中心号码
	{
		isReadServerNumber = FALSE;
	}
	else if(pHandle->SimcomModeType==SIMCOM_SIM7000C)		//SIM7000C
	{
		isReadServerNumber = FALSE; //sim7000不支持
	}
	else if(pHandle->SimcomModeType==SIMCOM_SIM7600)		//SIM7600
	{
		switch(pHandle->NetworkMode)						//查看网络制式,如果是CDMA(电信卡)则不需要获取短信中心号码
		{
			case SIMCOM_NETMODE_CDMA	://CDMA
			case SIMCOM_NETMODE_EVDO	://EVDO
			case SIMCOM_NETMODE_HYBRID	://HYBRID (CDMA and EVDO)
			case SIMCOM_NETMODE_1XLTE	://1XLTE(CDMA and LTE)
			{
				isReadServerNumber = FALSE;
			}break;
		}
	}

	if(isReadServerNumber)				//需要获取短信中心号码
	{
		for(i = 0;i < retry;i ++)
		{
			if(SIMCOM_GetServeNumber(pHandle, pHandle->ServiceCenterPhoneNumber) == TRUE)				//获取短信服务中心号码成功
			{
				if(pHandle->ServiceCenterPhoneNumber[0] == 0)
				{
					SIMCOM_USER_debug("短信中心号码为空\r\n");
				}
				else
				{
					SIMCOM_USER_debug("短信中心号码:%s\r\n",pHandle->ServiceCenterPhoneNumber);
				}
				break;
			}
			else
			{
				SIMCOM_WaitSleep(pHandle, 100);
				SIMCOM_Ready(pHandle);
				pHandle->pDelayMS(1000);
			}
		}
		if(i==retry) return FALSE;
	}
	else
	{
		pHandle->pDelayMS(2000);	//等待2s钟
		strcpy(pHandle->ServiceCenterPhoneNumber, "13800818500");	//短信中心号码-固定值,防止为空
		SIMCOM_USER_debug("[缺省]短信中心号码:%s\r\n",pHandle->ServiceCenterPhoneNumber);
	}
	
	//获取信号强度
	for(i = 0;i < retry;i ++)
	{
		Singal = SIMCOM_GetSignal(pHandle);				//获取信号强度
		if((Singal > 0) && (Singal!=99)) 
		{
			pHandle->Singal = (u8)Singal;
			SIMCOM_USER_debug("信号强度 <%02d>!\r\n" ,Singal);
			break;
		}
		else
		{
			pHandle->Singal = 0;			//没有读取到,延时2秒
			pHandle->pDelayMS(2000);		//等待2s钟
		}
		SIMCOM_WaitSleep(pHandle, 100);
		SIMCOM_Ready(pHandle);
		pHandle->pDelayMS(1000);			//等待1s钟
	}
	
	//获取本机号码
	for(i = 0;i < retry;i ++)
	{
		if(pHandle->NetworkMode == LYNQ_L700)			//L700 NBIOT 无法获取
		{
			pHandle->pDelayMS(1000);					//等待1s钟
			pHandle->LocalPhoneNumber[0] = 0;
			
			return TRUE;
		}
		else if(pHandle->NetworkMode == SIMCOM_SIM7000C)	//SIM7000C 无法获取
		{
			pHandle->pDelayMS(1000);			//等待1s钟
			pHandle->LocalPhoneNumber[0] = 0;
			
			return TRUE;
		}
		else if(pHandle->SimcomModeType==SIMCOM_SIM7600)		//SIM7600,SIM7000C
		{
			switch(pHandle->NetworkMode)						//查看网络制式,如果是CDMA(电信卡)则不需要获取短信中心号码
			{
				case SIMCOM_NETMODE_CDMA	://CDMA
				case SIMCOM_NETMODE_EVDO	://EVDO
				case SIMCOM_NETMODE_HYBRID	://HYBRID (CDMA and EVDO)
				case SIMCOM_NETMODE_1XLTE	://1XLTE(CDMA and LTE)
				{
					status = SIMCOM_GetBookNumber(pHandle, 1, pHandle->LocalPhoneNumber);	//从电话簿中读取一个电话号码
				}break;
				default: //其他制式可以读取
				{
					status = SIMCOM_GetPhoneNumber(pHandle, pHandle->LocalPhoneNumber);	//读取本机号码
				}break; 
			}
		}
		else if(pHandle->SimcomModeType == SIMCOM_SIM2000) //SIM2000
		{
			status = SIMCOM_GetBookNumber(pHandle, 1, pHandle->LocalPhoneNumber);	//从电话簿中读取一个电话号码
		}	
		
		else	//其它模块
		{
			status = SIMCOM_GetPhoneNumber(pHandle, pHandle->LocalPhoneNumber);	//读取本机号码
		}
		
		
		if(status== TRUE)			//获取本机号码成功
		{
			pHandle->LocalPhoneNumber[15] = 0;
			if(pHandle->LocalPhoneNumber[0] == 0)
			{
				SIMCOM_USER_debug("本机号码为空\r\n");
			}
			else
			{
				SIMCOM_USER_debug("本机号码:%s\r\n",pHandle->LocalPhoneNumber);
			}
			break;
		}
		else
		{
			SIMCOM_WaitSleep(pHandle, 100);
			SIMCOM_Ready(pHandle);
			pHandle->pDelayMS(2000);		//等待2s钟
		}
	}
	if(i==retry) return FALSE;
	
	
	//获取SIM卡CIMI号码
	for(i = 0;i < retry;i ++)
	{
		//获取SIM卡CIMI号码(SIM卡唯一id,必须存在)
		if(SIMCOM_GetCIMI(pHandle, pHandle->SIM_CIMI) == TRUE) break;
		
		SIMCOM_WaitSleep(pHandle, 100);
		SIMCOM_Ready(pHandle);
		pHandle->pDelayMS(1000);			//等待1s钟
	}
	if(i==retry) return FALSE;

	
	return TRUE;
}

//SIMCOM_USER.h

/*************************************************************************************************************
 * 文件名:			SIMCOM_USER.h
 * 功能:			SIMCOM用户层函数
 * 作者:			[email protected]
 * 创建时间:		2015-02-15
 * 最后修改时间:	2018-03-23
 * 详细:			
*************************************************************************************************************/
#ifndef _SIMCOM_SUER_H_
#define _SIMCOM_SUER_H_
#include "system.h"
#include "simcom.h"

//SIMCOM 初始化错误
typedef enum
{
	SIMCOM_INIT_OK				=	0,	//初始化成功
	
	SIMCOM_POWER_UP_ERROR		=	1,	//上电错误
	SIMCOM_REG_ERROR			=	2,	//注册出错(超时)
	SIMCOM_INIT_ERROR			=	3,	//初始化配置错误
	SIMCOM_SIM_NOT_REALYE		=	4,	//SIM卡未就绪导致上电失败
	SIMCOM_NULL_ERROR			=	255	//状态无效
}SIMCOM_USER_ERROR;


//API
//初始化SIMCOM句柄接口
bool SIMCOM_Init(SIMCOM_HANDLE *pHandle,
		bool (* pSendData)(u8 *pDataBuff, u16 DataLen),											//发送数据接口,如果发送失败,返回FALSE,成功返回TRUE;
		int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay),	//接收数据接口,返回数据长度,如果失败返回<=0,成功,返回数据长度
		void (*pClearRxData)(void),																//清除接收缓冲区函数,用于清除接收数据缓冲区数据
		void (*pSetDTR_Pin)(u8 Level),															//DTR引脚电平控制-用于控制sleep模式或者退出透传模式
		void (*pSetPWRKEY_Pin)(u8 Level),														//PWRKEY开机引脚电平控制-用于开机
		u8 (*pGetSTATUS_Pin)(void),																//获取STATUS引脚电平-用于指示模块上电状态
		u8 (*pGetDCD_Pin)(void),																//获取DCD引脚电平-高电平AT指令模式,低电平为透传模式
		void (*pDelayMS)(u32 ms),																//系统延时函数
		void (*pIWDG_Feed)(void)																//清除系统看门狗(可以为空)
	);
		
SIMCOM_USER_ERROR SIMCOM_RegisNetwork(SIMCOM_HANDLE *pHandle, u16 Retry, u16 NetworkDelay,const char **pModeInof);//SIMCOM模块上电初始化并注册网络
bool SIMCOM_PhoneMessageNumberInitialize(SIMCOM_HANDLE *pHandle, u8 retry);						//SIMCOM 初始化获取短信中心号码以及本机号码,信号强度,CIMI(结果存放在句柄pHandle中)



#endif /*_SIMCOM_SUER_H_*/

//底层相关接口,自己根据自己的平台进行开发的接口

//发送数据接口
static bool GPRS_UART_SendData(u8 DataBuff[], u16 DataLen)
{
	UARTx_SendData(SIMCOM_UART_CH, DataBuff, DataLen);
	
	return TRUE;
}



//接收数据接口
static int GPRS_UART_ReadData(u8 **pDataBuff,u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelayMs)
{
	u32 cnt = 0;
	u16 TempTime;
	
	if(ByteTimeOutMs < 1) ByteTimeOutMs = 1;	//字节超时时间,2个帧之间的间隔最小时间
	TimeOutMs /= ByteTimeOutMs;
	TimeOutMs += 1;
	TempTime = TimeOutMs;
	while(TimeOutMs --)
	{
		cnt = UARTx_GetRxCnt(SIMCOM_UART_CH);
		OSTimeDlyHMSM(0,0,0,ByteTimeOutMs);;
		if((cnt > 0) && (cnt == UARTx_GetRxCnt(SIMCOM_UART_CH)))
		{
			if(pReceiveDelayMs!=NULL)	//需要返回延时
			{
				*pReceiveDelayMs = (TempTime-TimeOutMs)*ByteTimeOutMs;
			}
			*pDataBuff = g_SIMCOM_Buff;						//接收缓冲区
			
			return cnt;
		}
#if SYS_WDG_EN_
		IWDG_Feed();										//喂狗
#endif			
	}
	
	return 0;
}


//清除接收缓冲区
static void GPRS_UART_ClearData(void)
{
	UARTx_ClearRxCnt(SIMCOM_UART_CH);	//清除串口缓冲区
}
/////////////////////////////////////////////////////////////////////////////////////////////
//SIM900/SIM800通信支持
//GSM模块相关定义
#define SIMCOM_UART_CH			UART_CH3			//串口3
#define SIMCOM_UART_BAUD		115200				//波特率
#define SIMCOM_UART_BUFF_SIZE	(1024*4)			//接收缓冲区大小

//相关控制引脚
__inline void SIMCOM_SetDTR(u8 Level)		{(PGout(4)=Level);}			//DTR
__inline void SIMCOM_SetPWRKEY(u8 Level)	{(PGout(3)=Level);}			//PWRKEY
__inline u8 SIMCOM_GetSTATUS(void)			{return PGin(5)?1:0;}		//STATUS
__inline u8 SIMCOM_GetDCD(void)				{return PDin(11)?1:0;}		//DCD-上拉输入,高电平AT指令模式,低电平为透传模式

//引脚初始化
__inline void SIMCOM_IO_Init(void)	
{
	SYS_DeviceClockEnable(DEV_GPIOD, TRUE);					//使能GPIOD时钟
	SYS_DeviceClockEnable(DEV_GPIOG, TRUE);					//使能GPIOG时钟
	SYS_GPIOx_Init(GPIOG, BIT3|BIT4, OUT_PP, SPEED_2M);		//推挽输出
	SYS_GPIOx_OneInit(GPIOD, 11, IN_IPU, IN_NONE);			//DCD 上拉输入
	SYS_GPIOx_OneInit(GPIOG, 5, IN_IPD, IN_NONE);			//STATUS 下拉输入
}  

另外还有一个看门狗清除的回调函数

//喂独立看门狗
__inline void IWDG_Feed(void) {IWDG->KR=0XAAAA;}

//实现了以上的接口就可以调用了

//下面是应用层调用,使用了ucos的一个任务

SIMCOM_HANDLE	g_SIMCOM_Handle;								//SIMCOM通信模块句柄
u8 g_SIMCOM_Buff[SIMCOM_UART_BUFF_SIZE+1];						//串口接收缓冲区



static bool GPRS_UART_SendData(u8 DataBuff[], u16 DataLen);		//发送数据接口
static int GPRS_UART_ReadData(u8 **pDataBuff,u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelayMs);		//接收数据接口
static void GPRS_UART_ClearData(void);							//清除接收缓冲区


//GPRS通信任务
void GPRS_Task(void *pdata)
{
	const char *pModeInof;
		
	UARTx_Init(SIMCOM_UART_CH, SIMCOM_UART_BAUD, ENABLE);													//初始化串口
	UARTx_SetRxBuff(SIMCOM_UART_CH, g_SIMCOM_Buff,  SIMCOM_UART_BUFF_SIZE);									//设置串口接收缓冲区
	SIMCOM_IO_Init();																						//SIMCOM相关IO初始化
	OSTimeDlyHMSM(0,0,0,20);
	
	//初始化SIMCOM句柄接口
	SIMCOM_Init(&g_SIMCOM_Handle,
		GPRS_UART_SendData,		//发送数据接口,如果发送失败,返回FALSE,成功返回TRUE;
		GPRS_UART_ReadData,		//接收数据接口,返回数据长度,如果失败返回<=0,成功,返回数据长度
		GPRS_UART_ClearData,	//清除接收缓冲区函数,用于清除接收数据缓冲区数据
		SIMCOM_SetDTR,			//DTR引脚电平控制-用于控制sleep模式或者退出透传模式
		SIMCOM_SetPWRKEY,		//PWRKEY开机引脚电平控制-用于开机
		SIMCOM_GetSTATUS,		//获取STATUS引脚电平-用于指示模块上电状态
		SIMCOM_GetDCD,			//DCD-上拉输入,高电平AT指令模式,低电平为透传模式
		SYS_DelayMS,			//系统延时函数
		IWDG_Feed				//清除系统看门狗(可以为空)
	);
		
	while(1)
	{
		SIMCOM_RegisNetwork(&g_SIMCOM_Handle, 6, 60, &pModeInof);//SIMCOM模块上电初始化并注册网络
		//SIMCOM 初始化获取短信中心号码以及本机号码,信号强度,CIMI(结果存放在句柄pHandle中)
		if(SIMCOM_PhoneMessageNumberInitialize(&g_SIMCOM_Handle, 3) == FALSE)
		{
			uart_printf("\r\n警告:初始化获取相关信息失败!\r\n");
		}
		
		
		OSTimeDlyHMSM(0,5,0,20);
	}
}

//以上代码实现了通信模块的初始化,开机,联网,读取本机号码,中心站号码,SIMI码,信号等操作,感兴趣的朋友可以依照此模板进行后续的开发,使用底层分离的方式可以让代码解耦便于在各个平台上面移植,同时增加了稳定性。

//下面是串口打印的信息,命令执行的很快,我使用的是SIM7600CE模块,全网通4G,初始化非常快,每个文件都有定义调试开关,可以动态使用一个变量控制开关,也可以使用宏定义控制调试信息开关。

SIMCOM(26B)->
SIMCOM_SIM7600CE

OK

OK 返回成功!
[DTU]通信模块为SIM7600

SIMCOM(22B)->
+CPIN: READY

OK

OK 返回成功!

SIM卡准备就绪!

SIMCOM(20B)->
+CREG: 0,1

OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!
[DTU]网络注册状态1!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(22B)->
+CPIN: READY

OK

OK 返回成功!

SIM卡准备就绪!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(35B)->
OK

SIMCOM INCORPORATED

OK

OK 返回成功!

SIMCOM(26B)->
SIMCOM_SIM7600CE

OK

OK 返回成功!

SIMCOM(34B)->
+GMR: LE11B02SIM7600CE-A

OK

OK 返回成功!

SIMCOM(25B)->
861477030032237

OK

OK 返回成功!

制造商:OK
模块型号:SIMCOM_SIM7600CE
软件版本:LE11B02SIM7600CE-A
模块序列号:861477030032237

SIMCOM(42B)->
+COPS: 0,0,"CHINA MOBILE CMCC",7

OK

OK 返回成功!
运营商信息:CHINA MOBILE CMCC

SIMCOM(22B)->
+CNSMOD: 0,8

OK

OK 返回成功!
网络制式:LTE

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(6B)->
OK

OK 返回成功!

SIMCOM(37B)->
+CSCA: "+8613800100569",145

OK

OK 返回成功!
短信中心号码:13800100569
短信中心号码:13800100569

SIMCOM(21B)->
+CSQ: 20,99

OK

OK 返回成功!
信号强度 <20>!

SIMCOM(41B)->
+CNUM: "","1064838905852",129


OK

OK 返回成功!
本机号码:1064838905852
本机号码:1064838905852

SIMCOM(25B)->
460040389005852

OK

OK 返回成功!
获取CIMI成功:460040389005852


猜你喜欢

转载自blog.csdn.net/cp1300/article/details/79686460
sim