2026-04-23 13:56:52 +08:00
|
|
|
|
#include "CatOneTask.h"
|
|
|
|
|
|
#include "Public.h"
|
|
|
|
|
|
#include "DebugCmd.h"
|
|
|
|
|
|
|
|
|
|
|
|
static rt_sem_t CatOneRev_Sem = RT_NULL;
|
|
|
|
|
|
static rt_sem_t CatOneIRQ_Sem = RT_NULL;
|
|
|
|
|
|
static rt_sem_t EthIRQ_Sem = RT_NULL;
|
|
|
|
|
|
static rt_thread_t Cat1Rev_Thread = RT_NULL;
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t CAT1DispEn = false;
|
|
|
|
|
|
static CatOne_t CatOne;
|
|
|
|
|
|
|
|
|
|
|
|
static char CatOneEthRxBuff[CAT_ONE_REV_LEN_MAX];
|
|
|
|
|
|
static uint16_t CatOneEthRxLen;
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t CatOneEthTxBuff[CAT_ONE_REV_LEN_MAX];
|
|
|
|
|
|
static uint16_t CatOneEthTxLen;
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t Payload[CAT_ONE_REV_LEN_MAX];
|
|
|
|
|
|
static char CommUnitSendASCII[CAT_ONE_REV_LEN_MAX * 2];
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t EthRevTimeOutCnt;
|
|
|
|
|
|
|
|
|
|
|
|
static uint16_t CatSendErrCnt = 0;
|
|
|
|
|
|
|
2026-06-11 19:17:31 +08:00
|
|
|
|
// ETH状态机相关变量已移至 CatOne_t 结构体中
|
|
|
|
|
|
|
2026-04-23 13:56:52 +08:00
|
|
|
|
#define CAT1_DBG_LOG(...) { if(CAT1DispEn) Debug_Printf(__VA_ARGS__);}
|
|
|
|
|
|
//#define CAT1_DBG_ARRAY(ARRAY, SIZE) { if(CAT1DispEn) {DBG_ARRAY(ARRAY,SIZE)}}
|
|
|
|
|
|
|
|
|
|
|
|
#define CATONE_RESET_DELAY_TIME_MAX (5 * 60 * 1000)
|
|
|
|
|
|
|
2026-06-05 11:08:54 +08:00
|
|
|
|
//const char *CatOneATCmdStr[16] = {
|
|
|
|
|
|
// "NULL",
|
|
|
|
|
|
// "AT\r\n", //开机检测
|
|
|
|
|
|
// "ATE0\r\n", //关回显
|
|
|
|
|
|
// "AT+CPIN?\r\n", //识卡
|
|
|
|
|
|
//// "AT+CIMI\r\n", //IMEI
|
|
|
|
|
|
// "AT+CGSN=1\r\n",
|
|
|
|
|
|
// "AT+LCCID\r\n", //读卡号
|
|
|
|
|
|
// "AT+CEREG?\r\n", //查询注册状态
|
|
|
|
|
|
// "AT+CGPADDR=1\r\n", //查询IP地址
|
|
|
|
|
|
// "AT+CSQ\r\n", //查询信号强度
|
|
|
|
|
|
// "AT+LDNSGIP=gxjt.cui635.cn\r\n",
|
|
|
|
|
|
// "AT+LBS=0\r\n", //获取基站定位信息
|
|
|
|
|
|
// "AT+LIPOPEN=", //设置TCP服务器地址和端口,AT+LIPOPEN="TCP","114.55.52.96",6803
|
|
|
|
|
|
// "AT+LIPSEND=", //发送数据, AT+LIPSEND=0,1,20,"31313131313131323232323232"
|
|
|
|
|
|
// "AT+LIPCLOSE=0\r\n",//断开连接
|
|
|
|
|
|
// "AT+LBSPARA=http://locator-aep.xiot.senthink.com:80/locator/v0.1/locate,B84E427D95B1DF4A3F49B18DDF714C72\r\n",
|
|
|
|
|
|
// "AT+CCLK?\r\n", //获取时间
|
|
|
|
|
|
//};
|
|
|
|
|
|
|
2026-04-23 13:56:52 +08:00
|
|
|
|
const char *CatOneATCmdStr[16] = {
|
|
|
|
|
|
"NULL",
|
|
|
|
|
|
"AT\r\n", //开机检测
|
|
|
|
|
|
"ATE0\r\n", //关回显
|
|
|
|
|
|
"AT+CPIN?\r\n", //识卡
|
|
|
|
|
|
// "AT+CIMI\r\n", //IMEI
|
|
|
|
|
|
"AT+CGSN=1\r\n",
|
2026-06-05 11:08:54 +08:00
|
|
|
|
"AT+QCCID\r\n", //读卡号
|
2026-04-23 13:56:52 +08:00
|
|
|
|
"AT+CEREG?\r\n", //查询注册状态
|
|
|
|
|
|
"AT+CGPADDR=1\r\n", //查询IP地址
|
|
|
|
|
|
"AT+CSQ\r\n", //查询信号强度
|
|
|
|
|
|
"AT+LDNSGIP=gxjt.cui635.cn\r\n",
|
2026-06-05 11:08:54 +08:00
|
|
|
|
"AT+QLBS\r\n", //获取基站定位信息
|
|
|
|
|
|
"AT+QIOPEN=", //设置TCP服务器地址和端口,AT+LIPOPEN="TCP","114.55.52.96",6803
|
|
|
|
|
|
"AT+QISEND=", //发送数据, AT+LIPSEND=0,1,20,"31313131313131323232323232"
|
|
|
|
|
|
"AT+QICLOSE=0\r\n",//断开连接
|
|
|
|
|
|
"AT+QLBSCFG=\"server\",http://locator-aep.xiot.senthink.com:80/locator/v0.1/locate\r\n",
|
|
|
|
|
|
"AT+QLBSCFG=\"token\",45B516D3078467E84DD2CFBF3532A4CB\r\n",
|
|
|
|
|
|
"AT+CCLK?\r\n", //获取时间
|
2026-04-23 13:56:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void Cat1DBGOnOff(bool OnOff)
|
|
|
|
|
|
{
|
|
|
|
|
|
CAT1DispEn = OnOff;
|
|
|
|
|
|
if(OnOff)
|
|
|
|
|
|
Debug_Printf("\r\nCat1 Display Enable!\r\n\r\n");
|
|
|
|
|
|
else
|
|
|
|
|
|
Debug_Printf("\r\nCat1 Display Disable!\r\n\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const CatOneATCMD_m CatOneModeSetCmdArray[] = {
|
|
|
|
|
|
CAT_ONE_AT_NULL,
|
|
|
|
|
|
CAT_ONE_AT,
|
|
|
|
|
|
CAT_ONE_ATE0,
|
|
|
|
|
|
//CAT_ONE_LBSPARA,
|
|
|
|
|
|
CAT_ONE_LCCID,
|
|
|
|
|
|
CAT_ONE_IMEI,
|
|
|
|
|
|
CAT_ONE_CPIN,
|
|
|
|
|
|
CAT_ONE_CEREG,
|
|
|
|
|
|
CAT_ONE_CSQ,
|
|
|
|
|
|
//CAT_ONE_LDNSGIP,
|
|
|
|
|
|
//CAT_ONE_LBS,
|
|
|
|
|
|
CAT_ONE_CCLK,
|
|
|
|
|
|
CAT_ONE_AT_CMD_END
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//CatOneRetStatus_m CatOneSend(uint8_t *sData, uint16_t sLen)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// rt_err_t result;
|
|
|
|
|
|
//
|
2026-06-15 18:38:41 +08:00
|
|
|
|
// if(CatOne.Cat1Status != CAT_ONE_IDEL && CatOne.Cat1Status != CAT_ONE_WAIT_SEND)
|
2026-04-23 13:56:52 +08:00
|
|
|
|
// return CAT_ONE_RET_ERR;
|
|
|
|
|
|
//
|
2026-06-15 18:38:41 +08:00
|
|
|
|
// //CatOne.Cat1Status = CAT_ONE_RESET;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
// result = rt_mq_send(CatOneRev_MQ, sData, sLen);
|
|
|
|
|
|
// if(result != RT_EOK) {
|
|
|
|
|
|
// CAT1_DBG_LOG("CatOne MQ Send ERR...\r\n");
|
|
|
|
|
|
// return CAT_ONE_RET_ERR;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// CAT1_DBG_LOG("CatOne Send Message: \r\n", sData);
|
|
|
|
|
|
// return CAT_ONE_RET_OK;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneStop(void)
|
|
|
|
|
|
{
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_OFF;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-15 15:11:23 +08:00
|
|
|
|
void ETHStop(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
CatOne.EthStatus = ETH_OFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ETHReset(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
CatOne.EthStatus = ETH_RESET;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-23 13:56:52 +08:00
|
|
|
|
void CatOneGetLocationInfo(int *Longitude, int *Latitude)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(CatOne.LBSFlag) {
|
|
|
|
|
|
*Longitude = CatOne.Longitude;
|
|
|
|
|
|
*Latitude = CatOne.Latitude;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
*Longitude = 0;
|
|
|
|
|
|
*Latitude = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneGetIMEIAndSIM(char *Imei, char *Sim)
|
|
|
|
|
|
{
|
|
|
|
|
|
memcpy(Imei, CatOne.IMEI, 15);
|
|
|
|
|
|
memcpy(Sim, CatOne.SIM, 20);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//返回true-busy, false-Idle
|
|
|
|
|
|
bool CatOneGetStatus(void)
|
|
|
|
|
|
{
|
2026-06-15 18:38:41 +08:00
|
|
|
|
if(CatOne.Cat1Status == CAT_ONE_IDEL)
|
2026-04-23 13:56:52 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneReset(void)
|
|
|
|
|
|
{
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_RESET;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatTimeSync(char *Data)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct tm sTimet;
|
|
|
|
|
|
time_t sTime;
|
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
|
|
p = strchr(Data, '\"');
|
|
|
|
|
|
if(p == NULL)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
int ret = sscanf(p, "\"%d/%d/%d,%d:%d:%d+",
|
|
|
|
|
|
&sTimet.tm_year, &sTimet.tm_mon, &sTimet.tm_mday,
|
|
|
|
|
|
&sTimet.tm_hour, &sTimet.tm_min, & sTimet.tm_sec);
|
|
|
|
|
|
if(ret != 6) {
|
|
|
|
|
|
int ret = sscanf(p, "\"%d/%d/%d,%d:%d:%d-",
|
|
|
|
|
|
&sTimet.tm_year, &sTimet.tm_mon, &sTimet.tm_mday,
|
|
|
|
|
|
&sTimet.tm_hour, &sTimet.tm_min, & sTimet.tm_sec);
|
|
|
|
|
|
if(ret != 6)
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sTimet.tm_isdst = 0;
|
|
|
|
|
|
if(sTimet.tm_year < 24 || sTimet.tm_year > 50)
|
|
|
|
|
|
return;
|
|
|
|
|
|
sTimet.tm_year += 100;
|
|
|
|
|
|
|
|
|
|
|
|
if(sTimet.tm_mon > 12 || sTimet.tm_mon == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
sTimet.tm_mon--;
|
|
|
|
|
|
|
|
|
|
|
|
sTime = mktime(&sTimet);
|
|
|
|
|
|
TimeSync(sTime);
|
|
|
|
|
|
CAT1_DBG_LOG("Set Time:");
|
|
|
|
|
|
TimeShow(TimeTs());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneAtCmdAnalyze(char *RxBuff)
|
|
|
|
|
|
{
|
|
|
|
|
|
char *p;
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_OK;
|
|
|
|
|
|
CAT1_DBG_LOG(RxBuff);
|
|
|
|
|
|
|
|
|
|
|
|
switch(CatOne.AtCmd) {
|
|
|
|
|
|
case CAT_ONE_AT:
|
|
|
|
|
|
case CAT_ONE_ATE0:
|
|
|
|
|
|
case CAT_ONE_LIPSEND:
|
|
|
|
|
|
case CAT_ONE_LDNSGIP:
|
|
|
|
|
|
case CAT_ONE_LBSPARA:
|
|
|
|
|
|
if(strstr(RxBuff, "OK") == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_IMEI:
|
|
|
|
|
|
if(strstr(RxBuff, "OK") == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
p = strstr(RxBuff, "+CGSN");
|
|
|
|
|
|
if(p == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
p = strchr(p, '"');
|
|
|
|
|
|
if(p != NULL) {
|
|
|
|
|
|
memcpy(CatOne.IMEI, p+1, 15);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
memset(CatOne.IMEI, 0, 15);
|
|
|
|
|
|
}
|
|
|
|
|
|
// ret = sscanf(p, "+CGSN: \"%s\"\r\n", CatOne.IMEI);
|
|
|
|
|
|
// if(ret != 1) {
|
|
|
|
|
|
// memset(CatOne.IMEI, 0, 15);
|
|
|
|
|
|
// }
|
|
|
|
|
|
CatOne.IMEI[15] = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_CCLK:
|
|
|
|
|
|
if(strstr(RxBuff, "+CCLK") != NULL) {
|
|
|
|
|
|
CatTimeSync(RxBuff);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_LCCID:
|
|
|
|
|
|
if(strstr(RxBuff, "OK") == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
2026-06-05 11:08:54 +08:00
|
|
|
|
p = strstr(RxBuff, "+QCCID");
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(p == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
memset(CatOne.SIM, 0, 32);
|
2026-06-05 11:08:54 +08:00
|
|
|
|
ret = sscanf(p, "+QCCID: %s\r\n", CatOne.SIM);
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(ret != 1) {
|
|
|
|
|
|
memset(CatOne.SIM, 0, 32);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_LBS:
|
2026-06-05 11:08:54 +08:00
|
|
|
|
p = strstr(RxBuff, "+QLBS");
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(p != NULL) {
|
|
|
|
|
|
double Longitude, Latitude;
|
2026-06-05 11:08:54 +08:00
|
|
|
|
int ret = sscanf(p, "+QLBS: %lf,%lf\r\n", &Longitude, &Latitude);
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(ret == 2) {
|
|
|
|
|
|
CatOne.LBSFlag = true;
|
|
|
|
|
|
CatOne.Longitude = Longitude * 100000;
|
|
|
|
|
|
CatOne.Latitude = Latitude * 100000;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_LIPOPEN:
|
|
|
|
|
|
if(strstr(RxBuff, "OK") != NULL) {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CatOne.NextStatus;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CatOne.CatOne1mSDelayCnt = 10 * 1000;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
if(strstr(RxBuff, "LIPOPEN: 0,1") != NULL) {
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 successfully to connect to the server.\r\n\r\n");
|
|
|
|
|
|
CatOne.TcpConnFlag = true;
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CatOne.NextStatus;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
rt_sem_release(CatOneRev_Sem);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(strstr(RxBuff, "LIPOPEN: 0,0") != NULL) {
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 failed to connect to the server.\r\n\r\n");
|
|
|
|
|
|
CatOne.TcpConnFlag = false;
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_OFF;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_CPIN:
|
|
|
|
|
|
if(strstr(RxBuff, "READY") == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_CEREG:
|
|
|
|
|
|
if(strstr(RxBuff, "CEREG: 0,1") == NULL) {
|
|
|
|
|
|
CatOne.CatOne1mSDelayCnt = 3000;
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_CGPADDR:
|
|
|
|
|
|
if(strstr(RxBuff, "+CGPADDR") == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_CSQ:
|
|
|
|
|
|
if(strstr(RxBuff, "+CSQ") == NULL) {
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_LTPCLOSE:
|
|
|
|
|
|
if(strstr(RxBuff, "CLOSE OK") != NULL) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(strstr(RxBuff, "ERROR") != NULL) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(strstr(RxBuff, "OK") != NULL){
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CAT_ONE_AT_NULL:
|
|
|
|
|
|
p = strstr(RxBuff, "+LIPURC");
|
|
|
|
|
|
if(p != NULL) {
|
|
|
|
|
|
char rData[120];
|
|
|
|
|
|
uint8_t hData[60];
|
|
|
|
|
|
int rLen, hLen, ret;
|
|
|
|
|
|
|
|
|
|
|
|
if(strstr(p, "+LIPURC: 0,0") != NULL) {
|
|
|
|
|
|
CAT1_DBG_LOG("TCP connection disconnected.\r\n\r\n");
|
|
|
|
|
|
CatOne.TcpConnFlag = false;
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_OFF;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ret = sscanf(p, "+LIPURC: 0,1,%d,%s\r\n", &rLen, rData);
|
|
|
|
|
|
if(ret == 2) {
|
|
|
|
|
|
if(rLen < 24)
|
|
|
|
|
|
return;
|
|
|
|
|
|
memset(hData, 0x00, 60);
|
|
|
|
|
|
hLen = AsciiToHex(rData, hData, rLen);
|
|
|
|
|
|
CatSendErrCnt = 0;
|
|
|
|
|
|
CatOne.GateWay->SvrRevCallBack(CatOne.GateWay, hData, hLen);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-06-15 18:38:41 +08:00
|
|
|
|
//CatOne.Cat1Status = CAT_ONE_CLOSE_TCP;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
rt_sem_release(CatOneRev_Sem);//接收任务
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
if(CatOne.ATCmdRet == CAT_ONE_RET_OK) {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CatOne.NextStatus;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(CatOne.AtCmd == CAT_ONE_LIPSEND)
|
|
|
|
|
|
CatOne.CatOne1mSDelayCnt = 5 * 1000;
|
|
|
|
|
|
else
|
|
|
|
|
|
CatOne.CatOne1mSDelayCnt = 10;
|
|
|
|
|
|
CatOne.AtCmd = CAT_ONE_AT_NULL;
|
|
|
|
|
|
rt_sem_release(CatOneRev_Sem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneAtCmdSend(CatOneATCMD_m Cmd, uint32_t Dly, CatOneStatus_m NextStatus)
|
|
|
|
|
|
{
|
|
|
|
|
|
CatOne.AtCmd = Cmd;
|
|
|
|
|
|
if(CatOne.AtCmd == CAT_ONE_LIPSEND) {
|
|
|
|
|
|
HexToAscii(CatOneEthTxBuff, CommUnitSendASCII, CatOneEthTxLen);
|
|
|
|
|
|
sprintf(CatOne.CatOneSendBuff,"AT+LIPSEND=0,1,%d,\"%s\"\r\n",CatOneEthTxLen * 2, CommUnitSendASCII);
|
|
|
|
|
|
CatOne.GateWay->BatteryReadDlyCnt = 30;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(CatOne.AtCmd == CAT_ONE_LIPOPEN) {
|
|
|
|
|
|
sprintf(CatOne.CatOneSendBuff,"AT+LIPOPEN=\"TCP\",\"%d.%d.%d.%d\",%d\r\n",
|
2026-06-17 12:30:57 +08:00
|
|
|
|
CatOne.GateWay->ConfigPara.LTENet.DestAddr[0],
|
|
|
|
|
|
CatOne.GateWay->ConfigPara.LTENet.DestAddr[1],
|
|
|
|
|
|
CatOne.GateWay->ConfigPara.LTENet.DestAddr[2],
|
|
|
|
|
|
CatOne.GateWay->ConfigPara.LTENet.DestAddr[3],
|
|
|
|
|
|
CatOne.GateWay->ConfigPara.LTENet.DestPort);
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
strcpy(CatOne.CatOneSendBuff, CatOneATCmdStr[CatOne.AtCmd]);
|
|
|
|
|
|
}
|
|
|
|
|
|
CAT1_DBG_LOG(CatOne.CatOneSendBuff);
|
|
|
|
|
|
EthRevTimeOutCnt = 0;
|
|
|
|
|
|
EthOrCat1UartSend((uint8_t *)CatOne.CatOneSendBuff, strlen(CatOne.CatOneSendBuff));
|
|
|
|
|
|
CatOne.CatOne1mSDelayCnt = Dly;
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_WAIT_REV;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CatOne.NextStatus = NextStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GateWayRegister(uint8_t *TxBuff)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t UnitCommCnt = 0;
|
|
|
|
|
|
uint8_t *p = &TxBuff[0];
|
|
|
|
|
|
uint16_t len = 5;
|
|
|
|
|
|
|
|
|
|
|
|
if(CatOne.GateWay->ConfigPara.Rs485Ch1.CommUnitEnable == true && CatOne.GateWay->ConfigPara.Rs485Ch1.Enable == true) {
|
|
|
|
|
|
UnitCommCnt++;
|
2026-06-12 18:14:43 +08:00
|
|
|
|
memcpy(&p[len], CatOne.GateWay->ConfigPara.Rs485Ch1.CUPara.Para.Mac[0], 6);
|
2026-04-23 13:56:52 +08:00
|
|
|
|
len += 6;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(CatOne.GateWay->ConfigPara.Rs485Ch2.CommUnitEnable == true && CatOne.GateWay->ConfigPara.Rs485Ch2.Enable == true) {
|
|
|
|
|
|
UnitCommCnt++;
|
2026-06-12 18:14:43 +08:00
|
|
|
|
memcpy(&p[len], CatOne.GateWay->ConfigPara.Rs485Ch2.CUPara.Para.Mac[0], 6);
|
2026-04-23 13:56:52 +08:00
|
|
|
|
len += 6;
|
|
|
|
|
|
}
|
|
|
|
|
|
for(int i = 0; i < COMMUNIT_NUM_MAX; i++) {
|
|
|
|
|
|
if(CatOne.GateWay->ConfigPara.CommUnitArray[i].RegFlag == true) {
|
|
|
|
|
|
for(int j = 0; j < CatOne.GateWay->ConfigPara.CommUnitArray[i].SensorN; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
memcpy(&p[len], CatOne.GateWay->ConfigPara.CommUnitArray[i].Mac[j], 6);
|
|
|
|
|
|
len += 6;
|
|
|
|
|
|
UnitCommCnt++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
TxBuff[0] = (len - 3) & 0x00ff;
|
|
|
|
|
|
TxBuff[1] = ((len - 3) >> 8) & 0x00ff;
|
|
|
|
|
|
TxBuff[2] = NET_COMM_CMD_REG;
|
|
|
|
|
|
TxBuff[3] = UnitCommCnt & 0x00ff;
|
|
|
|
|
|
TxBuff[4] = (UnitCommCnt >> 8) & 0x00ff;
|
|
|
|
|
|
return len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneLoopHandler(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
static rt_err_t result;
|
|
|
|
|
|
uint16_t ret;
|
|
|
|
|
|
static uint8_t Cat1RevErrCnt = 0;
|
|
|
|
|
|
|
2026-06-15 18:38:41 +08:00
|
|
|
|
switch(CatOne.Cat1Status){
|
2026-04-23 13:56:52 +08:00
|
|
|
|
case CAT_ONE_IDEL:
|
|
|
|
|
|
rt_thread_delay(1);
|
|
|
|
|
|
if(CatOne.ResetDelayCnt > 0) {
|
|
|
|
|
|
CatOne.ResetDelayCnt--;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_RESET;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_WAIT_REV:
|
|
|
|
|
|
result = rt_sem_take(CatOneRev_Sem, CatOne.CatOne1mSDelayCnt);
|
|
|
|
|
|
if(result != RT_EOK) {
|
|
|
|
|
|
if(CatOne.AtCmdResendCnt > 0) {
|
|
|
|
|
|
CatOne.AtCmdResendCnt--;
|
|
|
|
|
|
CatOneAtCmdSend(CatOne.AtCmd, 2000, CatOne.NextStatus);
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 Ret TimeOut, ReSend(%d)...\r\n", CatOne.AtCmdResendCnt);
|
|
|
|
|
|
}
|
|
|
|
|
|
else { //3次错误,关机
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 error, Close!\r\n");
|
|
|
|
|
|
if(CatOne.AtCmd == CAT_ONE_LIPSEND)
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_CLOSE_TCP;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
else
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_OFF;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_INIT:
|
|
|
|
|
|
CatOne.AtCmdIdx++;
|
|
|
|
|
|
if(CatOneModeSetCmdArray[CatOne.AtCmdIdx] != CAT_ONE_AT_CMD_END) {
|
|
|
|
|
|
if(CatOneModeSetCmdArray[CatOne.AtCmdIdx] == CAT_ONE_CEREG)
|
|
|
|
|
|
CatOne.AtCmdResendCnt = 30;
|
|
|
|
|
|
else
|
|
|
|
|
|
CatOne.AtCmdResendCnt = 3;
|
|
|
|
|
|
CatOneAtCmdSend(CatOneModeSetCmdArray[CatOne.AtCmdIdx], 1000, CAT_ONE_INIT);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_TCP_CONN;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CatOne.CatOne1mSDelayCnt = 0;
|
|
|
|
|
|
CatOne.AtCmdIdx = 0;
|
|
|
|
|
|
CatOne.AtCmd = CAT_ONE_AT_NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_TCP_CONN:
|
|
|
|
|
|
CatOneAtCmdSend(CAT_ONE_LIPOPEN, 2000, CAT_ONE_WAIT_CONN);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_WAIT_CONN:
|
|
|
|
|
|
if(CatOne.TcpConnFlag) {
|
|
|
|
|
|
if(CatOne.GateWay->SvrRegFlag == false)
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_REG_SVR;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
else
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_REG_SVR: //注册服务器
|
|
|
|
|
|
ret = GateWayRegister(CatOneEthTxBuff);
|
|
|
|
|
|
rt_mq_send(CatOne.GateWay->NetSendData_MQ, CatOneEthTxBuff, ret);
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_WAIT_SEND:
|
|
|
|
|
|
result = rt_mq_recv(CatOne.GateWay->NetSendData_MQ, Payload, CAT_ONE_REV_LEN_MAX, 1000);
|
|
|
|
|
|
if(result == RT_EOK) {
|
|
|
|
|
|
CatOneEthTxLen = NetCommOrgData(CatOne.GateWay, Payload, CatOneEthTxBuff);
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_SEND_DATA;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
if(CatOne.Cat1Status == CAT_ONE_RESET || CatOne.Cat1Status == CAT_ONE_OFF) //外部命令执行,状态改变
|
2026-04-23 13:56:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
if(!CatOne.TcpConnFlag) {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_OFF;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
CatSendErrCnt++;
|
|
|
|
|
|
if(CatSendErrCnt > CAT1_ERR_RESET_DLY_MAX) {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_RESET;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CAT1_DBG_LOG("Cat1 has no data for a long time, Reset!\r\n");
|
|
|
|
|
|
CatSendErrCnt = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_SEND_DATA:
|
|
|
|
|
|
CatOne.AtCmdResendCnt = 3;
|
|
|
|
|
|
Cat1RevErrCnt++;
|
|
|
|
|
|
if(Cat1RevErrCnt > 10) {
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_RESET;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CAT1_DBG_LOG("Cat1 has no receive data for a long time, Reset!\r\n");
|
|
|
|
|
|
Cat1RevErrCnt = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
CatOneAtCmdSend(CAT_ONE_LIPSEND, 5000, CAT_ONE_REV_DATA);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_REV_DATA:
|
|
|
|
|
|
result = rt_sem_take(CatOneRev_Sem, CatOne.CatOne1mSDelayCnt);
|
|
|
|
|
|
if(result != RT_EOK) {
|
|
|
|
|
|
if(CatOne.TcpConnFlag == false) {
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 Rec Server Data Timeout!\r\n");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
Cat1RevErrCnt = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(CatOne.GateWay->SvrRegFlag == false) //设备没注册,关闭4G,等待下一次重新注册
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_OFF;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
else
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_CLOSE_TCP:
|
|
|
|
|
|
CatOne.AtCmdResendCnt = 3;
|
|
|
|
|
|
CatOneAtCmdSend(CAT_ONE_LTPCLOSE, 1000, CAT_ONE_OFF);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_OFF:
|
|
|
|
|
|
//CAT1_POW_OFF();
|
|
|
|
|
|
CAT1_RESET_SET();
|
|
|
|
|
|
CAT1_PWR_KEY_CLR();
|
|
|
|
|
|
rt_thread_delay(3000);
|
|
|
|
|
|
CAT1_PWR_KEY_SET();
|
|
|
|
|
|
CatSendErrCnt = 0;
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 Power Off!\r\n");
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_IDEL;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CatOne.ResetDelayCnt = CATONE_RESET_DELAY_TIME_MAX;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CAT_ONE_RESET:
|
|
|
|
|
|
CatSendErrCnt = 0;
|
|
|
|
|
|
CAT1_DBG_LOG("Cat1 Reset!\r\n");
|
|
|
|
|
|
CAT1_RESET_CLR();
|
|
|
|
|
|
CAT1_PWR_KEY_SET();
|
|
|
|
|
|
//CAT1_POW_ON();
|
|
|
|
|
|
rt_thread_delay(50);
|
|
|
|
|
|
CAT1_RESET_SET();
|
|
|
|
|
|
CAT1_PWR_KEY_CLR();
|
|
|
|
|
|
rt_thread_delay(1000);
|
|
|
|
|
|
CAT1_PWR_KEY_SET();
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_INIT;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CatOne.AtCmdIdx = 0;
|
|
|
|
|
|
rt_thread_delay(1000);
|
|
|
|
|
|
CatOne.GateWay->BatteryReadDlyCnt = 60;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EthLoopHandler(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
rt_err_t result;
|
|
|
|
|
|
|
2026-06-11 19:17:31 +08:00
|
|
|
|
switch(CatOne.EthStatus) {
|
|
|
|
|
|
case ETH_IDEL:
|
|
|
|
|
|
rt_thread_delay(1);
|
|
|
|
|
|
if(CatOne.EthResetDelayCnt > 0) {
|
|
|
|
|
|
CatOne.EthResetDelayCnt--;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
CatOne.EthStatus = ETH_RESET;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_RESET:
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Reset!\r\n");
|
|
|
|
|
|
ETH_RESET_CLR();
|
|
|
|
|
|
rt_thread_delay(10);
|
|
|
|
|
|
ETH_RESET_SET();
|
|
|
|
|
|
rt_thread_delay(2000); // 延长复位后稳定时间到2秒
|
2026-06-17 12:30:57 +08:00
|
|
|
|
ETHApplyNetPara(); // 配置EthNet网络参数
|
2026-06-11 19:17:31 +08:00
|
|
|
|
CatOne.EthStatus = ETH_WAIT_LINK;
|
|
|
|
|
|
CatOne.EthLinkWaitCnt = 0;
|
|
|
|
|
|
CatOne.EthFirstRegFlag = true; // 重置首次注册标志
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_WAIT_LINK:
|
2026-06-17 17:46:33 +08:00
|
|
|
|
if(CatOne.EthLinkWaitCnt == 0) {
|
|
|
|
|
|
/* 首次进入等待链路状态,等待模块完全启动 */
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Waiting for module ready...\r\n");
|
|
|
|
|
|
rt_thread_delay(2000);
|
|
|
|
|
|
}
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(ETH_LINK_GET() == Reset) {
|
2026-06-11 19:17:31 +08:00
|
|
|
|
CAT1_DBG_LOG("ETH Link OK!\r\n");
|
|
|
|
|
|
if(CatOne.GateWay->SvrRegFlag == false) {
|
|
|
|
|
|
CatOne.EthStatus = ETH_REG_SVR;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
CatOne.EthStatus = ETH_WAIT_SEND;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
CatOne.EthLinkWaitCnt++;
|
|
|
|
|
|
if(CatOne.EthLinkWaitCnt >= ETH_LINK_WAIT_TIME_MAX) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Link Timeout, Reset!\r\n");
|
|
|
|
|
|
CatOne.EthStatus = ETH_OFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
rt_thread_delay(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_REG_SVR:
|
|
|
|
|
|
{
|
|
|
|
|
|
// 首次注册时添加延迟,等待系统稳定
|
|
|
|
|
|
if(CatOne.EthFirstRegFlag) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH First Register, waiting for system stable...\r\n");
|
|
|
|
|
|
rt_thread_delay(ETH_FIRST_REG_DELAY);
|
|
|
|
|
|
CatOne.EthFirstRegFlag = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-23 13:56:52 +08:00
|
|
|
|
uint8_t ret = GateWayRegister(CatOneEthTxBuff);
|
|
|
|
|
|
rt_mq_send(CatOne.GateWay->NetSendData_MQ, CatOneEthTxBuff, ret);
|
2026-06-11 19:17:31 +08:00
|
|
|
|
CAT1_DBG_LOG("ETH Register Server...\r\n");
|
|
|
|
|
|
CatOne.EthStatus = ETH_WAIT_SEND;
|
|
|
|
|
|
CatOne.EthSendRetryCnt = 0; // 重置重试计数器
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
2026-06-11 19:17:31 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_WAIT_SEND:
|
|
|
|
|
|
result = rt_mq_recv(CatOne.GateWay->NetSendData_MQ, Payload, CAT_ONE_REV_LEN_MAX, 100);
|
|
|
|
|
|
if(result == RT_EOK) {
|
|
|
|
|
|
CatOneEthTxLen = NetCommOrgData(CatOne.GateWay, Payload, CatOneEthTxBuff);
|
|
|
|
|
|
CatOne.EthStatus = ETH_SEND_DATA;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
if(CatOne.EthStatus == ETH_RESET || CatOne.EthStatus == ETH_OFF)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if(ETH_LINK_GET() != Reset) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Link Lost!\r\n");
|
|
|
|
|
|
CatOne.EthStatus = ETH_OFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
rt_thread_delay(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_SEND_DATA:
|
|
|
|
|
|
HexToAscii(CatOneEthTxBuff, CommUnitSendASCII, CatOneEthTxLen);
|
|
|
|
|
|
EthRevTimeOutCnt = 0;
|
|
|
|
|
|
EthOrCat1UartSend((uint8_t *)CommUnitSendASCII, CatOneEthTxLen * 2);
|
|
|
|
|
|
CommUnitSendASCII[CatOneEthTxLen * 2] = 0;
|
|
|
|
|
|
CAT1_DBG_LOG("Eth Send: %s\r\n", CommUnitSendASCII);
|
|
|
|
|
|
|
|
|
|
|
|
CatOne.EthStatus = ETH_WAIT_RECV;
|
|
|
|
|
|
CatOne.EthRecvTimeoutCnt = 0;
|
|
|
|
|
|
CatOne.EthSendRetryCnt = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_WAIT_RECV:
|
|
|
|
|
|
rt_thread_delay(1);
|
|
|
|
|
|
CatOne.EthRecvTimeoutCnt++;
|
|
|
|
|
|
|
|
|
|
|
|
if(CatOne.EthRecvTimeoutCnt >= ETH_RECV_TIMEOUT_MAX) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Recv Timeout!\r\n");
|
|
|
|
|
|
CatOne.EthSendRetryCnt++;
|
|
|
|
|
|
if(CatOne.EthSendRetryCnt >= ETH_SEND_RETRY_MAX) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Send Retry Max, Reset!\r\n");
|
|
|
|
|
|
CatOne.EthStatus = ETH_OFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
if(CatOne.GateWay->SvrRegFlag == false) {
|
|
|
|
|
|
CatOne.EthStatus = ETH_REG_SVR;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
CatOne.EthStatus = ETH_WAIT_SEND;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(ETH_LINK_GET() != Reset) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Link Lost During Wait!\r\n");
|
|
|
|
|
|
CatOne.EthStatus = ETH_OFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(CatOne.GateWay->SvrRegFlag == true) {
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Register Success!\r\n");
|
|
|
|
|
|
CatOne.EthStatus = ETH_WAIT_SEND;
|
|
|
|
|
|
CatOne.EthRecvTimeoutCnt = 0;
|
|
|
|
|
|
CatOne.EthSendRetryCnt = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ETH_OFF:
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Power Off!\r\n");
|
2026-06-15 15:11:23 +08:00
|
|
|
|
//ETH_RESET_CLR();
|
|
|
|
|
|
//rt_thread_delay(3000);
|
|
|
|
|
|
//ETH_RESET_SET();
|
2026-06-11 19:17:31 +08:00
|
|
|
|
CatOne.EthStatus = ETH_IDEL;
|
|
|
|
|
|
CatOne.EthResetDelayCnt = ETH_RESET_DELAY_TIME_MAX;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
CatOne.EthStatus = ETH_RESET;
|
|
|
|
|
|
break;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CatOneEthSendQueue(uint8_t *sData, uint16_t sLen)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(CatOne.GateWay->SvrRegFlag == false)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
rt_mq_send(CatOne.GateWay->NetSendData_MQ, sData, sLen);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void CatOneInit(GateWayPara GateWay)
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(&CatOne, 0x00, sizeof(CatOne_t));
|
2026-06-15 18:38:41 +08:00
|
|
|
|
CatOne.Cat1Status = CAT_ONE_RESET;
|
2026-04-23 13:56:52 +08:00
|
|
|
|
CatOne.GateWay = GateWay;
|
|
|
|
|
|
CatOne.CatOneRevCallBack = GateWay->SvrRevCallBack;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOneEthRev_Thread_Entry(void *parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
rt_err_t result;
|
|
|
|
|
|
char RxBuffTemp[CAT_ONE_REV_LEN_MAX];
|
|
|
|
|
|
uint8_t HexData[CAT_ONE_REV_LEN_MAX / 2];
|
|
|
|
|
|
|
|
|
|
|
|
GateWayPara GateWay = (GateWayPara)parameter;
|
|
|
|
|
|
|
|
|
|
|
|
rt_kprintf("CatOneTthRev Thread is running!\r\n");
|
|
|
|
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
|
|
if(GateWay->ConfigPara.Comm == CATONE_COMM) {
|
|
|
|
|
|
result = rt_sem_take(CatOneIRQ_Sem, 500);
|
|
|
|
|
|
if(result == RT_EOK) {
|
|
|
|
|
|
memcpy(RxBuffTemp, CatOneEthRxBuff, CatOneEthRxLen);
|
|
|
|
|
|
RxBuffTemp[CatOneEthRxLen] = 0;
|
|
|
|
|
|
CatOneAtCmdAnalyze(RxBuffTemp);
|
|
|
|
|
|
memset(CatOneEthRxBuff, 0x00, CAT_ONE_REV_LEN_MAX);
|
|
|
|
|
|
CatOneEthRxLen = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
//CatOneEthRxLen = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(GateWay->ConfigPara.Comm == ETH_COMM) {
|
|
|
|
|
|
result = rt_sem_take(EthIRQ_Sem, 500);
|
|
|
|
|
|
if(result == RT_EOK) {
|
|
|
|
|
|
memcpy(RxBuffTemp, CatOneEthRxBuff, CatOneEthRxLen);
|
|
|
|
|
|
RxBuffTemp[CatOneEthRxLen] = 0;
|
|
|
|
|
|
CAT1_DBG_LOG("Eth Rev: %s\r\n",RxBuffTemp);
|
|
|
|
|
|
memset(HexData, 0x00, CatOneEthRxLen / 2);
|
|
|
|
|
|
uint8_t ret = AsciiToHex(RxBuffTemp, HexData, CatOneEthRxLen);
|
|
|
|
|
|
if(ret > 0)
|
|
|
|
|
|
GateWay->SvrRevCallBack(GateWay, HexData, ret);
|
|
|
|
|
|
memset(CatOneEthRxBuff, 0x00, CAT_ONE_REV_LEN_MAX);
|
|
|
|
|
|
CatOneEthRxLen = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
//CatOneEthRxLen = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatOne_Eth_Thread_Entry(void *parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
GateWayPara GateWay = (GateWayPara)parameter;
|
|
|
|
|
|
|
|
|
|
|
|
CatOneRev_Sem = rt_sem_create("cat1r_sem", 0, RT_IPC_FLAG_FIFO);
|
|
|
|
|
|
if(CatOneRev_Sem == RT_NULL) {
|
|
|
|
|
|
rt_kprintf("CatOne Sem Create Failed!\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EthIRQ_Sem = rt_sem_create("eth_sem", 0, RT_IPC_FLAG_FIFO);
|
|
|
|
|
|
if(EthIRQ_Sem == RT_NULL) {
|
|
|
|
|
|
rt_kprintf("Eth Sem Create Failed!\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CatOneIRQ_Sem = rt_sem_create("cat1_sem", 0, RT_IPC_FLAG_FIFO);
|
|
|
|
|
|
if(CatOneIRQ_Sem == RT_NULL) {
|
|
|
|
|
|
rt_kprintf("CatOneIRQ Sem Create Failed!\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CatOneInit(GateWay);
|
|
|
|
|
|
ETH_RESET_CLR();
|
|
|
|
|
|
rt_thread_delay(10);
|
|
|
|
|
|
ETH_RESET_SET();
|
|
|
|
|
|
Cat1Rev_Thread = rt_thread_create("Cat1Rev", CatOneEthRev_Thread_Entry, parameter, 3000, 3, 20);
|
|
|
|
|
|
if (Cat1Rev_Thread != RT_NULL) {
|
|
|
|
|
|
rt_thread_startup(Cat1Rev_Thread);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
rt_kprintf("CatOneRev Thread Create Failed! Exit...\r\n");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
rt_kprintf("CatOne Thread is running!\r\n");
|
|
|
|
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
|
|
//rt_mutex_take(GateWay->UartRevMutex, RT_WAITING_FOREVER);
|
|
|
|
|
|
if(GateWay->ConfigPara.Comm == CATONE_COMM)
|
|
|
|
|
|
CatOneLoopHandler();
|
|
|
|
|
|
else if(GateWay->ConfigPara.Comm == ETH_COMM)
|
|
|
|
|
|
EthLoopHandler();
|
|
|
|
|
|
else
|
|
|
|
|
|
rt_thread_delay(1);
|
|
|
|
|
|
//rt_mutex_release(GateWay->UartRevMutex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void EthOrCat1RxIrqCallback(uint8_t rData)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(EthRevTimeOutCnt == 0)
|
|
|
|
|
|
CatOneEthRxLen = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if(CatOneEthRxLen < CAT_ONE_REV_LEN_MAX) {
|
|
|
|
|
|
CatOneEthRxBuff[CatOneEthRxLen++] = rData;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EthRevTimeOutCnt = 3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EthRxOverhandler(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(EthRevTimeOutCnt > 0)
|
|
|
|
|
|
EthRevTimeOutCnt--;
|
2026-06-17 12:30:57 +08:00
|
|
|
|
|
2026-04-23 13:56:52 +08:00
|
|
|
|
if(CatOneEthRxLen > 5 && EthRevTimeOutCnt == 0) {
|
|
|
|
|
|
EthRevTimeOutCnt = 20;
|
|
|
|
|
|
if(CatOne.GateWay->ConfigPara.Comm == CATONE_COMM)
|
|
|
|
|
|
rt_sem_release(CatOneIRQ_Sem);
|
|
|
|
|
|
else
|
|
|
|
|
|
rt_sem_release(EthIRQ_Sem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CatReadImeiOrSim(char *Imei, char *Sim)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(Imei != NULL) {
|
|
|
|
|
|
memcpy(Imei, CatOne.IMEI, 15);
|
|
|
|
|
|
Imei[15] = 0x00;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(Sim != NULL) {
|
|
|
|
|
|
memcpy(Sim, CatOne.SIM, 20);
|
|
|
|
|
|
Sim[20] = 0x00;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-15 18:38:41 +08:00
|
|
|
|
|
|
|
|
|
|
void CatOneTriggerRegister(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
CatOne.Cat1Status = CAT_ONE_REG_SVR;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ETHTriggerRegister(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
CatOne.EthStatus = ETH_REG_SVR;
|
|
|
|
|
|
}
|
2026-06-17 12:30:57 +08:00
|
|
|
|
|
|
|
|
|
|
void ETHApplyNetPara(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t cmdBuf[128];
|
|
|
|
|
|
uint16_t idx = 0;
|
|
|
|
|
|
GWConfigPara_t *pCfg = (GWConfigPara_t *)&CatOne.GateWay->ConfigPara;
|
|
|
|
|
|
|
|
|
|
|
|
/* EthNet模块二进制命令协议:
|
|
|
|
|
|
* 识别流(10B): ED F2 A3 56 CA DB 91 84 B0 D7
|
|
|
|
|
|
* 命令类型00: 读参数/状态
|
|
|
|
|
|
* 命令类型03: 写参数并保存到Flash
|
|
|
|
|
|
* 命令类型07: 写参数+保存+重启模块
|
|
|
|
|
|
*
|
|
|
|
|
|
* 参数偏移: 0x00=LocalIP(4B), 0x04=NetMask(4B), 0x08=Gateway(4B),
|
|
|
|
|
|
* 0x0C=DestIP(4B), 0x10=LocalPort(2B), 0x12=DestPort(2B),
|
|
|
|
|
|
* 0x14=WorkMode(1B: 0=TCP Server,1=TCP Client,2=UDP),
|
|
|
|
|
|
* 0x38=DHCP(1B: 0=静态,1=DHCP)
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* 步骤0: 检查系统是否初始化完毕
|
|
|
|
|
|
* 发送命令: ed f2 a3 56 ca db 91 84 b0 d7 00 3d 01
|
|
|
|
|
|
* 如果返回00或01则表示初始化完成,可以进行写参数
|
|
|
|
|
|
*/
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Check init...");
|
|
|
|
|
|
for(int waitCnt = 0; waitCnt < 50; waitCnt++) {
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
|
cmdBuf[idx++] = 0xED; cmdBuf[idx++] = 0xF2; cmdBuf[idx++] = 0xA3; cmdBuf[idx++] = 0x56;
|
|
|
|
|
|
cmdBuf[idx++] = 0xCA; cmdBuf[idx++] = 0xDB; cmdBuf[idx++] = 0x91; cmdBuf[idx++] = 0x84;
|
|
|
|
|
|
cmdBuf[idx++] = 0xB0; cmdBuf[idx++] = 0xD7;
|
|
|
|
|
|
cmdBuf[idx++] = 0x00; /* 读参数 */
|
|
|
|
|
|
cmdBuf[idx++] = 0x3D; /* 偏移: 0x3D (Status) */
|
|
|
|
|
|
cmdBuf[idx++] = 0x01; /* 长度: 1字节 */
|
|
|
|
|
|
EthOrCat1UartSend(cmdBuf, idx);
|
|
|
|
|
|
rt_thread_delay(100);
|
|
|
|
|
|
/* 实际应该检查返回值,这里简单等待后继续 */
|
|
|
|
|
|
}
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Init check done");
|
|
|
|
|
|
|
|
|
|
|
|
/* 步骤1: 一次性写入从0x00开始的网络参数(LocalIP~WorkMode, 共0x15字节)
|
|
|
|
|
|
* 偏移0x00~0x14: LocalIP(4) + NetMask(4) + Gateway(4) + DestIP(4) + LocalPort(2) + DestPort(2) + WorkMode(1)
|
|
|
|
|
|
*/
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
|
cmdBuf[idx++] = 0xED; cmdBuf[idx++] = 0xF2; cmdBuf[idx++] = 0xA3; cmdBuf[idx++] = 0x56;
|
|
|
|
|
|
cmdBuf[idx++] = 0xCA; cmdBuf[idx++] = 0xDB; cmdBuf[idx++] = 0x91; cmdBuf[idx++] = 0x84;
|
|
|
|
|
|
cmdBuf[idx++] = 0xB0; cmdBuf[idx++] = 0xD7;
|
2026-06-17 17:46:33 +08:00
|
|
|
|
cmdBuf[idx++] = 0x01; /* 命令类型: 写参数,部分参数修改后会自动重启 */
|
2026-06-17 12:30:57 +08:00
|
|
|
|
cmdBuf[idx++] = 0x00; /* 偏移: 0x00 */
|
|
|
|
|
|
cmdBuf[idx++] = 0x15; /* 长度: 21字节 */
|
|
|
|
|
|
|
|
|
|
|
|
/* Local IP */
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.IpAddr[0];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.IpAddr[1];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.IpAddr[2];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.IpAddr[3];
|
|
|
|
|
|
/* Net Mask */
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.SubnetMask[0];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.SubnetMask[1];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.SubnetMask[2];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.SubnetMask[3];
|
|
|
|
|
|
/* Gateway */
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.Gateway[0];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.Gateway[1];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.Gateway[2];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.Gateway[3];
|
|
|
|
|
|
/* Dest IP */
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.DestIp[0];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.DestIp[1];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.DestIp[2];
|
|
|
|
|
|
cmdBuf[idx++] = pCfg->EthNet.DestIp[3];
|
|
|
|
|
|
/* Local Port (大端) */
|
|
|
|
|
|
cmdBuf[idx++] = (uint8_t)(pCfg->EthNet.IpPort >> 8);
|
|
|
|
|
|
cmdBuf[idx++] = (uint8_t)(pCfg->EthNet.IpPort & 0xFF);
|
|
|
|
|
|
/* Dest Port (大端) */
|
|
|
|
|
|
cmdBuf[idx++] = (uint8_t)(pCfg->EthNet.DestPort >> 8);
|
|
|
|
|
|
cmdBuf[idx++] = (uint8_t)(pCfg->EthNet.DestPort & 0xFF);
|
|
|
|
|
|
/* Work Mode: 0=TCP Server, 1=TCP Client, 2=UDP */
|
|
|
|
|
|
if(pCfg->EthNet.WorkMode == ETH_MODE_TCP_SERVER) {
|
|
|
|
|
|
cmdBuf[idx++] = 0x00;
|
|
|
|
|
|
} else if(pCfg->EthNet.WorkMode == ETH_MODE_TCP_CLIENT) {
|
|
|
|
|
|
cmdBuf[idx++] = 0x01;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cmdBuf[idx++] = 0x02;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Write IP/Mode, len=%d", idx);
|
|
|
|
|
|
EthOrCat1UartSend(cmdBuf, idx);
|
|
|
|
|
|
rt_thread_delay(500);
|
|
|
|
|
|
|
|
|
|
|
|
/* 步骤2: 写入DHCP/IP模式 (偏移0x38, 1字节)
|
|
|
|
|
|
* 0=静态IP, 1=DHCP
|
|
|
|
|
|
*/
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
|
cmdBuf[idx++] = 0xED; cmdBuf[idx++] = 0xF2; cmdBuf[idx++] = 0xA3; cmdBuf[idx++] = 0x56;
|
|
|
|
|
|
cmdBuf[idx++] = 0xCA; cmdBuf[idx++] = 0xDB; cmdBuf[idx++] = 0x91; cmdBuf[idx++] = 0x84;
|
|
|
|
|
|
cmdBuf[idx++] = 0xB0; cmdBuf[idx++] = 0xD7;
|
2026-06-17 17:46:33 +08:00
|
|
|
|
cmdBuf[idx++] = 0x01; /* 命令类型: 写参数,DHCP修改后会自动重启 */
|
2026-06-17 12:30:57 +08:00
|
|
|
|
cmdBuf[idx++] = 0x38; /* 偏移: 0x38 (DHCP en) */
|
|
|
|
|
|
cmdBuf[idx++] = 0x01; /* 长度: 1字节 */
|
|
|
|
|
|
cmdBuf[idx++] = (pCfg->EthNet.IpMode == ETH_IP_DHCP) ? 0x01 : 0x00;
|
|
|
|
|
|
|
|
|
|
|
|
CAT1_DBG_LOG("ETH Write DHCP=%d", cmdBuf[idx - 1]);
|
|
|
|
|
|
EthOrCat1UartSend(cmdBuf, idx);
|
2026-06-17 17:46:33 +08:00
|
|
|
|
rt_thread_delay(3000); /* 等待模块重启 */
|
2026-06-17 12:30:57 +08:00
|
|
|
|
|
2026-06-17 17:46:33 +08:00
|
|
|
|
/* 注意:不要向DevID(偏移0x1F)区域写入任意数据,否则根据手册说明,
|
|
|
|
|
|
* 如果写入的ID不正确,设备会丢弃所有其他写入的参数
|
|
|
|
|
|
* 模块会在下次上电时自动使用Flash中保存的参数工作
|
2026-06-17 12:30:57 +08:00
|
|
|
|
*/
|
|
|
|
|
|
}
|