ajustes udp

This commit is contained in:
Diego Freitas 2026-03-05 13:53:30 -03:00
parent c95564d49f
commit 2b4505d98a
4 changed files with 82 additions and 58 deletions

View File

@ -108,6 +108,8 @@ namespace AgroBase.Forms
PythonService.EncerrarProcessos();
Variaveis.StopUdpChannel();
foreach (var Disp in Variaveis.DispositivosConectados)
{
Disp.EnviarProtocolosConfiguracao(false);

View File

@ -1709,7 +1709,8 @@ namespace AgroBase.Models
if (topico != null && !string.IsNullOrEmpty(msg))
{
await Variaveis.MqttServiceBase.PublishAsync(topico, msg);
Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.UltimoEnvioLog = DateTime.Now;
if (Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura != null)
Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.UltimoEnvioLog = DateTime.Now;
}
}

View File

@ -199,24 +199,28 @@ namespace AgroBase.Models
private static AsyncTaskTimerModel _tmrUdpWatchdog;
private const int FAILSAFE_MS = 400;
private const int UDP_RESTART_MS = 2000;
private const int UDP_RESTART_MS = 5000;
public static void IniciarUDP()
{
StartUdpChannel();
_tmrFailSafe?.Dispose();
_tmrFailSafe = new AsyncTaskTimerModel("tmrFailSafe", tmrFailSafe_Tick, 100);
_tmrFailSafe.Start();
_tmrUdpWatchdog?.Dispose();
_tmrUdpWatchdog = new AsyncTaskTimerModel("tmrUdpWatchdog", tmrUdpWatchdog_Tick, 250);
_tmrUdpWatchdog.Start();
}
private static void StartUdpChannel()
{
StopUdpChannel();
//StopUdpChannel();
UdpChannel?.Stop();
UdpChannel?.Dispose();
UdpChannel = new UdpReliableChannel();
UdpChannel.Start(VariaveisPortas.Ethernet_UDP_RX);
@ -231,6 +235,9 @@ namespace AgroBase.Models
{
try
{
_tmrFailSafe?.Dispose();
_tmrUdpWatchdog?.Dispose();
UdpChannel?.Stop();
UdpChannel?.Dispose();
}
@ -249,6 +256,8 @@ namespace AgroBase.Models
return;
}
Console.WriteLine("[UDP] Commnad");
// Só controle entra daqui
if (type != UdpReliableChannel.TYPE_COMMAND) return;
@ -375,6 +384,7 @@ namespace AgroBase.Models
}
catch { }
Console.WriteLine("[UDP] Tentando reconectar...");
// Reinicia o canal
StartUdpChannel();

View File

@ -1,6 +1,4 @@
using AgroBase.Models;
using AgroMonitor;
using System;
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
@ -10,7 +8,7 @@ using System.Threading.Tasks;
public sealed class UdpReliableChannel : IDisposable
{
public const ushort MAGIC = 0xA711;
public const byte TYPE_COMMAND = 0x7F;
public const byte TYPE_COMMAND = 0x01;
public const byte TYPE_HEARTBEAT = 0x7F;
public int AckTimeoutMs { get; set; } = 120;
@ -95,7 +93,7 @@ public sealed class UdpReliableChannel : IDisposable
try
{
if (_rxThread != null && _rxThread.IsAlive)
_rxThread.Join(500);
_rxThread.Join(2000); // ou sem timeout se preferir travar até fechar
}
catch { }
@ -272,62 +270,75 @@ public sealed class UdpReliableChannel : IDisposable
{
var from = new IPEndPoint(IPAddress.Any, 0);
while (_running)
while (true)
{
byte[] data = null;
UdpClient udp;
lock (_sockLock) udp = _udp;
if (!_running || udp == null) break;
try
{
data = _udp.Receive(ref from); // bloqueia
if (udp.Available == 0)
{
Thread.Sleep(30);
continue;
}
var data = udp.Receive(ref from);
if (data == null || data.Length < 12) continue;
ushort magic = (ushort)((data[0] << 8) | data[1]);
if (magic != MAGIC) continue;
byte type = data[2];
byte flags = data[3];
uint seq = ReadU32BE(data, 4);
int payloadLen = data.Length - 12;
byte[] payload = new byte[payloadLen];
if (payloadLen > 0)
Buffer.BlockCopy(data, 12, payload, 0, payloadLen);
// ACK
if (type == 0xFF)
{
if (payloadLen >= 4)
{
uint ackSeq = ReadU32BE(payload, 0);
var h = OnAck;
if (h != null) h(ackSeq);
TaskCompletionSource<bool> tcs;
if (_pendingAck.TryGetValue(ackSeq, out tcs))
tcs.TrySetResult(true);
}
continue;
}
// newest wins
if (seq <= _lastSeqRx) continue;
_lastSeqRx = seq;
var handler = OnPacket;
if (handler != null)
handler(type, payload, from);
// responde ACK se pedido
if ((flags & 1) != 0)
{
try { SendAckAsync(from, seq); }
catch { }
}
}
catch
catch (ObjectDisposedException)
{
break; // Stop()
}
catch (SocketException)
{
if (!_running) break;
continue;
}
if (data == null || data.Length < 12) continue;
ushort magic = (ushort)((data[0] << 8) | data[1]);
if (magic != MAGIC) continue;
byte type = data[2];
byte flags = data[3];
uint seq = ReadU32BE(data, 4);
int payloadLen = data.Length - 12;
byte[] payload = new byte[payloadLen];
if (payloadLen > 0)
Buffer.BlockCopy(data, 12, payload, 0, payloadLen);
// ACK
if (type == 0xFF)
{
if (payloadLen >= 4)
{
uint ackSeq = ReadU32BE(payload, 0);
var h = OnAck;
if (h != null) h(ackSeq);
TaskCompletionSource<bool> tcs;
if (_pendingAck.TryGetValue(ackSeq, out tcs))
tcs.TrySetResult(true);
}
continue;
}
// newest wins
if (seq <= _lastSeqRx) continue;
_lastSeqRx = seq;
var handler = OnPacket;
if (handler != null)
handler(type, payload, from);
// responde ACK se pedido
if ((flags & 1) != 0)
{
try { SendAckAsync(from, seq); }
catch { }
// erro real (raro). pode logar se quiser
}
}
}