stm32_ota/HARDWARE/LTE/EC20/ec20http.c

343 lines
14 KiB
C
Raw 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 "ec20http.h"
#include <stdlib.h>
#include "syslib.h" //#define STR2(R) STR1(R)
/********************************************************************************
* @file ec20http.c
* @author 晏诚科技 Mr.Wang
* @version V1.0.0
* @date 11-Dec-2018
* @brief 提供Quectel模块EC20关于HTTP驱动程序
******************************************************************************
* @attention
*
* 约定基本名词如下:
* contextID:链路ID connetcID通道ID channal连接通道
* EC20模块链路ID范围1~16每一个链路ID都会对应一个本地IP 通道ID范围0~11。
* 每一个链路ID可以有12个通道ID。
* 本驱动强制规定HTTP协议只用一个链路1D即contextID=2用于HTTP链路。
* @use
* 先调用Http_Init()初始化HTTP链路等参数接着调用Send_Post发送POST请求最后通过Http_Read读取接收到的POST数据
*******************************************************************************/
/*****************************************
*内部常量
****************************************/
#define HTTP_CMDPACK_LEN 300 //EC20 HTTP相关命令字符串的最大长度
#define HTTP_CONTEXTID 2 //1~16 本驱动强制规定HTTP协议只用一个链路1D即contextID=2用于HTTP链路
/********************************************************
ec20模块TCP/IP相关AT指令处理
*********************************************************/
enum eHttpCmdNum
{
HTTPCONTEST =0, ENREQHEADER =1, CLOSETIME =2,
BODYTYPE =3, SETURLCMD =4, HTTPURL =5,
POSTREQCMD =6, POSTREQBUF =7, HTTPREAD =8
} ; //枚举ec20模块http相关指令
volatile EC20_CMD_DATA_s sHttpCmd[9]=
{
// cmdNum cmdStr, timeout(100ms), trueStr, trueOffset, falseStr revResult rtyNum
{HTTPCONTEST, "AT+QHTTPCFG=\"contextid\","STR2(HTTP_CONTEXTID)"\r\n", 5, "OK", -1, "ERROR", TIMEOUT, 2 }, //配置http使用的contextid
{ENREQHEADER, "AT+QHTTPCFG=\"requestheader\",1\r\n" , 5, "OK" , -1, "ERROR", TIMEOUT, 2 }, //配置是否输出接收头数据
{CLOSETIME, "AT+QHTTPCFG=\"closewaittime\",100\r\n" , 5, "OK" , -1, "ERROR", TIMEOUT, 2 }, //配置http请求超时时间
{BODYTYPE, "AT+QHTTPCFG=\"contenttype\",1\r\n" , 5, "OK" , -1, "ERROR", TIMEOUT, 2 }, //设置content_type为 1 text/plain类型
{SETURLCMD, "AT+QHTTPURL=%d,60\r\n" , (60*10), "CONNECT", -1, "ERROR", TIMEOUT, 1 }, //设置URL
{HTTPURL, "%s" , 5, "OK" , -1, "ERROR", TIMEOUT, 2 }, //发起post请求
{POSTREQCMD, "AT+QHTTPPOST=%d,6,6\r\n" , (6*10), "CONNECT", -1, "ERROR", TIMEOUT, 1 },
{POSTREQBUF, "%s" , (8*10), "+QHTTPPOST: 0,200", -1, "ERROR", TIMEOUT, 1 }, //读取http返回的数据
//{HTTPREAD, "AT+QHTTPREAD=6\r\n" , (6*10), "OK", -1, "ERROR", TIMEOUT, 2 }
{HTTPREAD, "AT+QHTTPREAD=6\r\n" , (10*10), "+QHTTPREAD", -1, "ERROR", TIMEOUT, 1 }
} ; //EC20模块HTTP相关指令的EC20_CMD_DATA_s结构体类型参数
/**************************************************************************************************
* 名 称: static const char *HttpCmdNumToString(enum eHttpCmdNum result)
* 功能说明: 输出枚举成员名的字符串指针。
* 入口参数: eHttpCmdNum类型的枚举
* 出口参数: 为枚举的成员名字符串指针
**************************************************************************************************/
static inline const char *HttpCmdNumToString(enum eHttpCmdNum result)
{
switch (result)
{
ENUM_CHIP_TYPE_CASE(HTTPCONTEST)
ENUM_CHIP_TYPE_CASE(ENREQHEADER)
ENUM_CHIP_TYPE_CASE(CLOSETIME)
ENUM_CHIP_TYPE_CASE(BODYTYPE)
ENUM_CHIP_TYPE_CASE(SETURLCMD)
ENUM_CHIP_TYPE_CASE(HTTPURL)
ENUM_CHIP_TYPE_CASE(POSTREQCMD)
ENUM_CHIP_TYPE_CASE(POSTREQBUF)
ENUM_CHIP_TYPE_CASE(HTTPREAD)
}
return "无此命令";
}
/**************************************************************************************************
* 名 称: RunResult EC20_SendHttpCmd( uint8_t cmdNum, char *format,... )
* 功能说明: MCU串口向EC20发送http相关命令
* 入口参数:
* @param1 cmdNum EC20_CMD_DATA_s中cmdNum成员命令编号
* @param2 char *format,... 可变参变量
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_SendHttpCmd( uint8_t cmdNum, char *format,... )
{
uint8_t revTimes = 0 ;
RunResult status = TIMEOUT ;
uint8_t retryTimes = sHttpCmd[cmdNum].rtyNum ;
char *cmdPack = NULL ;
format = sHttpCmd[cmdNum].cmdStr ;
cmdPack = portMalloc(HTTP_CMDPACK_LEN*sizeof(uint8_t)) ;
va_list ap;
va_start (ap, format);
int outLen = vsnprintf(cmdPack, HTTP_CMDPACK_LEN, (const char*)format, ap) ;
if((outLen<=0)||( outLen > HTTP_CMDPACK_LEN)) //vsprintf (temp, cmd, ap); //到此为止所有的参数情况已经汇总到temp了
{
ErrorLogPrintf("Http cmdPack 溢出!--增加HTTP_CMDPACK_LEN数值。") ;
goto httpCmdOut ;
}
while(retryTimes--)
{
Ec20AtBufReset() ;
revTimes = 0 ;
//UARTx_Printf(EC20_UART, (uint8_t *)"%s", (uint8_t *)cmdPack);
UARTx_SendData(EC20_UART, cmdPack, outLen) ; //DMA发送
while( revTimes++ < (sHttpCmd[cmdNum].timeout*2) )
{
Wait_For_Nms(50);
sHttpCmd[cmdNum].trueOffset = kmp(ec20AtBuf, sHttpCmd[cmdNum].trueStr) ;
if( sHttpCmd[cmdNum].trueOffset >= 0)
{
status = RUNOK ;
goto httpCmdOut ;
}
else if( kmp(ec20AtBuf, sHttpCmd[cmdNum].falseStr) >= 0)
{
status = RUNERR ;
goto httpCmdOut ;
}
}
Wait_For_Nms( 1000 ) ;
}
httpCmdOut:portFree(cmdPack) ;
va_end (ap);
DebugLogPrintf("%s %s", HttpCmdNumToString((enum eHttpCmdNum)cmdNum), RunResultToString(status) ) ;
return (status) ;
}
/**************************************************************************************************
* 名 称: RunResult Http_Config(void)
* 功能说明: http相关的基本配置包括请求头、超时时间、请求的数据类型等
**************************************************************************************************/
RunResult Http_Config(void)
{
RunResult runStatus = TIMEOUT ;
runStatus = EC20_SendHttpCmd(HTTPCONTEST, NULL ) ;
if( RUNOK != runStatus )
{
return (runStatus) ;
}
runStatus = EC20_SendHttpCmd(ENREQHEADER, NULL ) ;
if( RUNOK != runStatus )
{
return (runStatus) ;
}
if( (kmp(sEc20Param.ec20SoftVer , "EC20CEFDKGR06A03M2G") < 0) ) //EC20该版本需要增加下面指令
{
runStatus = EC20_SendHttpCmd(CLOSETIME, NULL ) ; //ec20SoftVer
if( RUNOK != runStatus )
{
return (runStatus) ;
}
}
// runStatus = EC20_SendHttpCmd(CLOSETIME, NULL ) ; //ec20SoftVer
// if( RUNOK != runStatus )
// {
// return (runStatus) ;
// }
runStatus = EC20_SendHttpCmd(BODYTYPE, NULL ) ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult Http_PDP_Init(void)
* 功能说明: http协议的链路ID contextid配置强制设置为HTTP_CONTEXTID
**************************************************************************************************/
RunResult Http_PDP_Init( void )
{
RunResult runResult = TIMEOUT ;
uint8_t *httpLocalIp = portMalloc(MAX_IP_LEN) ;
runResult = Query_Context( HTTP_CONTEXTID, httpLocalIp ) ; //查询HTTP_CONTEXTID是否激活
if( RUNOK == runResult ) /*HTTP_CONTEXTID已激活*/ //去激活->再次激活
{
// runResult = Deact_Context(HTTP_CONTEXTID) ;
// if( RUNOK != runResult ) /*HTTP_CONTEXTID去激活失败*/ //直接返回错误
// {
// return RUNERR ;
// }
return RUNOK ;
}
runResult = ActivePDP(HTTP_CONTEXTID, httpLocalIp) ;
if( RUNOK == runResult )
{
AppLogPrintf("HTTP本地IP%s", httpLocalIp) ;
}
portFree(httpLocalIp) ;
return(runResult) ;
}
/**************************************************************************************************
* 名 称: RunResult Set_HttpURL(char *host)
* 功能说明: 设置http请求的主机地址
* 入口参数:
* @param1 *host 主机地址
**************************************************************************************************/
RunResult Set_HttpURL(char *host)
{
RunResult runStatus = TIMEOUT ;
int hostLen = strlen(host) ;
char *url = portMalloc(10+hostLen) ;
snprintf(url, 10+hostLen, "%s%s", "http://", host) ;
runStatus = EC20_SendHttpCmd(SETURLCMD, NULL, strlen((const char*)url) ) ;
if( RUNOK == runStatus )
{
runStatus = EC20_SendHttpCmd(HTTPURL, NULL, url ) ;
if( RUNOK == runStatus )
{
AppLogPrintf("POST URL:%s.", url) ;
}
}
portFree(url) ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult Http_PDP_Init(void)
* 功能说明: http初始化包括基本参数、和链路初始化
**************************************************************************************************/
RunResult Http_Init( void )
{
RunResult runStatus = TIMEOUT ;
if( RUNOK != Http_Config() )
return (runStatus) ;
runStatus = Http_PDP_Init() ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult Send_Post( POSTP_s *psHttpP, char* postBody )
* 功能说明: http发送post请求
* 入口参数:
* @param1 *psHttpP POSTP_s类型数据指针包含http请求的参数
* @param2 *postBody post请求的负载数据
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
* 如果返回RUNOK说明已经请求成功接下来就可以调用Http_Read函数读取存储在缓冲区内的数据了
**************************************************************************************************/
RunResult Send_Post( POSTP_s *psHttpP, char* postBody )
{
int outLen = 0 ;
RunResult runStatus = TIMEOUT ;
Set_HttpURL(psHttpP->host) ; //设置HTTP请求URL
char *headerBodyBuf = portMalloc(HTTP_CMDPACK_LEN) ;
outLen = snprintf(headerBodyBuf, HTTP_CMDPACK_LEN, psHttpP->postBuf, psHttpP->host, psHttpP->httpPort, psHttpP->host,strlen(postBody), postBody ) ;
if((outLen<=0)||(outLen>HTTP_CMDPACK_LEN))
{
runStatus = RUNERR ;
ErrorLogPrintf("headerBodyBuf 溢出!--增加HTTP_CMDPACK_LEN数值。") ;
goto PostOut ;
}
runStatus = EC20_SendHttpCmd(POSTREQCMD, NULL, outLen ) ; //发送POST请求命令
if( RUNOK != runStatus )
{
goto PostOut ;
}
runStatus = EC20_SendHttpCmd(POSTREQBUF, NULL, headerBodyBuf ) ;//发送POST请求数据 //DebugLogPrintf("%s",headerBodyBuf) ;
PostOut:
portFree(headerBodyBuf) ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult Http_Read( void )
* 功能说明: 读取http返回的数据, 将读取到的http数据存于ec20HttpBuf中
**************************************************************************************************/
RunResult Http_Read( void )
{
uint8_t revTimes = 0 ;
int errCode = 0 ;
RunResult runStatus = TIMEOUT ;
Ec20HttpBufReset() ; //ec20HttpBuf清空 准备接下来接收数据
httpDataMode = true ; //将EC20_UART串口接收模式改为接收http数据模式
UARTx_SendData(EC20_UART, sHttpCmd[HTTPREAD].cmdStr, strlen((const char*)sHttpCmd[HTTPREAD].cmdStr) ) ; //DMA发送
while( revTimes++ < (sHttpCmd[HTTPREAD].timeout) )
{
Wait_For_Nms(100) ; //等待100ms
sHttpCmd[HTTPREAD].trueOffset = kmp(ec20HttpBuf, sHttpCmd[HTTPREAD].trueStr) ; //在ec20HttpBuf缓冲区中查找 sHttpCmd[HTTPREAD].trueStr字串
if( sHttpCmd[HTTPREAD].trueOffset >= 0)
{
if( ec20HttpBuf[sHttpCmd[HTTPREAD].trueOffset+12] == 0x30 ) /*"AT+QHTTPREAD"指令返回“+QHTTPREAD: 0” 表示请求成功*/
{
errCode = 0 ;
runStatus = RUNOK ;
}
else /*"AT+QHTTPREAD"指令返回“+QHTTPREAD: <err>” 表示请求出错*/
{
errCode = (ec20HttpBuf[sHttpCmd[HTTPREAD].trueOffset+1]-0x30)*100+(ec20HttpBuf[sHttpCmd[HTTPREAD].trueOffset+2]-0x30)*10+
(ec20HttpBuf[sHttpCmd[HTTPREAD].trueOffset+3]) ;
runStatus = RUNERR ;
}
HttpErrorCode(errCode) ;
break ;
}
else if( kmp(ec20AtBuf, sHttpCmd[HTTPREAD].falseStr) >= 0)
{
runStatus = RUNERR ;
break ;
}
}
httpDataMode = false ; //关闭 接收http数据模式
DebugLogPrintf("%s %s", HttpCmdNumToString(HTTPREAD), RunResultToString(runStatus) ) ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: void HttpErrorCode( int errCode )
* 功能说明: 解析HTTP返回的错误码,请参照《Quectel_EC2x&EG9x&EM05_HTTP(S)_AT_Commands_Manual_V1.0.pdf》手册P35
* 入口参数:
* @param1 errCode 错误码
**************************************************************************************************/
void HttpErrorCode( int errCode )
{
switch( errCode)
{
case 0:
AppLogPrintf("Http Operation successful.") ;
break ;
case 701:
AppLogPrintf("HTTP(S) unknown error.") ;
break ;
case 702:
AppLogPrintf("HTTP(S) timeout.") ;
break ;
default:
AppLogPrintf("HTTP(S) other error.") ;
break ;
}
}