stm32_ota/HARDWARE/LTE/EC20/ec20tcp.c

348 lines
13 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 "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 *channalChannalP_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 *channalChannalP_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 connectIdTCP连接通道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 connectIdTCP连接通道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 connectIdTCP连接通道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 ;
}