435 lines
17 KiB
C
435 lines
17 KiB
C
#include "ec20net.h"
|
||
#include "syslib.h"
|
||
|
||
/********************************************************************************
|
||
* @file ec20.c
|
||
* @author 晏诚科技 Mr.Wang
|
||
* @version V1.0.0
|
||
* @date 11-Dec-2018
|
||
* @brief 提供Quectel模块EC20公共硬件驱动程序(激活去激活ContextID链路、EC20串口回调函数)
|
||
******************************************************************************
|
||
* @attention
|
||
* 约定基本名词如下:
|
||
* contextID:链路ID
|
||
* EC20模块链路ID范围1~16,每一个链路ID都会对应一个本地IP; 通道ID范围0~11。
|
||
* 每一个链路ID可以单独相同/不同通信协议(TCP/IP、UDP、HTTP、FTP)。
|
||
* @use:
|
||
* 先调用EC20_Uart_Init()初始化通讯串口,接着调用ActivePDP()激活相关链路,最后通过链路实现
|
||
* TCP\HTTTP\FTP通信
|
||
*******************************************************************************/
|
||
|
||
/*****************************************
|
||
*ec20 NET 驱动内部使用常变量
|
||
****************************************/
|
||
#define NET_CMDPACK_LEN 128 //EC20 NET相关命令字符串的最大长度
|
||
#define APN "CMIOT" //APN,使用的SIM运营商不同对应的APN可能不通
|
||
|
||
/********************************************************
|
||
ec20模块PDP连接相关AT指令处理
|
||
*********************************************************/
|
||
enum eNetCmdNum
|
||
{
|
||
QUERYICCID =0, SETCS =1, QUERYCS =2 , SETPS =3, QUERYPS =4,
|
||
QUERYNETINFO =5, QUERYCSQ =6, COFCONTEXT =7, ACTCONTEXT =8,
|
||
DEACTCONTEXT =9, QUERYCONTEXT =10
|
||
} ; //枚举ec20模块NET相关指令
|
||
|
||
volatile EC20_CMD_DATA_s sNetCmd[11]=
|
||
{
|
||
// cmdNum cmdStr, timeout(100ms), trueStr, trueOffset falseStr revResult rtyNum
|
||
{QUERYICCID, "AT+QCCID\r\n", 5, "+QCCID" , -1, "ERROR", TIMEOUT, 3 },
|
||
{SETCS, "AT+CREG=2\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 },
|
||
{QUERYCS, "AT+CREG?\r\n", 3, "+CREG:" , -1, "ERROR", TIMEOUT, 2 },
|
||
{SETPS, "AT+CGREG=2\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 },
|
||
{QUERYPS, "AT+CGREG?\r\n", 3, "+CGREG:" , -1, "ERROR", TIMEOUT, 2 },
|
||
{QUERYNETINFO, "AT+QNWINFO\r\n", 3, "+QNWINFO:" , -1, "ERROR", TIMEOUT, 1 },
|
||
{QUERYCSQ, "AT+CSQ\r\n", 3, "+CSQ:" , -1, "ERROR", TIMEOUT, 2 },
|
||
{COFCONTEXT, "AT+QICSGP=%d,1,\"%s\",\"\",\"\",1\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //配置TCP context
|
||
{ACTCONTEXT, "AT+QIACT=%d\r\n", (150*10), "OK" , -1, "ERROR", TIMEOUT, 1 },
|
||
{DEACTCONTEXT, "AT+QIDEACT=%d\r\n", (40*10), "OK" , -1, "ERROR", TIMEOUT, 1 },
|
||
{QUERYCONTEXT, "AT+QIACT?\r\n", 3, "+QIACT:", -1, "ERROR", TIMEOUT, 2 }
|
||
} ; //EC20模块NET相关指令的EC20_CMD_DATA_s结构体类型参数
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: static const char *NetCmdNumToString(enum eNetCmdNum result)
|
||
* 功能说明: 输出枚举成员名的字符串指针。
|
||
* 入口参数: eNetCmdNum类型的枚举
|
||
* 出口参数: 为枚举的成员名字符串指针
|
||
**************************************************************************************************/
|
||
static inline const char *NetCmdNumToString(enum eNetCmdNum result)
|
||
{
|
||
switch (result)
|
||
{
|
||
ENUM_CHIP_TYPE_CASE(QUERYICCID)
|
||
ENUM_CHIP_TYPE_CASE(SETCS)
|
||
ENUM_CHIP_TYPE_CASE(QUERYCS)
|
||
ENUM_CHIP_TYPE_CASE(SETPS)
|
||
ENUM_CHIP_TYPE_CASE(QUERYPS)
|
||
ENUM_CHIP_TYPE_CASE(QUERYNETINFO)
|
||
ENUM_CHIP_TYPE_CASE(QUERYCSQ)
|
||
ENUM_CHIP_TYPE_CASE(COFCONTEXT)
|
||
ENUM_CHIP_TYPE_CASE(ACTCONTEXT)
|
||
ENUM_CHIP_TYPE_CASE(DEACTCONTEXT)
|
||
ENUM_CHIP_TYPE_CASE(QUERYCONTEXT)
|
||
}
|
||
ErrorLogPrintf("EC20 无效eNetCmdNum!") ;
|
||
return "无此命令";
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_SendNetCmd( uint8_t cmdNum, char *format,... )
|
||
* 功能说明: MCU串口向EC20发送PDP相关命令
|
||
* 入口参数:
|
||
* @param1 cmdNum EC20_CMD_DATA_s中cmdNum成员命令编号
|
||
* @param2 char *format,... 可变参变量
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_SendNetCmd( uint8_t cmdNum, char *format,... )
|
||
{
|
||
uint8_t revTimes = 0 ;
|
||
RunResult status = TIMEOUT ;
|
||
uint8_t retryTimes = sNetCmd[cmdNum].rtyNum ;
|
||
char *cmdPack = NULL ;
|
||
format = sNetCmd[cmdNum].cmdStr ;
|
||
cmdPack = portMalloc(NET_CMDPACK_LEN*sizeof(uint8_t)) ;
|
||
va_list ap;
|
||
va_start (ap, format);
|
||
int outLen = vsnprintf(cmdPack, NET_CMDPACK_LEN, (const char*)format, ap); //vsprintf (temp, cmd, ap); //到此为止,所有的参数情况已经汇总到temp了
|
||
if((outLen<=0)||( outLen > NET_CMDPACK_LEN)) //vsprintf (temp, cmd, ap); //到此为止,所有的参数情况已经汇总到temp了
|
||
{
|
||
ErrorLogPrintf("%s,%d:cmdPack spillover!",__FILE__, __LINE__) ; //增加NET_CMDPACK_LEN数值
|
||
status = RUNERR ;
|
||
goto netCmdOut ;
|
||
}
|
||
while(retryTimes--)
|
||
{
|
||
Ec20AtBufReset() ;
|
||
revTimes = 0 ;
|
||
//UARTx_Printf(EC20_UART, (uint8_t *)"%s", (uint8_t *)cmdPack);
|
||
UARTx_SendData(EC20_UART, cmdPack, outLen) ; //DMA发送
|
||
while( revTimes++ < sNetCmd[cmdNum].timeout )
|
||
{
|
||
Wait_For_Nms(15);
|
||
sNetCmd[cmdNum].trueOffset = kmp(ec20AtBuf, sNetCmd[cmdNum].trueStr) ;
|
||
if( sNetCmd[cmdNum].trueOffset >= 0)
|
||
{
|
||
status = RUNOK ;
|
||
goto netCmdOut ;
|
||
}
|
||
else if( kmp(ec20AtBuf, sNetCmd[cmdNum].falseStr) >= 0)
|
||
{
|
||
status = RUNERR ;
|
||
goto netCmdOut ;
|
||
}
|
||
}
|
||
Wait_For_Nms( 1000 ) ;
|
||
}
|
||
netCmdOut:portFree(cmdPack) ;
|
||
va_end (ap);
|
||
DebugLogPrintf("%s %s", NetCmdNumToString((enum eNetCmdNum)cmdNum), RunResultToString(status) ) ;
|
||
return (status) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Config_Context( uint8_t contextId )
|
||
* 功能说明: 对contextID进行配置( <APN>, <username>, <password>等信息)
|
||
* 入口参数:
|
||
* @param1 contextId: 取值范围1~16
|
||
* 出口参数:
|
||
* @param1 runStatus RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Config_Context( uint8_t contextId )
|
||
{
|
||
RunResult runStatus = EC20_SendNetCmd(COFCONTEXT, NULL, contextId, APN ) ;
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Act_Context( uint8_t contextId )
|
||
* 功能说明: 激活contextID
|
||
* 入口参数:
|
||
* @param1 contextId: 取值范围1~16
|
||
* 出口参数:
|
||
* @param1 runStatus RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Act_Context( uint8_t contextId )
|
||
{
|
||
RunResult runStatus = EC20_SendNetCmd(ACTCONTEXT, NULL, contextId) ;
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Deact_Context( uint8_t contextId )
|
||
* 功能说明: 去激活contextID
|
||
* 入口参数:
|
||
* @param1 contextId: 取值范围1~16
|
||
* 出口参数:
|
||
* @param1 runStatus RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Deact_Context( uint8_t contextId )
|
||
{
|
||
RunResult runStatus = EC20_SendNetCmd(DEACTCONTEXT, NULL, contextId) ;
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Query_Context( uint8_t contextId, uint8_t *localIp )
|
||
* 功能说明: 查询contextID激活状态,并获取对应本地IP地址
|
||
* 入口参数:
|
||
* @param1 contextId: 取值范围1~16
|
||
* @param2 *localIp: 保存本地IP数据的地址
|
||
* 出口参数:
|
||
* @param1 runStatus RunResult枚举类型变量,返回函数运行结果
|
||
* 注 意:目前只支持contextID小于等于3链路的本地IP获取
|
||
**************************************************************************************************/
|
||
RunResult Query_Context( uint8_t contextId, uint8_t *localIp )
|
||
{
|
||
RunResult runStatus = EC20_SendNetCmd(QUERYCONTEXT, NULL, contextId) ;
|
||
if( RUNOK == runStatus )
|
||
{
|
||
switch(contextId)
|
||
{
|
||
case 1:
|
||
sNetCmd[QUERYCONTEXT].trueOffset = kmp(ec20AtBuf, "+QIACT: 1" );
|
||
break ;
|
||
case 2:
|
||
sNetCmd[QUERYCONTEXT].trueOffset = kmp(ec20AtBuf, "+QIACT: 2" );
|
||
break ;
|
||
case 3:
|
||
sNetCmd[QUERYCONTEXT].trueOffset = kmp(ec20AtBuf, "+QIACT: 3" );
|
||
break ;
|
||
default:
|
||
sNetCmd[QUERYCONTEXT].trueOffset = kmp(ec20AtBuf, "+QIACT: 1" );
|
||
break ;
|
||
}
|
||
if( (sNetCmd[QUERYCONTEXT].trueOffset>=0) &&
|
||
(ec20AtBuf[sNetCmd[QUERYCONTEXT].trueOffset+8] == (0x30+contextId))&&
|
||
(ec20AtBuf[sNetCmd[QUERYCONTEXT].trueOffset+10] == '1')
|
||
)
|
||
{
|
||
runStatus = RUNOK ;
|
||
CopyValues(localIp, (uint8_t*)&ec20AtBuf[sNetCmd[QUERYCONTEXT].trueOffset+15], '"', MAX_IP_LEN) ;
|
||
//AppLogPrintf("ContextId %c 本地IP:%s",contextId, localIp) ;
|
||
}
|
||
else
|
||
{
|
||
runStatus = RUNERR ;
|
||
}
|
||
}
|
||
return (runStatus) ;
|
||
}
|
||
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_QueryCsServiceStatus(void)
|
||
* 功能说明: 注册CS网络
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_QueryCsServiceStatus(void)
|
||
{
|
||
RunResult runStatus = TIMEOUT ;
|
||
int checkCsTimes = 45 ; //45*2S内没有连接到CS Server则表示连接失败《TCP(IP)_AT_Commands》手册P8 要求90S等待 <stat>equals to 1 or 5
|
||
EC20_SendNetCmd(SETCS, NULL ) ;
|
||
while( checkCsTimes-- )
|
||
{
|
||
Wait_For_Nms(100) ;
|
||
runStatus = EC20_SendNetCmd(QUERYCS, NULL ) ;
|
||
if( RUNOK == runStatus )
|
||
{
|
||
if( (sNetCmd[QUERYCS].trueOffset > 0)&&
|
||
((ec20AtBuf[sNetCmd[QUERYCS].trueOffset+9] == 0x31)||(ec20AtBuf[sNetCmd[QUERYCS].trueOffset+9] == 0x35) ))
|
||
{
|
||
runStatus =RUNOK ;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
runStatus =RUNERR ;
|
||
}
|
||
}
|
||
}
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_QueryPsServiceStatus(void)
|
||
* 功能说明: 注册PS网络
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_QueryPsServiceStatus(void)
|
||
{
|
||
RunResult runResult = TIMEOUT ;
|
||
int checkPsTimes = 30 ; //30*2S内没有连接到CS Server则表示连接失败 《TCP(IP)_AT_Commands》手册P8 要求60S等待 <stat>equals to 1 or 5
|
||
EC20_SendNetCmd(SETPS, NULL ) ; //Enable network registration unsolicited result code with location information+CREG: <stat>[,<lac>,<ci>[,<Act>]]
|
||
while( checkPsTimes-- )
|
||
{
|
||
Wait_For_Nms(50) ;
|
||
runResult = EC20_SendNetCmd(QUERYPS, NULL ) ; //查询模块连接PS server的状态
|
||
if( RUNOK == runResult )
|
||
{
|
||
if(
|
||
(sNetCmd[QUERYPS].trueOffset > 0)&&
|
||
((ec20AtBuf[sNetCmd[QUERYPS].trueOffset+10] == 0x31)||(ec20AtBuf[sNetCmd[QUERYPS].trueOffset+10] == 0x35))
|
||
)
|
||
{
|
||
runResult =RUNOK ;
|
||
break ;
|
||
}
|
||
else
|
||
{
|
||
runResult =RUNERR ;
|
||
}
|
||
}
|
||
}
|
||
return (runResult) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_Query_SimIccid(char *simICCID)
|
||
* 功能说明: 查询SIM卡的ICCID编号
|
||
* 入口参数:
|
||
* @param1 *simICCID: 存放ICCID的内存地址
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_Query_SimIccid(char *simICCID)
|
||
{
|
||
memset(simICCID, 0, SIM_ICCID_LEN);
|
||
RunResult runStatus = EC20_SendNetCmd(QUERYICCID, NULL ) ;
|
||
if( RUNOK == runStatus )
|
||
{
|
||
CopyValues((uint8_t*)simICCID, (uint8_t*)&ec20AtBuf[(sNetCmd[QUERYICCID].trueOffset+8)], 0x0D, SIM_ICCID_LEN) ;
|
||
}
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: char* EC20_Query_NetInfo(void)
|
||
* 功能说明: 查询网络CSQ(信号质量)
|
||
* 出口参数:
|
||
* @param1 网络信息数据存放地址
|
||
**************************************************************************************************/
|
||
char* EC20_Query_NetInfo(void)
|
||
{
|
||
char *end ;
|
||
RunResult runResult = EC20_SendNetCmd(QUERYNETINFO, NULL ) ;
|
||
if( RUNOK == runResult )
|
||
{
|
||
//start = strchr( (const char*)ec20ReceBuffer, ':' ) ;
|
||
end = strchr((const char*)&ec20AtBuf[sNetCmd[QUERYNETINFO].trueOffset], 0x0D) ;
|
||
*end = 0x00 ; //添加字符串结尾
|
||
return (char*)&ec20AtBuf[sNetCmd[QUERYNETINFO].trueOffset+10] ;
|
||
}
|
||
else
|
||
{
|
||
return "获取网络信息失败!" ;
|
||
}
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_Query_CSQ(char *csq)
|
||
* 功能说明: 查询网络CSQ(信号质量)
|
||
* 入口参数:
|
||
* @param1 *csq 存放csq的内存地址
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_Query_CSQ(char *csq)
|
||
{
|
||
memset(csq, 0, CSQ_LEN+1);
|
||
RunResult runResult = EC20_SendNetCmd(QUERYCSQ, NULL ) ;
|
||
if( RUNOK == runResult )
|
||
{
|
||
CopyValues((uint8_t*)csq, (uint8_t*)&ec20AtBuf[sNetCmd[QUERYCSQ].trueOffset+6], ',', SIM_ICCID_LEN) ;
|
||
}
|
||
return (runResult) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_Net_Reg(char *errInfo, uint8_t errLen)
|
||
* 功能说明: 模块注册到CS\PS服务器
|
||
* 入口参数:
|
||
* @param1 *errInfo 存放错误信息
|
||
* @param2 errLen 错误信息的长度
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_Net_Reg(char *errInfo, uint8_t errLen)
|
||
{
|
||
RunResult runResult = TIMEOUT ;
|
||
runResult = EC20_Query_SimIccid(sEc20Param.simICCID) ;
|
||
if( RUNOK != runResult )
|
||
{
|
||
snprintf(errInfo, errLen, "请插入SIM卡") ;
|
||
ErrorLogPrintf("未检测到SIM卡") ;
|
||
return (RUNERR) ;
|
||
}
|
||
AppLogPrintf("Sim卡ICCID:%.*s", SIM_ICCID_LEN, sEc20Param.simICCID) ;
|
||
|
||
runResult = EC20_QueryCsServiceStatus() ;
|
||
if( RUNOK != runResult )
|
||
{
|
||
snprintf(errInfo, errLen, "SIM卡欠费") ;
|
||
ErrorLogPrintf("SIM欠费无法注册上网络") ;
|
||
return (RUNERR) ;
|
||
}
|
||
EC20_QueryPsServiceStatus() ;
|
||
AppLogPrintf("网络信息:%s", EC20_Query_NetInfo()) ;
|
||
EC20_Query_CSQ(sEc20Param.csq) ;
|
||
snprintf(errInfo, errLen, "信号质量:%s", sEc20Param.csq) ;
|
||
AppLogPrintf("LTE CSQ:%.*s", CSQ_LEN, sEc20Param.csq) ;
|
||
return (runResult) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult ActivePDP( uint8_t contextId, uint8_t *localIp)
|
||
* 功能说明: 配置、去激活、激活、查询PDP
|
||
* 入口参数:
|
||
* @param1 contextId: 取值范围1~16
|
||
* @param2 *localIp: 保存本地IP数据的地址
|
||
* 出口参数:
|
||
* @param1 runStatus RunResult枚举类型变量,返回函数运行结果
|
||
* 异常处理:去激活如果超时直接返回TIMEOUT。否则激活失败执行重复去激活再激活流程三次
|
||
**************************************************************************************************/
|
||
RunResult ActivePDP( uint8_t contextId, uint8_t *localIp)
|
||
{
|
||
RunResult runResult = TIMEOUT ;
|
||
Config_Context(contextId) ; //配置PDP VPN等信息
|
||
runResult = Act_Context(contextId) ; //激活PDP
|
||
if( runResult == RUNOK )
|
||
{
|
||
Query_Context(contextId, localIp) ; //激活成功->获取PDP的IP
|
||
}
|
||
return (runResult) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult DeactivePDP( uint8_t contextId, uint8_t *localIp)
|
||
* 功能说明: 去激活PDP链路
|
||
* 入口参数:
|
||
* @param1 contextId: 取值范围1~16
|
||
* 出口参数:
|
||
* @param1 runStatus RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult DeactivePDP( uint8_t contextId)
|
||
{
|
||
RunResult runResult = TIMEOUT ;
|
||
runResult = Deact_Context(contextId) ;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|