418 lines
18 KiB
C
418 lines
18 KiB
C
#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) ;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|