From 2b4505d98a5b5408a82f1377c3bd16816e2f887a Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Thu, 5 Mar 2026 13:53:30 -0300 Subject: [PATCH] ajustes udp --- AgroBase/AgroBase/Forms/frmInstancial.cs | 2 + .../Models/Operacoes/OperacaoModel.cs | 3 +- AgroBase/AgroBase/Models/Variaveis.cs | 14 +- .../AgroBase/Services/UdpReliableChannel.cs | 121 ++++++++++-------- 4 files changed, 82 insertions(+), 58 deletions(-) diff --git a/AgroBase/AgroBase/Forms/frmInstancial.cs b/AgroBase/AgroBase/Forms/frmInstancial.cs index c5de4459a..80fc81833 100644 --- a/AgroBase/AgroBase/Forms/frmInstancial.cs +++ b/AgroBase/AgroBase/Forms/frmInstancial.cs @@ -108,6 +108,8 @@ namespace AgroBase.Forms PythonService.EncerrarProcessos(); + Variaveis.StopUdpChannel(); + foreach (var Disp in Variaveis.DispositivosConectados) { Disp.EnviarProtocolosConfiguracao(false); diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index 8d32aa788..b20c1bf2d 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -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; } } diff --git a/AgroBase/AgroBase/Models/Variaveis.cs b/AgroBase/AgroBase/Models/Variaveis.cs index 8a867b304..b80783174 100644 --- a/AgroBase/AgroBase/Models/Variaveis.cs +++ b/AgroBase/AgroBase/Models/Variaveis.cs @@ -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(); diff --git a/AgroBase/AgroBase/Services/UdpReliableChannel.cs b/AgroBase/AgroBase/Services/UdpReliableChannel.cs index 1ac1b4763..f4faf212b 100644 --- a/AgroBase/AgroBase/Services/UdpReliableChannel.cs +++ b/AgroBase/AgroBase/Services/UdpReliableChannel.cs @@ -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 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 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 } } }