348 lines
13 KiB
C
348 lines
13 KiB
C
#include "ec20tcp.h"
|
||
#include <stdlib.h>
|
||
#include "syslib.h" //#define STR2(R) STR1(R)
|
||
|
||
/********************************************************************************
|
||
* @file ec20tcp.c
|
||
* @author 晏诚科技 Mr.Wang
|
||
* @version V1.0.0
|
||
* @date 11-Dec-2018
|
||
* @brief 提供Quectel模块EC20关于TCP/IP硬件驱动程序
|
||
******************************************************************************
|
||
* @attention
|
||
* 约定基本名词如下:
|
||
* contextID:链路ID connetcID:通道ID channal:连接通道
|
||
* EC20模块链路ID范围1~16,每一个链路ID都会对应一个本地IP; 通道ID范围0~11。
|
||
* 每一个链路ID可以有12个通道ID。
|
||
* 本驱动强制规定,TCP/IP协议只用一个链路1D(即contextID=1)用于TCP链路。
|
||
* 通过不同的通道ID我们可以多台不同IP和端口的服务器。
|
||
* 结构体ChannalP_s封装了每一路连接通道的参数
|
||
* @use:
|
||
* 先调用Tcp_PDP_Init()初始化TCP链路,接着调用Tcp_Channal_Init打开Socket,最后通过Tcp_SendData发送TCP数据
|
||
*******************************************************************************/
|
||
|
||
/*****************************************
|
||
*内部使用的常变量定义
|
||
****************************************/
|
||
#define TCP_CMDPACK_LEN 128 //EC20 TCP相关命令字符串的最大长度
|
||
|
||
|
||
/********************************************************
|
||
ec20模块TCP/IP相关AT指令处理
|
||
*********************************************************/
|
||
enum eTcpCmdNum
|
||
{ OPENSOCKET =0, CLOSESOCKET =1, QUERYSOCKET =2,
|
||
TCPSENDCMD =3, TCPSENDBUF =4
|
||
} ; //枚举ec20模块TCP相关指令
|
||
|
||
volatile EC20_CMD_DATA_s sTcpCmd[5]=
|
||
{
|
||
// cmdNum cmdStr, timeout(100ms), trueStr, trueOffset falseStr revResult rtyNum
|
||
{OPENSOCKET, "AT+QIOPEN="STR2(TCP_CONTEXTID)",%d,\"TCP\",\"%s\",%d,%d,1\r\n", (20*10), "+QIOPEN:", -1,"ERROR", TIMEOUT, 1 }, //打开socket 手册回码等待150S
|
||
{CLOSESOCKET, "AT+QICLOSE=%d,10\r\n" , (10*10), "OK" , -1, "ERROR", TIMEOUT, 2 }, //关闭socket
|
||
{QUERYSOCKET, "AT+QISTATE=1,%d\r\n" , 5, "+QISTATE:" , -1, "ERROR", TIMEOUT, 2 }, //查询socket状态
|
||
{TCPSENDCMD, "AT+QISEND=%d,%d\r\n" , (2*10), ">" , -1, "ERROR", TIMEOUT, 1 }, //通过socket发送数据
|
||
{TCPSENDBUF, "%s" , (2*10), "SEND OK" , -1, "ERROR", TIMEOUT, 1 } //SOCKET发送负载数据
|
||
} ; //EC20模块TCP相关指令的EC20_CMD_DATA_s结构体类型参数
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: static const char *TcpCmdNumToString(enum eTcpCmdNum result)
|
||
* 功能说明: 输出枚举成员名的字符串指针。
|
||
* 入口参数: eTcpCmdNum类型的枚举
|
||
* 出口参数: 为枚举的成员名字符串指针
|
||
**************************************************************************************************/
|
||
static inline const char *TcpCmdNumToString(enum eTcpCmdNum result)
|
||
{
|
||
switch (result)
|
||
{
|
||
ENUM_CHIP_TYPE_CASE(OPENSOCKET)
|
||
ENUM_CHIP_TYPE_CASE(CLOSESOCKET)
|
||
ENUM_CHIP_TYPE_CASE(QUERYSOCKET)
|
||
ENUM_CHIP_TYPE_CASE(TCPSENDCMD)
|
||
ENUM_CHIP_TYPE_CASE(TCPSENDBUF)
|
||
}
|
||
return "无此命令";
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Tcp_PDP_Init( void )
|
||
* 功能说明: 初始化TCP链路
|
||
* 出口参数:
|
||
* @param1 runResult RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Tcp_PDP_Init( void )
|
||
{
|
||
RunResult runResult = TIMEOUT ;
|
||
uint8_t *tcpLocalIp = portMalloc(MAX_IP_LEN) ;
|
||
runResult = Query_Context( TCP_CONTEXTID, tcpLocalIp ) ; //查询TCP_CONTEXTID是否激活
|
||
if( RUNOK == runResult ) /*TCP_CONTEXTID已激活*/ //去激活->再次激活
|
||
{
|
||
// runResult = Deact_Context(TCP_CONTEXTID) ;
|
||
// if( RUNOK != runResult ) /*TCP_CONTEXTID去激活失败*/ //直接返回错误
|
||
// {
|
||
// return RUNERR ;
|
||
// }
|
||
return RUNOK ;
|
||
}
|
||
runResult = ActivePDP(TCP_CONTEXTID, tcpLocalIp) ;
|
||
if( RUNOK == runResult )
|
||
{
|
||
AppLogPrintf("TCP本地IP:%s", tcpLocalIp) ;
|
||
}
|
||
portFree(tcpLocalIp) ;
|
||
return(runResult) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Tcp_Channal_Init( ChannalP_s *channal )
|
||
* 功能说明: TCP连接通道初始化
|
||
* 入口参数:
|
||
* @param1 *channal:ChannalP_s结构体变量,存放TCP连接通道相关参数
|
||
* 出口参数:
|
||
* @param1 runResult RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Tcp_Channal_Init( ChannalP_s *channal )
|
||
{
|
||
RunResult runResult = TIMEOUT ;
|
||
runResult = Close_Socket(channal->connectId) ;
|
||
if( runResult != RUNOK ) //关闭SOCKET失败直接返回失败状态
|
||
return(runResult) ;
|
||
runResult = Open_Socket(channal->connectId, channal->serverIP, channal->serverPort, channal->localPort) ;
|
||
if( RUNOK == runResult )
|
||
Query_Socket(channal->connectId) ;
|
||
return(runResult) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Tcp_SendData(ChannalP_s *channal, uint8_t *sendBuf, uint16_t sendLen)
|
||
* 功能说明: 通过连接通道channal将长度为sendLen的sendBuf缓冲区数据发送到服务器
|
||
* 入口参数:
|
||
* @param1 *channal:ChannalP_s结构体变量,存放TCP连接通道相关参数
|
||
* @param2 *sendBuf:发送数据缓冲区地址
|
||
* @param3 sendLen:发送数据的长度
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Tcp_SendData(ChannalP_s *channal, uint8_t *sendBuf, uint16_t sendLen)
|
||
{
|
||
if( sendLen <=0 )
|
||
{
|
||
return (RUNOK) ;
|
||
}
|
||
uint8_t times = 0, enableSendData = 0 ;
|
||
uint16_t revTimes = 0 ;
|
||
RunResult runStatus = TIMEOUT ;
|
||
Ec20AtBufReset() ;
|
||
UARTx_SendString(EC20_UART, (uint8_t*)sTcpCmd[TCPSENDCMD].cmdStr, channal->connectId, sendLen );
|
||
while( times++ < 70 )
|
||
{
|
||
Wait_For_Nms(20) ;
|
||
if( NULL != strchr((const char*)ec20AtBuf, '>') )
|
||
{
|
||
enableSendData = 1 ;
|
||
break ;
|
||
}
|
||
}
|
||
|
||
if( enableSendData == 1 ) //已经成功收到‘>’,串口可以发送TCP需要上传的数据
|
||
{
|
||
UARTx_SendData(EC20_UART, (char*)sendBuf, sendLen) ;
|
||
while( revTimes++ < sTcpCmd[TCPSENDBUF].timeout )
|
||
{
|
||
Wait_For_Nms(5);
|
||
sTcpCmd[TCPSENDBUF].trueOffset = kmp(ec20AtBuf, sTcpCmd[TCPSENDBUF].trueStr) ;
|
||
if( sTcpCmd[TCPSENDBUF].trueOffset >= 0)
|
||
{
|
||
runStatus = RUNOK ;
|
||
DebugLogPrintf("%s %s", TcpCmdNumToString(TCPSENDBUF), RunResultToString(runStatus)) ;
|
||
break ;
|
||
}
|
||
else if( kmp(ec20AtBuf, sTcpCmd[TCPSENDBUF].falseStr) >= 0)
|
||
{
|
||
runStatus = RUNERR ;
|
||
ErrorLogPrintf("%s %s %s", TcpCmdNumToString(TCPSENDBUF), RunResultToString(runStatus), ec20AtBuf ) ;
|
||
break ;
|
||
}
|
||
}
|
||
//EC20_SendTcpCmd( TCPSENDBUF, NULL ) ;
|
||
}
|
||
else
|
||
{
|
||
ErrorLogPrintf("%s %s %s %s", TcpCmdNumToString(TCPSENDCMD), RunResultToString(runStatus), "未收到\">\"", ec20AtBuf ) ;
|
||
}
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult EC20_SendTcpCmd( uint8_t cmdNum, char *format,... )
|
||
* 功能说明: MCU串口向EC20发送Tcp相关命令
|
||
* 入口参数:
|
||
* @param1 cmdNum EC20_CMD_DATA_s中cmdNum成员命令编号
|
||
* @param2 char *format,... 可变参变量
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult EC20_SendTcpCmd( uint8_t cmdNum, char *format,... )
|
||
{
|
||
uint8_t revTimes = 0 ;
|
||
RunResult status = TIMEOUT ;
|
||
uint8_t retryTimes = sTcpCmd[cmdNum].rtyNum ;
|
||
char *cmdPack = NULL ;
|
||
format = sTcpCmd[cmdNum].cmdStr ;
|
||
cmdPack = portMalloc(TCP_CMDPACK_LEN*sizeof(uint8_t)) ;
|
||
va_list ap;
|
||
va_start (ap, format);
|
||
int outLen = vsnprintf(cmdPack, TCP_CMDPACK_LEN, (const char*)format, ap); //vsprintf (temp, cmd, ap); //到此为止,所有的参数情况已经汇总到temp了
|
||
if((outLen<=0)||( outLen > TCP_CMDPACK_LEN))
|
||
{
|
||
ErrorLogPrintf("Tcp cmdPack 溢出!--增加TCP_CMDPACK_LEN数值。") ;
|
||
status = RUNERR ;
|
||
goto tcpCmdOut ;
|
||
}
|
||
while(retryTimes--)
|
||
{
|
||
Ec20AtBufReset() ;
|
||
revTimes = 0 ;
|
||
UARTx_SendData(EC20_UART, cmdPack, outLen ) ; //DMA发送
|
||
while( revTimes++ < sTcpCmd[cmdNum].timeout )
|
||
{
|
||
Wait_For_Nms(100) ;
|
||
sTcpCmd[cmdNum].trueOffset = kmp(ec20AtBuf, sTcpCmd[cmdNum].trueStr) ;
|
||
if( sTcpCmd[cmdNum].trueOffset >= 0)
|
||
{
|
||
status = RUNOK ;
|
||
goto tcpCmdOut ;
|
||
}
|
||
else if( kmp(ec20AtBuf, sTcpCmd[cmdNum].falseStr) >= 0)
|
||
{
|
||
status = RUNERR ;
|
||
goto tcpCmdOut ;
|
||
}
|
||
}
|
||
Wait_For_Nms( 1000 ) ;
|
||
}
|
||
tcpCmdOut:
|
||
portFree(cmdPack) ;
|
||
va_end(ap) ;
|
||
DebugLogPrintf("%s %s", TcpCmdNumToString((enum eTcpCmdNum)cmdNum), RunResultToString(status) ) ;
|
||
return (status) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Open_Socket(uint8_t connectId, uint8_t *serverIp, uint16_t serverPortNum, uint16_t localPortNum )
|
||
* 功能说明: 打开TCP Socket
|
||
* 入口参数:
|
||
* @param1 connectId:TCP连接通道ID
|
||
* @param2 *serverIp:存放服务器IP的指针
|
||
* @param3 serverPortNum:服务器端口号
|
||
* @param4 localPortNum:模块本地端口号
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Open_Socket(uint8_t connectId, uint8_t *serverIp, uint16_t serverPortNum, uint16_t localPortNum )
|
||
{
|
||
RunResult runStatus = TIMEOUT ;
|
||
runStatus = EC20_SendTcpCmd(OPENSOCKET, NULL, connectId, serverIp, serverPortNum, localPortNum ) ;
|
||
if( RUNOK == runStatus )
|
||
{
|
||
if( (ec20AtBuf[sTcpCmd[OPENSOCKET].trueOffset+9] == (0X30+connectId)) &&
|
||
(ec20AtBuf[sTcpCmd[OPENSOCKET].trueOffset+11] == '0')
|
||
)
|
||
{
|
||
runStatus = RUNOK ;
|
||
}
|
||
else
|
||
{
|
||
runStatus = RUNERR ;
|
||
}
|
||
}
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Close_Socket(uint8_t connectId)
|
||
* 功能说明: 关闭TCP Socket
|
||
* 入口参数:
|
||
* @param1 connectId:TCP连接通道ID
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Close_Socket(uint8_t connectId)
|
||
{
|
||
RunResult runStatus = TIMEOUT ;
|
||
runStatus = EC20_SendTcpCmd(CLOSESOCKET, NULL, connectId ) ;
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: RunResult Query_Socket(uint8_t connectId)
|
||
* 功能说明: 查询TCP Socket状态
|
||
* 入口参数:
|
||
* @param1 connectId:TCP连接通道ID
|
||
* 出口参数:
|
||
* @param1 status RunResult枚举类型变量,返回函数运行结果
|
||
**************************************************************************************************/
|
||
RunResult Query_Socket(uint8_t connectId)
|
||
{
|
||
RunResult runStatus = TIMEOUT ;
|
||
runStatus = EC20_SendTcpCmd(QUERYSOCKET, NULL, connectId ) ;
|
||
if( RUNOK == runStatus )
|
||
{
|
||
uint8_t serverPort[5] = {0} ;
|
||
ChannalP_s *sReturnP ;
|
||
sReturnP = portMalloc(sizeof(ChannalP_s)) ;
|
||
sReturnP->connectId = ec20AtBuf[sTcpCmd[QUERYSOCKET].trueOffset+10] ;
|
||
CopyValues(sReturnP->serverIP, (uint8_t*)&ec20AtBuf[sTcpCmd[QUERYSOCKET].trueOffset+19], ',', MAX_IP_LEN) ;
|
||
CopyValues(serverPort, (uint8_t*)&ec20AtBuf[sTcpCmd[QUERYSOCKET].trueOffset+20+strlen((const char*)sReturnP->serverIP)], ',', 5) ;
|
||
DebugLogPrintf("TCP Channal:%c 。 服务器IP:%s。 服务器端口:%s", sReturnP->connectId, sReturnP->serverIP, serverPort) ;
|
||
portFree(sReturnP) ;
|
||
}
|
||
return (runStatus) ;
|
||
}
|
||
|
||
/**************************************************************************************************
|
||
* 名 称: TcpUrcType TcpUrcHandle( char *recvBuf, uint16_t recvLen )
|
||
* 功能说明: TCP/IP协议中模块返回的一写URC分类处理
|
||
* 入口参数:
|
||
* @param1 recvBuf 接收的数据
|
||
* @param2 recvLen 接收的数据长度
|
||
* 出口参数:
|
||
* @param TcpUrcType TcpUrcType枚举类型变量,返回URC类型
|
||
**************************************************************************************************/
|
||
TcpUrcType TcpUrcHandle( char *recvBuf, uint16_t recvLen )
|
||
{
|
||
TcpUrcType urcType = UNKNOWM ;
|
||
if( kmp(recvBuf, "+QIURC: \"closed\"") > 0 )
|
||
{
|
||
urcType = CLOSED ;
|
||
}
|
||
else if( kmp(recvBuf, "+QIURC: \"pdpdeact\"") > 0 )
|
||
{
|
||
urcType = PDPDEACT ;
|
||
}
|
||
else if( kmp(recvBuf, "+QIURC: \"incoming\"") > 0 )
|
||
{
|
||
urcType = INCOMING_FULL ;
|
||
}
|
||
else if( kmp(recvBuf, "+QIURC: \"incoming full\"") > 0 )
|
||
{
|
||
urcType = INCOMING_CONT ;
|
||
}
|
||
else
|
||
{
|
||
urcType = UNKNOWM ;
|
||
}
|
||
return urcType ;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|