stm32_ota/HARDWARE/LTE/EC20/ec20module.c

418 lines
18 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 "ec20module.h"
#include "stm32f10x_gpio.h"
#include "sysport.h"
#include "syslib.h"
#include "io.h"
/********************************************************************************
* @file ec20module.c
* @author 晏诚科技 Mr.Wang
* @version V1.0.0
* @date 11-Dec-2018
* @brief 提供Quectel模块EC20模块级驱动程序控制IO、电源开关、回码、握手、CSQ、ICCID等
******************************************************************************
* @attention
* 外部调用EC20_Module_Init()对模块进行初始化此函数如果返回失败则说明MCU无法与EC20通过串口通信
可能是EC20供电、或者模块没有安装就位导致的。
* 网络通信前模块需要先查询SIM是否就绪接着注册到CS Service和PS service
* 最后才能配置相关通信协议实现通讯
*******************************************************************************/
/*****************************************
*ec20 module相关的常变量
****************************************/
ModuleParam_s sEc20Param ; //定义存放EC20模块参数的结构体
volatile bool httpDataMode = false ; //串口模式接收http数据模式
volatile bool ftpDataMode = false ; //串口模式接收ftp数据模式
char ec20AtBuf[EC20_ATBUF_LEN] ; //EC20 AT命令回码存放缓冲区
char ec20HttpBuf[EC20_HTTPBUF_LEN] ; //EC20 HTTP返回数据存放缓冲区
char ec20FtpBuf[EC20_FTPBUF_LEN] ; //EC20 FTP返回数据存放缓冲区
volatile int ec20FtpBufIndex = 0 ; //ec20FtpBuf缓冲区写指针
FrameQueue_s sTcpQueue ; //环形帧缓冲区存储模块返回的tcp相关数据
FrameQueue_s sUrcQueue ; //环形帧缓冲区存储模块返回的URC数据
/********************************************************
ec20模块Module指令相关处理
*********************************************************/
enum eModuleCmdNum
{
TURNOFF = 0, HANDSHAKE = 1, QUERYCONFIG = 2,
CLOSEECO =3, SAVECONFIG =4, QUERYRELESE =5,
QUERYVOLTAGE=6
} ; //枚举ec20模块Module相关指令
volatile EC20_CMD_DATA_s sModuleCmd[7]=
{
// cmdNum cmdStr, timeout trueStr trueOffset falseStr revResult rtyNum
{TURNOFF, "AT+QPOWD\r\n", (65*10), "POWERED DOWN", -1, "ERROR", TIMEOUT, 2 }, //关机命令
{HANDSHAKE, "AT\r\n", 10, "OK" , -1, "ERROR", TIMEOUT, 3 }, //握手指令
{QUERYCONFIG, "AT&V\r\n", 3, "E: 0" , -1, "E: 1", TIMEOUT, 1 }, //查询EC20配置命令AT&V
{CLOSEECO, "ATE0\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //关闭命令回显ATE0命令
{SAVECONFIG, "AT&W\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //保存配置命令
{QUERYRELESE, "AT+GMR\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //查询EC20软件版本号命令
{QUERYVOLTAGE,"AT+CBC\r\n", 10, "+CBC" , -1, "ERROR", TIMEOUT, 2 } //查询EC20电压命令
} ; //EC20模块module相关指令的EC20_CMD_DATA_s结构体类型参数
/**************************************************************************************************
* 名 称: static const char *ModuleCmdNumToString(enum eModuleCmdNum result)
* 功能说明: 输出枚举成员名的字符串指针。
* 入口参数: eModuleCmdNum类型的枚举
* 出口参数: 为枚举的成员名字符串指针
**************************************************************************************************/
static const char *ModuleCmdNumToString(enum eModuleCmdNum result)
{
switch (result)
{
ENUM_CHIP_TYPE_CASE(TURNOFF)
ENUM_CHIP_TYPE_CASE(HANDSHAKE)
ENUM_CHIP_TYPE_CASE(QUERYCONFIG)
ENUM_CHIP_TYPE_CASE(CLOSEECO)
ENUM_CHIP_TYPE_CASE(SAVECONFIG)
ENUM_CHIP_TYPE_CASE(QUERYRELESE)
ENUM_CHIP_TYPE_CASE(QUERYVOLTAGE)
}
return "无此命令";
}
/**************************************************************************************************
* 名 称: void Ec20AtBufReset(void)
* 功能说明: ec20AtBuf缓冲区初始化
**************************************************************************************************/
void Ec20AtBufReset(void)
{
memset(ec20AtBuf, 0, EC20_ATBUF_LEN) ;
}
/**************************************************************************************************
* 名 称: void Ec20HttpBufReset(void)
* 功能说明: ec20HttpBuf缓冲区初始化
**************************************************************************************************/
void Ec20HttpBufReset(void)
{
memset(ec20HttpBuf, 0, EC20_HTTPBUF_LEN) ;
}
/**************************************************************************************************
* 名 称: void Ec20FtpBufReset(void)
* 功能说明: ec20FtpBuf缓冲区初始化
**************************************************************************************************/
void Ec20FtpBufReset(void)
{
ec20FtpBufIndex = 0 ;
memset(ec20FtpBuf, 0, EC20_FTPBUF_LEN) ;
}
/**************************************************************************************************
* 名 称: void Ec20ReceiveFrameCallback(void)
* 功能说明: EC20模块——>MCU串口3接收空闲中断回调函数
* 将EC20模块返回的数据分为三大类1、http相关的数据2、tcp相关的数据3、模块URC相关的数据。
**************************************************************************************************/
void Ec20ReceiveFrameCallback(char *recvBuf, uint16_t recvLen)
{
int pos = 0;
//printf("\r\nEC20:%s", buf) ;
// if( httpDataMode == true ) /*串口接收模式为接收HTTP数据*/
// {
// strncat(ec20HttpBuf, recvBuf, recvLen) ;
//// SysLog("COM3 RxLen:%d; RxBuf:%s", len, uart3_Dma_Rx_Buf);
// }
if( ftpDataMode == true ) /*串口接收模式为接收HTTP数据*/
{
memcpy((ec20FtpBuf+ec20FtpBufIndex), recvBuf, recvLen) ;
ec20FtpBufIndex += recvLen ;
}
else if ( kmp(recvBuf, "+QIURC:")>=0 ) /*判断是否为TCP下行数据或者URC*/
{
pos = kmp(recvBuf, "+QIURC: \"recv\"") ;
if( pos>=0) /*判断是否为接收到TCP下行数据*/
{
if( RW_OK != InsertQueueMemData(&sTcpQueue, recvBuf, recvLen) )
{
ErrorLogPrintf("%s,%d:sTcpQueue spillover",__FILE__, __LINE__) ;
}
}
else /*判断是模块返回的URC*/
{
if( RW_OK != InsertQueueMemData(&sUrcQueue, recvBuf, recvLen) )
{
ErrorLogPrintf("%s,%d:sUrcQueue spillover",__FILE__, __LINE__) ;
}
}
}
else //EC20模块AT命令回码
{
if( recvLen < (EC20_ATBUF_LEN-strlen((const char*)ec20AtBuf))) /*ec20AtBuf剩余长度足以存贮recvBuf*/
{
strcat((char*)ec20AtBuf, recvBuf) ; //将接收到的AT命名回码数据存储到ec20AtBuf中去
}
else /*ec20AtBuf剩余长度不足以存贮recvBuf*/
{
ErrorLogPrintf("%s,%d:ec20AtBuf spillover. ",__FILE__, __LINE__) ; //报错
Ec20AtBufReset() ; //先清空 ec20AtBuf
strncpy((char*)ec20AtBuf, recvBuf, EC20_ATBUF_LEN) ; //再将recvBuf中的数据拷贝到ec20AtBuf中去
}
}
}
/**************************************************************************************************
* 名 称: RunResult EC20_Module_Init( void )
* 功能说明: EC20模块初始化IO初始化、供电、关闭回显、握手、查询SIM卡号、注册CS\PS网络、查询CSQ
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_Module_Init( void )
{
RunResult runResult = TIMEOUT ;
EC20_Uart_Init() ; //EC20_UART串口初始化,初始化接收缓冲区、注册串口回调函数
EC20_GPIO_Init() ; //MCU与EC20相关IO初始化、电源使能引脚、复位引脚
EC20_START() ; //EC20开机流程
EC20_Handshake() ; //EC20串口握手
runResult = EC20_CloseEcho() ; //EC20关闭命令回显
EC20_Query_SoftRelese(sEc20Param.ec20SoftVer) ; //查询EC20软件版本号并通过debug串口输出
AppLogPrintf("EC20 软件版本:%.*s", EC20_VER_LEN, sEc20Param.ec20SoftVer) ;
EC20_Query_Voltage(sEc20Param.ec20Voltage) ; //查询EC20供电电压并输出(实测在EC20刚刚启动阶段查询不到电压值)
AppLogPrintf("EC20 供电电压:%s mV", sEc20Param.ec20Voltage) ;// EC20_CLOSE() ;
//AppLogPrintf("EC20 供电电压:%.*smV", EC20_VOL_LEN, sEc20Param.ec20Voltage) ;// EC20_CLOSE() ;
return(runResult) ;
}
/**************************************************************************************************
* 名 称: RunResult EC20_SendModuleCmd( uint8_t cmdNum, char *format,... )
* 功能说明: MCU串口向EC20发送Module相关命令
* 入口参数:
* @param1 cmdNum EC20_CMD_DATA_s中cmdNum成员命令编号
* @param2 char *format,... 可变参变量
* 出口参数:
* @param status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_SendModuleCmd( uint8_t cmdNum, char *format,... )
{
uint8_t revTimes = 0 ;
RunResult status = TIMEOUT ;
uint8_t retryTimes = sModuleCmd[cmdNum].rtyNum ;
char *cmdPack = NULL ;
format = sModuleCmd[cmdNum].cmdStr ;
cmdPack = portMalloc(MODULE_CMDPACK_LEN*sizeof(uint8_t)) ;
va_list ap;
va_start (ap, format);
int outLen = vsnprintf(cmdPack, MODULE_CMDPACK_LEN, (const char*)format, ap); //vsprintf (temp, cmd, ap); //到此为止所有的参数情况已经汇总到temp了
if((outLen<=0)||( outLen > MODULE_CMDPACK_LEN))
{
ErrorLogPrintf("%s,%d:cmdPack spillover",__FILE__, __LINE__) ;
va_end (ap);
portFree(cmdPack) ;
return RUNERR ;
}
while(retryTimes--) //命令失败重试
{
Ec20AtBufReset() ; //ec20AtBuf缓冲区清空
revTimes = 0 ; //轮询计数器清零
UARTx_SendData(EC20_UART, cmdPack, outLen) ; //EC20_UART发送AT命令
while( revTimes++ < sModuleCmd[cmdNum].timeout ) /*在命令超时时间内一直在ec20AtBuf缓冲区内循环查找trueStr*/
{
Wait_For_Nms(10) ; //轮询查找时间间隔
sModuleCmd[cmdNum].trueOffset = kmp(ec20AtBuf, sModuleCmd[cmdNum].trueStr) ; //获取sModuleCmd[cmdNum].trueStr在ec20AtBuf中的偏移值
if( sModuleCmd[cmdNum].trueOffset >= 0) /*在ec20AtBuf中获取到sModuleCmd[cmdNum].trueStr字串*/
{
status = RUNOK ;
goto OUT ;
}
else if( kmp(ec20AtBuf, sModuleCmd[cmdNum].falseStr) >= 0)/*在ec20AtBuf中没有获取到sModuleCmd[cmdNum].trueStr字串*/
{
status = RUNERR ;
goto OUT ;
}
}
Wait_For_Nms( 200+( sModuleCmd[cmdNum].rtyNum-retryTimes)*100 ) ; //失败后延时一段时间再次发起请求命令
}
OUT:
portFree(cmdPack) ; //释放内存空间
va_end (ap) ; //释放内存空间
DebugLogPrintf("%s %s", ModuleCmdNumToString((enum eModuleCmdNum)cmdNum), RunResultToString(status) ) ; //输出命令执行结果
return (status) ; //返回函数执行结果
}
/**************************************************************************************************
* 名 称: void EC20_Uart_Init(void)
* 功能说明: 初始化EC20_UART初始化环形缓冲区、注册EC20_UART串口帧中断回调函数
**************************************************************************************************/
void EC20_Uart_Init(void)
{
UARTx_Init(EC20_UART, 115200, USART_Mode_Rx | USART_Mode_Tx, INT_RANK_1) ; //MCU与EC20通讯的串口初始化设置为收发模式中断优先级INT_RANK_1
Ec20AtBufReset() ; //ec20AtBuf缓冲区初始化
Ec20HttpBufReset() ; //ec20HttpBuf缓冲区初始化
InitQueueMem(&sTcpQueue) ; //初始化环形帧缓冲区存储模块返回的tcp相关数据
InitQueueMem(&sUrcQueue) ; //初始化环形帧缓冲区存储模块返回的URC数据
Uart_RegHookCallback(EC20_UART, Ec20ReceiveFrameCallback) ; //注册EC20接收帧中断回调函数
}
/**************************************************************************************************
* 名 称: void EC20_GPIO_Init( void )
* 功能说明: EC20模块相关IO初始化
**************************************************************************************************/
void EC20_GPIO_Init( void )
{
Gpio_Init(EC20_POW_PORT, EC20_POW_PIN, GPIO_Mode_Out_PP) ;
EC20_POWOFF() ; //初始化时EC20初始为断电状态
Gpio_Init(EC20_RST_PORT, EC20_RST_PIN, GPIO_Mode_Out_PP) ; //PERST上拉 = PE15拉低
EC20_RST = 0 ;
}
/****************************************************************************
* 名 称void EC20_POWON(void)
* 功 能打开EC20模块供电电源
****************************************************************************/
void EC20_POWON(void)
{
// Wait_For_Nms(3000) ; //开机前保持3S断电状态
EC20_POW = 1 ;
}
/****************************************************************************
* 名 称void EC20_POWOFF(void)
* 功 能关闭EC20模块供电电源
****************************************************************************/
void EC20_POWOFF(void)
{
EC20_POW = 0 ;
Wait_For_Nms(100) ; //断电后保持5S断电状态因为模块内核可能由于电容放电没有完全断电清除网络参数
}
/****************************************************************************
* 名 称RunResult EC20_START(void)
* 功 能EC20开机启动
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
* 说 明EC20上电大概15S内串口会输出“RDY”字符串
****************************************************************************/
RunResult EC20_START(void)
{
uint8_t findCount = 0 ;
RunResult runStatus = TIMEOUT ;
EC20_POWON() ; //开启EC20电源
Ec20AtBufReset() ; //ec20AtBuf缓冲区初始化
while( findCount < 20) //循环等待EC20开机标志
{
findCount++ ;
Wait_For_Nms(10) ;
if( kmp(ec20AtBuf, "RDY") >= 0) /*收到EC20返回的”RDY“字符串EC20开机完成*/
{
DebugLogPrintf("EC20 Start Waited:%d S", findCount ) ;
runStatus = RUNOK ;
break ;
}
}
return(runStatus) ;
}
/****************************************************************************
* 名 称RunResult EC20_CLOSE(void)
* 功 能EC20关机流程 软关机-->等待1S-->断电
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
****************************************************************************/
RunResult EC20_CLOSE(void)
{
RunResult runStatus = TIMEOUT ;
runStatus = EC20_SendModuleCmd(TURNOFF, NULL ) ;
if( RUNOK != runStatus )
{
ErrorLogPrintf("EC20 软关机失败,即将断电关机!") ;
}
Wait_For_Nms(10) ; //《AT Command》手册中建议延时1s后再断电
EC20_POWOFF() ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult EC20_Handshake( void )
* 功能说明: MCU串口发送AT指令验证串口通信是否就绪
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_Handshake( void )
{
RunResult runStatus = TIMEOUT ;
runStatus = EC20_SendModuleCmd(HANDSHAKE, NULL ) ;
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult EC20_CloseEcho(void)
* 功能说明: 关闭EC20指令回码
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_CloseEcho(void)
{
RunResult runStatus = TIMEOUT ;
runStatus = EC20_SendModuleCmd( QUERYCONFIG, NULL ) ;
if( runStatus != RUNOK )
{
EC20_SendModuleCmd( CLOSEECO, NULL ) ; //关闭串口AT命令ECHO
runStatus = EC20_SendModuleCmd( QUERYCONFIG, NULL ) ;
// EC20_SendModuleCmd( SAVECONFIG, sModuleCmd[SAVECONFIG].cmdStr ) ; //为了兼容前面版本,不保存
}
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult EC20_Query_SoftRelese(char *version)
* 功能说明: 查询EC20的固件版本
* 入口参数:
* @param1 *version 存放version的内存地址
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_Query_SoftRelese(char *version)
{
RunResult runStatus = TIMEOUT ;
char *start ;
memset(version, 0, EC20_VER_LEN+1);
runStatus = EC20_SendModuleCmd(QUERYRELESE, NULL ) ;
if( RUNOK == runStatus )
{
start = strchr( (const char*)ec20AtBuf, 0x0D ) ;
CopyValues((uint8_t*)version, (uint8_t*)(start+2), 0x0D, EC20_VER_LEN) ;
}
return (runStatus) ;
}
/**************************************************************************************************
* 名 称: RunResult EC20_Query_Voltage(char *voltage)
* 功能说明: 查询EC20的供电电压
* 入口参数:
* @param1 *voltage 存放voltage的内存地址
* 出口参数:
* @param1 status RunResult枚举类型变量返回函数运行结果
**************************************************************************************************/
RunResult EC20_Query_Voltage(char *voltage)
{
RunResult runStatus = TIMEOUT ;
char *start ;
memset(voltage, 0, EC20_VOL_LEN+1);
runStatus = EC20_SendModuleCmd(QUERYVOLTAGE, NULL ) ;
if( RUNOK == runStatus )
{
start = strrchr( (const char*)ec20AtBuf, ',' ) ;
CopyValues((uint8_t*)voltage, (uint8_t*)start+1, 0x0D, EC20_VOL_LEN) ;
}
return (runStatus) ;
}