/*
* iot.c
*
* Created on: 2018年11月1日
* Author: admin
*/
/*****************************************************************
* 代码解释可查看
https://blog.csdn.net/hnxyxiaomeng/article/details/84613712
******************************************************************/
#include "at.h"
#include <os.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
char *atAckBuf;
SendMsgFunc_t SendMsgCallback=NULL;
OS_SEM *pRecvAckSem=NULL;
OS_MUTEX *pAckBufMux=NULL;
static void AT_ClearAckBuff(void);
static char* AT_SearchRecvBuf(const char* recv_str,uint16_t max_resp_time);
//下面是系统时钟节拍,目前是1000Hz
// (CPU_INT32U)OSCfg_TickRate_Hz;
//ms数转化为系统节拍数
#define MS2OSTICK(ms) ((OSCfg_TickRate_Hz/1000)*(ms))
/*****************************************************************
* 功能:注册AT指令运行环境
******************************************************************/
void AT_RegisterHandler(SendMsgFunc_t func, char* recv_buf, OS_SEM* recv_sem, OS_MUTEX* buf_mutex)
{
SendMsgCallback=func; //串口发送数据的函数
pRecvAckSem = (OS_SEM*)recv_sem; //串口收到AT指令回令的信号量,可在串口接收空闲后发出
//对于裸奔的单片机系统,可改为串口接收空闲后将某个标志位置1
pAckBufMux=(OS_MUTEX*)buf_mutex; //串口接收缓冲区互斥信号量
atAckBuf = (char*)recv_buf; //串口接收缓冲区
return;
}
/*****************************************************************
* 功能:发送AT指令
* 输入: send_buf:发送的字符串
recv_str:期待回令中包含的子字符串
p_at_config:AT配置
* 输出:执行结果代码
******************************************************************/
uint8_t AT_SendCmd(const char *send_str,const char *recv_str,stcATConfig *p_at_config)
{
uint8_t _ret = 0;
uint8_t _try_times = 0;
uint8_t _reset_times = 0;
char * _p_msg = NULL;
OS_ERR _timeout_err;
if(SendMsgCallback==NULL | pAckBufMux==NULL | atAckBuf==NULL)
{
return _ret = 2;
}
do
{
AT_ClearAckBuff();
SendMsgCallback(send_str,strlen(send_str));
_p_msg = AT_SearchRecvBuf(recv_str,p_at_config->resp_time100ms);
if ( _p_msg != NULL )
{
return _ret = 0;
}
else
{
_try_times ++;
if ( _try_times >= p_at_config->max_try_times )
{
_reset_times ++;
if ( _reset_times >= p_at_config->max_reset_times + 1 )
{
return _ret = 1;
}
else
{
// TODO:硬件方式重启模块
}
}
else
{
OSTimeDlyHMSM( 0, 0, 0, p_at_config->try_delay1ms, OS_OPT_TIME_DLY, &_timeout_err );
}
}
}while(1);
return _ret;
}
/*****************************************************************
* 功能:发送数组数据
* 输入: send_buf:发送的数组
buf_len:数组长度
recv_str:期待回令中包含的子字符串
p_at_config:AT配置
* 输出:执行结果代码
******************************************************************/
uint8_t AT_SendData(const char *send_buf,const uint16_t buf_len,const char *recv_str,stcATConfig *p_at_config)
{
uint8_t _ret = 0;
uint8_t _try_times = 0;
uint8_t _reset_times = 0;
char * _p_msg = NULL;
OS_ERR _timeout_err;
if(SendMsgCallback==NULL | pAckBufMux==NULL | atAckBuf==NULL)
{
return _ret = 2;
}
do
{
AT_ClearAckBuff();
SendMsgCallback(send_buf,buf_len);
_p_msg = AT_SearchRecvBuf(recv_str,p_at_config->resp_time100ms);
if ( _p_msg != NULL )
{
return _ret = 0;
}
else
{
_try_times ++;
if ( _try_times >= p_at_config->max_try_times )
{
_reset_times ++;
return _ret = 1;
}
else
{
OSTimeDlyHMSM( 0, 0, 0, p_at_config->try_delay1ms, OS_OPT_TIME_DLY, &_timeout_err );
}
}
}while(1);
return _ret;
}
/*****************************************************************
* 功能:查询AT指令的回令中是否有需要的字符串
* 输入: recv_str:期待输出字符串中需要含有的子字符串,如"OK\r\n"
max_resp_time:指令最大响应时间,单位100ms
* 输出:查找到的子字符串指针
******************************************************************/
char* AT_SearchRecvBuf(const char* recv_str,uint16_t max_resp_time)
{
OS_ERR _errSem;
OS_ERR _errMux;
OS_ERR _errTimeout;
CPU_TS _ts;
char *_p_msg = NULL;
uint16_t _respCnt = 0;
do
{
OSTimeDlyHMSM( 0, 0, 0, 100, OS_OPT_TIME_DLY, &_errTimeout );
OSSemPend(pRecvAckSem,20u,OS_OPT_PEND_BLOCKING,&_ts,&_errSem);//这里占用的时间,实际延时比设置的要长
if(_errSem == OS_ERR_NONE)
{
OSSemSet(pRecvAckSem,0,_errSem);
OSMutexPend(pAckBufMux, 0, OS_OPT_PEND_BLOCKING, &_ts, &_errMux );
if ( _errMux == OS_ERR_NONE)
{
_p_msg = strstr( atAckBuf, recv_str );
}
OSMutexPost(pAckBufMux, OS_OPT_POST_NO_SCHED, ( OS_ERR * ) &_errMux );
if(_p_msg!=NULL)
{
break;
}
}
if(_errSem == OS_ERR_TIMEOUT)
{
_respCnt++;
}
}while(_respCnt<max_resp_time);
return _p_msg;
}
/******************************************
* 功能:清空串口接收缓冲区
******************************************/
void AT_ClearAckBuff(void)
{
OS_ERR _err;
CPU_TS _ts;
OSMutexPend( pAckBufMux, 20u, OS_OPT_PEND_BLOCKING, &_ts, &_err );
if ( _err == OS_ERR_NONE )
{
memset(atAckBuf,0,AT_ACK_BUF_SIZE);
}
OSMutexPost( pAckBufMux, OS_OPT_POST_NO_SCHED, ( OS_ERR * ) &_err );
return;
}