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 底层定义
* 作者: cp1300@139.com
* 创建时间: 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指令接口
* 作者: cp1300@139.com
* 创建时间: 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指令(会添加结束符rn),不会等待响应
* 参数 : pHandle:SIMCOM句柄;pStr:指令字符串
* 返回 : 接口发送状态
* 依赖 : 无
* 作者 : cp1300@139.com
* 时间 : 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 *)"rn", 2); //发送结束符
}
/*************************************************************************************************************************
* 函数 : bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry)
* 功能 : SIMCOM AT 命令通信测试
* 参数 : pHandle:SIMCOM句柄;retry:重试次数
* 返回 : FALSE:通信失败;TRUE:通信成功
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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:超时
* 依赖 : 无
* 作者 : cp1300@139.com
* 时间 : 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("模块进入空闲模式失败!rn");
pHandle->pClearRxData(); //清除接收计数器
return FALSE;
}
pHandle->pDelayMS(100); //延时100ms
SIMCOM_debug("模块进入空闲模式成功!rn");
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
* 依赖 : 无
* 作者 : cp1300@139.com
* 时间 : 2018-03-24
* 最后修改时间 : 2018-03-24
* 说明 : 本函数会在接收缓冲区字符串结束添加' '
本函数不能清除缓冲区
*************************************************************************************************************************/
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] = ' '; //将数据结尾添加结束字符串
}
SIMCOM_debug("rnSIMCOM(%dB)->%srn",len, *pRxBuff); //打印返回信息
if(strstr((const char*)(*pRxBuff), pKeyword) != NULL) //搜索关键字
{
SIMCOM_debug("%s 返回成功!rn",pKeyword);
return AT_RETURN_OK;
}
else if(strstr((const char*)(*pRxBuff), "ERROR") != NULL)
{
SIMCOM_debug("%s 返回错误!rn",pKeyword);
return AT_RETURN_ERROR;
}
else
{
SIMCOM_debug("%s 返回未知!rn",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
* 作者 : cp1300@139.com
* 时间 : 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进制数字位数
*返回 : 转换后的数字
*依赖 : 无
*作者 : cp1300@139.com
*时间 : 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进制数字位数
*返回 : 无
*依赖 : 无
*作者 : cp1300@139.com
*时间 : 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进制数字位数
*返回 : 转换后的数字
*依赖 : 无
*作者 : 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;
}
//SIMCOM_AT.h
/*************************************************************************************************************
* 文件名: SIMCOM_AT.h
* 功能: SIMCOM底层AT指令接口
* 作者: cp1300@139.com
* 创建时间: 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指令(会添加结束符rn),不会等待响应
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指令(会添加结束符rn),不会等待响应
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相关接口
* 作者: cp1300@139.com
* 创建时间: 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
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:失败
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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网络模式!rn");
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMP=13", SIMCOM_DEFAULT_RETRY, 200, "rn设置SIM7000C GSM模式失败!rn") == FALSE) return FALSE; //GSM模式
}break;
case 1://NB模式
{
uart_printf("[DTU]设置NBIOT网络模式!rn");
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMP=38", SIMCOM_DEFAULT_RETRY, 200, "rn设置SIM7000C LTE NB模式失败!rn") == 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, "rn设置SIM7000C CAT NB模式失败!rn") == 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, "rn设置SIM7000C NB 扰码模式失败!rn") == FALSE) return FALSE;
}break;
default:return TRUE; //忽略,无需设置
}
}
return TRUE;
}
/*************************************************************************************************************************
* 函数 : SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle)
* 功能 : 获取SIM卡状态
* 参数 : 无
* 返回 : FALSE:失败;TRUE:成功
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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:成功
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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, "开启透传模式失败!rn"); //开启透传模式
//设置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发送数据缓冲区设置失败!rn"); //发送
}
/*************************************************************************************************************************
* 函数 : bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle)
* 功能 : 初始化SIMCOM模块基本配置(不允许失败)
* 参数 : pHandle:句柄
* 返回 : FALSE:初始化失败;TRUE:初始化成功
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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, "rn关闭Call Ready显示失败!rn");
}break;
default:break;
}
//设置关闭回显
if(SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "rn关闭AT回显模式失败!rn") == FALSE)
{
return FALSE;
}
//设置短消息格式为PDU格式
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CMGF=0", SIMCOM_DEFAULT_RETRY, 110, "rn设置短消息格式为PDU格式失败!rn") == FALSE)
{
uart_printf("rn设置DCD功能模式失败!rn");
return FALSE;
}
//设置DCD功能模式,DCD线只在数据载波存在时为ON。
if(SIMCOM_SetParametersReturnBool(pHandle, "AT&C1", SIMCOM_DEFAULT_RETRY, 110, "rn设置DCD功能模式失败!rn") == FALSE)
{
uart_printf("rn设置DCD功能模式失败!rn");
//return FALSE;
}
//设置 DTR 功能模式,DTR 由ON至OFF:TA在保持当前数据通话的同时,切换至命令模式
if(SIMCOM_SetParametersReturnBool(pHandle, "AT&D1", SIMCOM_DEFAULT_RETRY, 110, "rn设置DTR功能模式失败!rn") == FALSE)
{
uart_printf("rn设置DTR功能模式失败!rn");
//return FALSE;
}
// //使能RI引脚提示
// if(SIM900_SetParametersReturnBool("AT+CFGRI=1", SIMCOM_DEFAULT_RETRY, 11, "rn启动RI引脚提示失败!rn") == FALSE)
// {
// return FALSE;
// }
//设置模块sleep模式使能//发送"AT+CSCLK",启动SLEEP模式;0:关闭;1:手动;2:自动空闲5S钟后休眠
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CSCLK=1", SIMCOM_DEFAULT_RETRY, 110, "rn设置SLEEP失败!rn") == FALSE)
{
return FALSE;
}
//检查卡是否就绪
retry = 8; //重试次数
do
{
if(SIMCOM_GetCPIN(pHandle)==SIM_READY)
{
uart_printf("rnSIM卡准备就绪!rn");
break;
}
else
{
uart_printf("rnSIM卡未准备就绪!rn");
}
SIMCOM_Ready(pHandle); //等待就绪
pHandle->pDelayMS(1000); //失败延时1秒后重试
retry --;
}while(retry);
if(retry == 0)
{
uart_printf("rnSIM卡未准备就绪!rn");
pHandle->pClearRxData(); //清除接收计数器
return FALSE;
}
// //上电删除所有短信
// retry = SIMCOM_DEFAULT_RETRY; //重试次数
// do
// {
// if(SIM900_DelMultiSMS(DelSMS) == TRUE)//删除短信
// {
// //uart_printf("上电删除短信成功!rn");
// break;
// }
// SIM900_Ready(); //等待就绪
// retry --;
// }while(retry);
// if(retry == 0)
// {
// uart_printf("上电删除短信失败!rn");
// 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, "rn关闭新消息自动上报失败!rn") == 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, "rn配置TCP/IP失败!rn") == FALSE)
{
//return FALSE;
}
else break;
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry == 0)
{
uart_printf("rn设置TCP重发次数以及发送延时失败!rn");
pHandle->pClearRxData(); //清除接收计数器
return FALSE;
}
//设置不用等到发送响应
retry = SIMCOM_DEFAULT_RETRY; //重试次数
while(retry)
{
//设置重试次数为3次,并且发送延时为120ms
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPSENDMODE=0", SIMCOM_DEFAULT_RETRY, 110, "rn不用等待发送ACK设置失败!rn") == FALSE)
{
//return FALSE;
}
else break;
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry == 0)
{
uart_printf("rn设置不用等待发送ACK失败!rn");
pHandle->pClearRxData(); //清除接收计数器
}
//显示接收数据长度
retry = SIMCOM_DEFAULT_RETRY; //重试次数
while(retry)
{
//设置重试次数为3次,并且发送延时为120ms
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPHEAD=1", SIMCOM_DEFAULT_RETRY, 110, "rn显示接收数据长度设置失败!rn") == FALSE)
{
//return FALSE;
}
else break;
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry == 0)
{
uart_printf("rn设置显示接收数据长度失败!rn");
pHandle->pClearRxData(); //清除接收计数器
return FALSE;
}
//不显示接收数据IP头
retry = SIMCOM_DEFAULT_RETRY; //重试次数
while(retry)
{
//设置重试次数为3次,并且发送延时为120ms
if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPSRIP=0", SIMCOM_DEFAULT_RETRY, 110, "rn不显示接收数据IP头设置失败!rn") == FALSE)
{
//return FALSE;
}
else break;
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry == 0)
{
uart_printf("rn不显示接收数据IP头失败!rn");
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("rn设置GPRS传输大小失败!rn");
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:成功
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 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("%srn",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] == ' ')) 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] == ' ')) 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("+