stm32_ota/HARDWARE/LTE/EC20/ec20net.c

435 lines
17 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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) ;
}