Files
GateWay/Project/GateWay/source/User/Src/EthTask.c
T
YuanHongbin 4cf73b5a0f fix(eth): 增加服务器无应答兜底复位+链路断开清除注册标志
1. 新增SendNoDataCnt计数器: Much=ETH时每次发送累加, 连续>10次
   无任何下行数据回应(0x7A帧)则置MuchRegFlag=false并ETH_RESET复位,
   解决服务器在线但不应答时网关一直沉默无感知的问题
2. ETH_WAIT_RECV和ETH_WAIT_SEND检测到物理链路断开时立即清除
   MuchRegFlag, 保证重连后强制重新注册, para显示为false
3. ETH_RESET和ETH_OFF时清零SendNoDataCnt, 避免计数器残留
4. 复位后MuchRegFlag=false使ETH_REG_SVR真正等待注册响应并重试,
   修复原逻辑中复位后注册流程被MuchRegFlag=true跳过的问题
2026-08-20 16:47:56 +08:00

349 lines
8.2 KiB
C

#include "EthTask.h"
#include "Public.h"
#include "DebugCmd.h"
static rt_sem_t EthIRQ_Sem = RT_NULL;
static rt_thread_t EthRev_Thread = RT_NULL;
static EthTask_t Eth;
static char EthRxBuff[ETH_RX_LEN_MAX];
static uint16_t EthRxLen;
static uint8_t EthRevTimeOutCnt;
static uint8_t Payload[ETH_RX_LEN_MAX];
static char CommUnitSendASCII[ETH_RX_LEN_MAX * 2];
static bool EthDispEn = false;
#define ETH_DBG_LOG(...) { if(EthDispEn) Debug_Printf(__VA_ARGS__);}
void ETHOnOff(bool OnOff)
{
EthDispEn = OnOff;
if(OnOff)
Debug_Printf("\r\nEth Display Enable!\r\n\r\n");
else
Debug_Printf("\r\nEth Display Disable!\r\n\r\n");
}
void ETHStop(void)
{
Eth.Status = ETH_OFF;
}
void ETHReset(void)
{
Eth.Status = ETH_RESET;
}
void ETHTriggerRegister(void)
{
Eth.Status = ETH_REG_SVR;
}
static int GateWayRegister(uint8_t *TxBuff)
{
uint16_t UnitCommCnt = 0;
uint8_t *p = &TxBuff[0];
uint16_t len = 5;
if(Eth.GateWay->ConfigPara.Rs485Ch1.CommUnitEnable == true && Eth.GateWay->ConfigPara.Rs485Ch1.Enable == true) {
UnitCommCnt++;
memcpy(&p[len], Eth.GateWay->ConfigPara.Rs485Ch1.CUPara.Para.Mac[0], 6);
len += 6;
}
if(Eth.GateWay->ConfigPara.Rs485Ch2.CommUnitEnable == true && Eth.GateWay->ConfigPara.Rs485Ch2.Enable == true) {
UnitCommCnt++;
memcpy(&p[len], Eth.GateWay->ConfigPara.Rs485Ch2.CUPara.Para.Mac[0], 6);
len += 6;
}
for(int i = 0; i < COMMUNIT_NUM_MAX; i++) {
if(Eth.GateWay->ConfigPara.CommUnitArray[i].RegFlag == true) {
for(int j = 0; j < Eth.GateWay->ConfigPara.CommUnitArray[i].SensorN; j++)
{
memcpy(&p[len], Eth.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 EthLoopHandler(void)
{
rt_err_t result;
switch(Eth.Status) {
case ETH_IDEL:
rt_thread_delay(1);
if(Eth.ResetDelayCnt > 0) {
Eth.ResetDelayCnt--;
}
else {
Eth.Status = ETH_RESET;
}
break;
case ETH_RESET:
ETH_DBG_LOG("ETH Reset!\r\n");
Eth.SendNoDataCnt = 0;
ETH_RESET_CLR();
rt_thread_delay(10);
ETH_RESET_SET();
rt_thread_delay(2000);
Eth.Status = ETH_WAIT_LINK;
Eth.LinkWaitCnt = 0;
Eth.FirstRegFlag = true;
break;
case ETH_WAIT_LINK:
if(Eth.LinkWaitCnt == 0) {
ETH_DBG_LOG("ETH Waiting for module ready...\r\n");
rt_thread_delay(2000);
}
if(ETH_LINK_GET() == Reset) {
ETH_DBG_LOG("ETH Link OK!\r\n");
if(Eth.GateWay->ConfigPara.Much != CH_ETH) {
GateWayRegister(Payload);
Eth.TxLen = NetCommOrgData(Eth.GateWay, Payload, Eth.TxBuff);
HexToAscii(Eth.TxBuff, CommUnitSendASCII, Eth.TxLen);
CommUnitSendASCII[Eth.TxLen * 2] = 0;
EthUartSend((uint8_t *)CommUnitSendASCII, Eth.TxLen * 2);
ETH_DBG_LOG("Eth Send Reg: %s\r\n", CommUnitSendASCII);
Eth.Status = ETH_WAIT_RECV;
Eth.RecvTimeoutCnt = 0;
Eth.SendRetryCnt = 0;
}
else {
Eth.Status = ETH_REG_SVR;
}
}
else {
Eth.LinkWaitCnt++;
if(Eth.LinkWaitCnt >= ETH_LINK_WAIT_TIME_MAX) {
ETH_DBG_LOG("ETH Link Timeout, Reset!\r\n");
Eth.Status = ETH_OFF;
}
rt_thread_delay(1);
}
break;
case ETH_REG_SVR:
{
if(Eth.FirstRegFlag) {
ETH_DBG_LOG("ETH First Register, waiting for system stable...\r\n");
rt_thread_delay(ETH_FIRST_REG_DELAY);
Eth.FirstRegFlag = false;
Eth.SendRetryCnt = 0;
}
GateWayRegister(Payload);
Eth.TxLen = NetCommOrgData(Eth.GateWay, Payload, Eth.TxBuff);
HexToAscii(Eth.TxBuff, CommUnitSendASCII, Eth.TxLen);
CommUnitSendASCII[Eth.TxLen * 2] = 0;
EthUartSend((uint8_t *)CommUnitSendASCII, Eth.TxLen * 2);
ETH_DBG_LOG("Eth Send Reg: %s\r\n", CommUnitSendASCII);
Eth.Status = ETH_WAIT_RECV;
Eth.RecvTimeoutCnt = 0;
}
break;
case ETH_WAIT_SEND:
result = rt_mq_recv(ChannelMQ(*Eth.GateWay, CH_ETH), Payload, ETH_RX_LEN_MAX, 100);
if(result == RT_EOK) {
Eth.TxLen = NetCommOrgData(Eth.GateWay, Payload, Eth.TxBuff);
Eth.Status = ETH_SEND_DATA;
}
else {
if(Eth.Status == ETH_RESET || Eth.Status == ETH_OFF)
return;
if(ETH_LINK_GET() != Reset) {
ETH_DBG_LOG("ETH Link Lost!\r\n");
Eth.GateWay->MuchRegFlag = false;
Eth.Status = ETH_OFF;
}
else {
rt_thread_delay(1);
}
}
break;
case ETH_SEND_DATA:
if(Eth.GateWay->ConfigPara.Much == CH_ETH) {
Eth.SendNoDataCnt++;
if(Eth.SendNoDataCnt > ETH_SEND_NO_DATA_MAX) {
ETH_DBG_LOG("ETH has no receive data for a long time, Reset!\r\n");
Eth.SendNoDataCnt = 0;
Eth.GateWay->MuchRegFlag = false;
Eth.Status = ETH_RESET;
break;
}
}
HexToAscii(Eth.TxBuff, CommUnitSendASCII, Eth.TxLen);
EthRevTimeOutCnt = 0;
EthUartSend((uint8_t *)CommUnitSendASCII, Eth.TxLen * 2);
CommUnitSendASCII[Eth.TxLen * 2] = 0;
ETH_DBG_LOG("Eth Send: %s\r\n", CommUnitSendASCII);
Eth.Status = ETH_WAIT_RECV;
Eth.RecvTimeoutCnt = 0;
Eth.SendRetryCnt = 0;
break;
case ETH_WAIT_RECV:
if(Eth.GateWay->ConfigPara.Much != CH_ETH) {
Eth.Status = ETH_WAIT_SEND;
break;
}
rt_thread_delay(1);
Eth.RecvTimeoutCnt++;
if(Eth.RecvTimeoutCnt >= ETH_RECV_TIMEOUT_MAX) {
ETH_DBG_LOG("ETH Recv Timeout!\r\n");
Eth.SendRetryCnt++;
if(Eth.SendRetryCnt >= ETH_SEND_RETRY_MAX) {
ETH_DBG_LOG("ETH Send Retry Max, Reset!\r\n");
Eth.Status = ETH_OFF;
}
else {
if(Eth.GateWay->MuchRegFlag == false) {
Eth.Status = ETH_REG_SVR;
}
else {
Eth.Status = ETH_WAIT_SEND;
}
}
}
if(ETH_LINK_GET() != Reset) {
ETH_DBG_LOG("ETH Link Lost During Wait!\r\n");
Eth.GateWay->MuchRegFlag = false;
Eth.Status = ETH_OFF;
}
if(Eth.GateWay->MuchRegFlag == true) {
ETH_DBG_LOG("ETH Register Success!\r\n");
Eth.Status = ETH_WAIT_SEND;
Eth.RecvTimeoutCnt = 0;
Eth.SendRetryCnt = 0;
}
break;
case ETH_OFF:
ETH_DBG_LOG("ETH Power Off!\r\n");
Eth.SendNoDataCnt = 0;
Eth.Status = ETH_IDEL;
Eth.ResetDelayCnt = ETH_RESET_DELAY_TIME_MAX;
break;
default:
Eth.Status = ETH_RESET;
break;
}
}
static void EthInit(GateWayPara GateWay)
{
memset(&Eth, 0x00, sizeof(EthTask_t));
Eth.Status = ETH_RESET;
Eth.GateWay = GateWay;
}
void EthIrqCallbackHandler(uint8_t rData)
{
if(EthRevTimeOutCnt == 0)
EthRxLen = 0;
if(EthRxLen < ETH_RX_LEN_MAX) {
EthRxBuff[EthRxLen++] = rData;
}
EthRevTimeOutCnt = 3;
}
void EthOverHandler(void)
{
if(EthRevTimeOutCnt > 0)
EthRevTimeOutCnt--;
if(EthRxLen > 0 && EthRevTimeOutCnt == 0) {
EthRevTimeOutCnt = 20;
rt_sem_release(EthIRQ_Sem);
}
}
static void EthRev_Thread_Entry(void *parameter)
{
rt_err_t result;
char RxBuffTemp[ETH_RX_LEN_MAX];
uint8_t HexData[ETH_RX_LEN_MAX / 2];
GateWayPara GateWay = (GateWayPara)parameter;
rt_kprintf("EthRev Thread is running!\r\n");
while(1) {
result = rt_sem_take(EthIRQ_Sem, 500);
if(result == RT_EOK || EthRxLen > 1) {
if(EthRxLen == 0) continue;
memcpy(RxBuffTemp, EthRxBuff, EthRxLen);
RxBuffTemp[EthRxLen] = 0;
memset(HexData, 0x00, EthRxLen / 2);
uint8_t ret = AsciiToHex(RxBuffTemp, HexData, EthRxLen);
if(ret > 0 && HexData[0] == 0x7A) {
Eth.SendNoDataCnt = 0;
if(GateWay->ConfigPara.Much == CH_ETH)
GateWay->MuchRevCallBack(GateWay, HexData, ret);
else
GateWay->AuchRevCallBack(GateWay, HexData, ret);
}
else if(EthRxLen > 1) {
DebugAnalyze(GateWay, (uint8_t *)RxBuffTemp, EthRxLen);
}
memset(EthRxBuff, 0x00, ETH_RX_LEN_MAX);
EthRxLen = 0;
}
}
}
void Eth_Thread_Entry(void *parameter)
{
GateWayPara GateWay = (GateWayPara)parameter;
EthIRQ_Sem = rt_sem_create("ethi_sem", 0, RT_IPC_FLAG_FIFO);
if(EthIRQ_Sem == RT_NULL) {
rt_kprintf("EthIRQ Sem Create Failed!\r\n");
}
EthInit(GateWay);
ETH_RESET_CLR();
rt_thread_delay(10);
ETH_RESET_SET();
EthRev_Thread = rt_thread_create("EthRev", EthRev_Thread_Entry, parameter, 3000, 3, 20);
if (EthRev_Thread != RT_NULL) {
rt_thread_startup(EthRev_Thread);
}
else {
rt_kprintf("EthRev Thread Create Failed! Exit...\r\n");
return;
}
rt_kprintf("Eth Thread is running!\r\n");
while(1) {
if(!ChannelIsActive(GateWay->ConfigPara, CH_ETH)) {
rt_thread_delay(100);
continue;
}
EthLoopHandler();
}
}