From 7f7ea84bd22eb91c5c4a8bb0d902aa9f089cddc5 Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Mon, 8 Dec 2025 14:37:55 -0300 Subject: [PATCH] novos arquivos para o fluxo can --- AgroBase/AgroBase/Models/Enums.cs | 1 + .../Models/Operacoes/OperacaoModel.cs | 22 +++++--- AgroBase/AgroBase/Services/CANService.cs | 6 +++ .../AgroBase/Services/CANServiceSerial.cs | 51 ++++++++++++++----- .../AgroBase/Services/CANServiceWaveshare.cs | 42 +++++++++++---- .../Operadores/HealthWorkerService.cs | 14 +++++ AgroBase/AgroBase/Services/SerialService.cs | 2 +- .../Scripts/workers/health_worker/main.py | 2 + .../Python/Scripts/workers/shared/enums.py | 14 ++--- .../OperationControl/Windows/MainWindow.xaml | 1 + .../Windows/MainWindow.xaml.cs | 15 +++++- Firmware/Modulos/Enuns.h | 7 +++ 12 files changed, 142 insertions(+), 35 deletions(-) diff --git a/AgroBase/AgroBase/Models/Enums.cs b/AgroBase/AgroBase/Models/Enums.cs index 140b39620..a32754bec 100644 --- a/AgroBase/AgroBase/Models/Enums.cs +++ b/AgroBase/AgroBase/Models/Enums.cs @@ -75,6 +75,7 @@ Bat = 119, Npc = 120, Ipb = 121, + Can = 122 } public enum F_Code diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index ad5d5b23b..cb40b91c2 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -834,8 +834,10 @@ namespace AgroBase.Models Variaveis.OperacaoEmAndamento.Parametros.RoverId = VariaveisEquipamento.Parametros.serial_number; Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.Add(new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Npc, Mandatorio = true, Utilizar = true }); - Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.Add(new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Bat, Mandatorio = true, Utilizar = true }); + Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.Add(new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Can, Mandatorio = true, Utilizar = true }); Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.Add(new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Ipb, Mandatorio = true, Utilizar = true }); + Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.Add(new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Bat, Mandatorio = true, Utilizar = true }); + Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.ForEach(m => m.ComponentesEmUso = Variaveis.OperacaoEmAndamento.PreencherComponentesEmUso(m.Dispositivo)); Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura = new OperacaoSensoriamentoLogModel(); @@ -2275,6 +2277,7 @@ namespace AgroBase.Models public bool CanSerialAtivado { get; set; } public Dictionary Iniciados { get; set; } public List Logs { get; set; } + public DateTime UltimoComandoRespondido { get; set; } public void InserirLog(T_Code dispositivo, StatusModulo status, double saude, string mensagem, string id = null, string condicoes = null) { @@ -2354,6 +2357,7 @@ namespace AgroBase.Models AnguloBarraEsquerda = _DispAtu.Dados.AnguloBarraEsquerda, AnguloBarraDireita = _DispAtu.Dados.AnguloBarraDireita, AnguloBarraAltura = _DispAtu.Dados.AnguloBarraAltura, + UltimoComandoRespondido = _DispAtu.Dados.DadosLeitura?.UltimoComandoRespondido ?? DateTime.MinValue } : new OperacaoSensoriamentoLogAtuModel(); var dadosMovimentacao = _DispMvd != null ? new OperacaoSensoriamentoLogMovModel() @@ -2378,7 +2382,8 @@ namespace AgroBase.Models TemperaturaDriver = x.MovMotor.TemperaturaDriver, RPM_Motor = x.MovMotor.RPM_Motor, RPM_Roda = x.MovMotor.RPM_Roda, - VelocidadeInstantanea = x.MovMotor.VelocidadeInstantanea + VelocidadeInstantanea = x.MovMotor.VelocidadeInstantanea, + UltimoComandoRespondido = x.MovMotor.Leitura?.UltimoComandoRecebido ?? DateTime.MinValue, }).ToList(), } : new OperacaoSensoriamentoLogMovModel(); @@ -2400,7 +2405,7 @@ namespace AgroBase.Models AnguloFolgaCompensar = x.DirMotor.AnguloFolgaCompensar, AnguloLeitura = x.DirMotor.AnguloLeitura, Controlar = x.DirMotor.Comandar, - UltimoComandoRespondido = x.DirMotor.UltimoComandoEnviado, + UltimoComandoRespondido = x.DirMotor.Leitura?.UltimoComandoRecebido ?? DateTime.MinValue, Velocidade = x.DirMotor.Velocidade, }).ToList() } : new OperacaoSensoriamentoLogDirModel(); @@ -2519,7 +2524,8 @@ namespace AgroBase.Models ModsCalibragem = new Dictionary>(Variaveis.OperacaoEmAndamento.ModsCalibragem), Temperaturas = _DispSen?.Dados?.Sensores?.Where(x => x.Componente == S_Code.sNTC)?.ToDictionary(x => x.ID, y => (double?)(y.ValoresLeituras?.FirstOrDefault(v => v.funcao == FuncoesPinout.Temperatura)?.atual?.valor) ?? -1), Iniciados = _DispSen?.Dados?.Servos?.Select(s => new { s.ID, s.Inicializado }).Union(_DispSen?.Dados?.Reles?.Select(r => new { r.ID, r.Inicializado })).Union(_DispSen?.Dados?.Sinaleiros?.Select(s => new { s.ID, s.Inicializado })).Union(_DispSen?.Dados?.Sensores?.Select(s => new { s.ID, s.Inicializado })).ToDictionary(s => s.ID, s => s.Inicializado), - Logs = new List(Logs ?? new List()) + Logs = new List(Logs ?? new List()), + UltimoComandoRespondido = _DispSen?.Dados?.DadosLeitura?.UltimoComandoRespondido ?? DateTime.MinValue }; Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura = dadosAtualizados; @@ -2569,7 +2575,8 @@ namespace AgroBase.Models ModsCalibragem = new Dictionary>(ModsCalibragem), Temperaturas = new Dictionary(Temperaturas ?? new Dictionary()), Iniciados = new Dictionary(Iniciados ?? new Dictionary()), - Logs = new List(Logs ?? new List()) + Logs = new List(Logs ?? new List()), + UltimoComandoRespondido = UltimoComandoRespondido }; } @@ -2625,6 +2632,7 @@ namespace AgroBase.Models public double AnguloBarraDireita { get; set; } public double AnguloBarraAltura { get; set; } public Dictionary Iniciados { get; set; } + public DateTime UltimoComandoRespondido { get; set; } public OperacaoSensoriamentoLogAtuModel Clone() { @@ -2650,7 +2658,8 @@ namespace AgroBase.Models AnguloBarraEsquerda = AnguloBarraEsquerda, AnguloBarraDireita = AnguloBarraDireita, AnguloBarraAltura = AnguloBarraAltura, - Iniciados = new Dictionary(Iniciados ?? new Dictionary()) + Iniciados = new Dictionary(Iniciados ?? new Dictionary()), + UltimoComandoRespondido = UltimoComandoRespondido }; } } @@ -2704,6 +2713,7 @@ namespace AgroBase.Models public double CicloTrabalho { get; set; } public double RPM_Motor { get; set; } public double VelocidadeInstantanea { get; set; } + public DateTime UltimoComandoRespondido { get; set; } } public class OperacaoSensoriamentoLogDirModel diff --git a/AgroBase/AgroBase/Services/CANService.cs b/AgroBase/AgroBase/Services/CANService.cs index 0a5941bc2..3df5969ed 100644 --- a/AgroBase/AgroBase/Services/CANService.cs +++ b/AgroBase/AgroBase/Services/CANService.cs @@ -163,6 +163,12 @@ namespace AgroBase.Services string _portName { get; set; } bool Iniciado { get; } bool IsConnected { get; } + double UltimoTx { get; set; } + double FreqTx { get; set; } + double UltimoRx { get; set; } + double FreqRx { get; set; } + int ErrosCriticos { get; set; } + double UltimoErroCritico { get; set; } } } \ No newline at end of file diff --git a/AgroBase/AgroBase/Services/CANServiceSerial.cs b/AgroBase/AgroBase/Services/CANServiceSerial.cs index 64756335a..8583500e4 100644 --- a/AgroBase/AgroBase/Services/CANServiceSerial.cs +++ b/AgroBase/AgroBase/Services/CANServiceSerial.cs @@ -1,7 +1,9 @@ using AgroBase.Models; +using Emgu.CV.Structure; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.IO.Ports; using System.Linq; using System.Text; @@ -34,8 +36,15 @@ namespace AgroBase.Services private List Mensagens = new List(); private readonly object _LockMensagens = new object(); - private DateTime UltimoTx = DateTime.MinValue; - private DateTime UltimoRx = DateTime.MinValue; + public double UltimoTx { get; set; } = 0; + private DateTime _ultimoTx = DateTime.MinValue; + public double FreqTx { get; set; } = 0; + public double UltimoRx { get; set; } = 0; + private DateTime _ultimoRx = DateTime.MinValue; + public double FreqRx{ get; set; } = 0; + public int ErrosCriticos { get; set; } = 0; + public double UltimoErroCritico { get; set; } = 0; + private DateTime _ultimoErroCritico = DateTime.MinValue; private bool DebugMode = false; private void MostrarLog(string message, byte id) @@ -121,9 +130,8 @@ namespace AgroBase.Services Iniciado = true; SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel() { - Dispositivo = T_Code.Vzo, - Endereco = _portName, - Mod_ID = "CAN" + Dispositivo = T_Code.Can, + Endereco = _portName }); break; } @@ -196,8 +204,10 @@ namespace AgroBase.Services _PortaCAN.DiscardOutBuffer(); } - UltimoRx = DateTime.Now; - UltimoTx = DateTime.Now; + _ultimoRx = DateTime.Now; + UltimoRx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; + _ultimoTx = DateTime.Now; + UltimoTx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; tmrOuvirCAN?.Dispose(); tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 1); @@ -277,7 +287,10 @@ namespace AgroBase.Services if (tempBuffer.Length > 0) { - UltimoRx = DateTime.Now; + var agora = DateTime.Now; + FreqRx = 1.0 / (agora - _ultimoRx).TotalSeconds; + _ultimoRx = agora; + UltimoRx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; } } } @@ -531,7 +544,10 @@ namespace AgroBase.Services { _PortaCAN.Write(comando); //Console.WriteLine($"[CAN] Frame enviado: {comando}"); - UltimoTx = DateTime.Now; + var agora = DateTime.Now; + FreqTx = 1.0 / (agora - _ultimoTx).TotalSeconds; + _ultimoTx = agora; + UltimoTx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; return true; } return false; @@ -575,14 +591,19 @@ namespace AgroBase.Services return; } - if (IsConnected && (((Agora - UltimoTx).TotalSeconds > 2 && (Agora - UltimoRx).TotalSeconds > 2) || _precisaReabrir)) + if (IsConnected && (((Agora - _ultimoTx).TotalSeconds > 2 && (Agora - _ultimoRx).TotalSeconds > 2) || _precisaReabrir)) { + ErrosCriticos++; + _ultimoErroCritico = Agora; + UltimoErroCritico = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; _precisaReabrir = false; - UltimoRx = Agora; - UltimoTx = Agora; MostrarLog("Muito tempo sem receber novos dados, reiniciando conexao CAN...", 0); ReabrirPortaSegura(); } + if ((Agora - _ultimoErroCritico).TotalMinutes > 10) + { + ErrosCriticos = 0; + } } public void Fechar() @@ -715,6 +736,12 @@ namespace AgroBase.Services EnviarComando("Z0\r"); Thread.Sleep(50); EnviarComando(ComandoBitRate(_bitRate)); Thread.Sleep(50); EnviarComando("O\r"); Thread.Sleep(50); + + _ultimoRx = DateTime.Now; + UltimoRx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; + _ultimoTx = DateTime.Now; + UltimoTx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; + } catch { diff --git a/AgroBase/AgroBase/Services/CANServiceWaveshare.cs b/AgroBase/AgroBase/Services/CANServiceWaveshare.cs index f6d2db131..a379a8a63 100644 --- a/AgroBase/AgroBase/Services/CANServiceWaveshare.cs +++ b/AgroBase/AgroBase/Services/CANServiceWaveshare.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.IO.Ports; using System.Linq; using System.Text; @@ -34,8 +35,15 @@ namespace AgroBase.Services private List MensagensPendentes = new List(); private readonly object _LockMensagens = new object(); private bool DebugMode = false; - private DateTime UltimoTx = DateTime.MinValue; - private DateTime UltimoRx = DateTime.MinValue; + public double UltimoTx { get; set; } = 0; + private DateTime _ultimoTx = DateTime.MinValue; + public double FreqTx { get; set; } = 0; + public double UltimoRx { get; set; } = 0; + private DateTime _ultimoRx = DateTime.MinValue; + public double FreqRx { get; set; } = 0; + public int ErrosCriticos { get; set; } = 0; + public double UltimoErroCritico { get; set; } = 0; + private DateTime _ultimoErroCritico = DateTime.MinValue; private void MostrarLog(string message, byte id) { @@ -87,7 +95,8 @@ namespace AgroBase.Services while (FramesRecebidos.Count > 4096) // cap opcional FramesRecebidos.TryDequeue(out _); } - UltimoRx = now; + _ultimoRx = now; + UltimoRx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; } catch (Exception ex) { @@ -111,8 +120,10 @@ namespace AgroBase.Services if (canIniciado || !IsConnected) { - UltimoRx = DateTime.Now; - UltimoTx = DateTime.Now; + _ultimoRx = DateTime.Now; + UltimoRx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; + _ultimoTx = DateTime.Now; + UltimoTx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; tmrEnviarCAN?.Dispose(); tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 3); @@ -138,6 +149,11 @@ namespace AgroBase.Services while (processed < MAX_BATCH && FramesRecebidos.TryDequeue(out var frame)) { + var agora = DateTime.Now; + FreqRx = 1.0 / (agora - _ultimoRx).TotalSeconds; + _ultimoRx = agora; + UltimoRx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; + ProcessarFrameCAN(frame); processed++; @@ -369,7 +385,10 @@ namespace AgroBase.Services if (sucesso) { MostrarLog($"Frame enviado: {comando}", msg.IdTx); - UltimoTx = DateTime.Now; + var agora = DateTime.Now; + FreqTx = 1.0 / (agora - _ultimoTx).TotalSeconds; + _ultimoTx = agora; + UltimoTx = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; } else { @@ -405,10 +424,11 @@ namespace AgroBase.Services private void VerificaSaudeConexao() { DateTime Agora = DateTime.Now; - if (IsConnected && ((Agora - UltimoTx).TotalSeconds > 10 || (Agora - UltimoRx).TotalSeconds > 10)) + if (IsConnected && ((Agora - _ultimoTx).TotalSeconds > 2 && (Agora - _ultimoRx).TotalSeconds > 2)) { - UltimoRx = Agora; - UltimoTx = Agora; + ErrosCriticos++; + _ultimoErroCritico = Agora; + UltimoErroCritico = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; MostrarLog("Muito tempo sem receber novos dados, reiniciando conexao CAN...", 0); try { Connector.Close(); } catch { } try @@ -417,6 +437,10 @@ namespace AgroBase.Services } catch { } } + if ((Agora - _ultimoErroCritico).TotalMinutes > 10) + { + ErrosCriticos = 0; + } } public void Fechar() diff --git a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs index 8cbc9c61c..c8064e656 100644 --- a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs +++ b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs @@ -580,6 +580,20 @@ namespace AgroBase.Services.Operadores ("gpu_temp", DadosMod.GPU_temp ?? 0) ); + var DadosCan = CanManager.CanService; + RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Can), + ("timestamp", agora), + ("conectado", DadosCan.Iniciado), + ("iniciado", DadosCan.IsConnected), + ("executando", SerialService.DispositivosMapeados.Any(x => SerialService.DispositivosCan.Contains(x.Dispositivo))), + ("erros_criticos", DadosCan.ErrosCriticos), + ("freq_tx", DadosCan.FreqTx), + ("freq_rx", DadosCan.FreqRx), + ("last_tx", DadosCan.UltimoTx), + ("last_rx", DadosCan.UltimoRx), + ("last_ec", DadosCan.UltimoErroCritico) + ); + } diff --git a/AgroBase/AgroBase/Services/SerialService.cs b/AgroBase/AgroBase/Services/SerialService.cs index 2eb485c1b..5ce229dde 100644 --- a/AgroBase/AgroBase/Services/SerialService.cs +++ b/AgroBase/AgroBase/Services/SerialService.cs @@ -30,7 +30,7 @@ namespace AgroBase.Services public static List DispositivosConexaoInicial = new List() { T_Code.Mvd, T_Code.Atu, T_Code.Sen }; public static List DispositivosProprios = new List() { T_Code.Atu, T_Code.Sen }; public static List DispositivosModbus = new List() { T_Code.Pzm, T_Code.Wit, T_Code.A05 }; - public static List DispositivosCan = new List() { T_Code.Vzo, T_Code.Mov, T_Code.Oid, T_Code.Dir, T_Code.Mks, T_Code.Sen, T_Code.Atu }; + public static List DispositivosCan = new List() { T_Code.Mov, T_Code.Oid, T_Code.Dir, T_Code.Mks, T_Code.Sen, T_Code.Atu }; public static List DispositivosMultiplos = new List() { T_Code.Bld, T_Code.Mks, T_Code.Mvd, T_Code.Oid, T_Code.Mov, T_Code.Dir }; public static List DispositivosMapeados = new List() diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/main.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/main.py index 323e56c41..3ddfafd65 100644 --- a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/main.py +++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/main.py @@ -17,6 +17,7 @@ def main(): from health_worker.modulos.pc import ModuloPC from health_worker.modulos.livox import ModuloLivox from health_worker.modulos.ponte_ip import ModuloIPBribge + from health_worker.modulos.can import ModuloCAN from health_worker.config import mostrar_log from shared.contexto_global_redis import ContextoGlobalRedis, CmdKey, CtxKey @@ -31,6 +32,7 @@ def main(): T_Code.Npc: ModuloPC(), T_Code.Lvx: ModuloLivox(), T_Code.Ipb: ModuloIPBribge(), + T_Code.Can: ModuloCAN(), } def loop_ativo(): diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/enums.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/enums.py index b17a622e3..7abb12d1f 100644 --- a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/enums.py +++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/enums.py @@ -67,12 +67,14 @@ class T_Code(IntEnum): Gps = 104 Lra = 106 Cam = 112 - Mod = 115 - Snr = 117 - Lvx = 118 - Bat = 119 - Npc = 120 - Ipb = 121 + Mod = 115, + Oid = 116, + Snr = 117, + Lvx = 118, + Bat = 119, + Npc = 120, + Ipb = 121, + Can = 122 class ParametrosOperacao(IntEnum): CameraSolo = 1 diff --git a/AgroBase/OperationControl/Windows/MainWindow.xaml b/AgroBase/OperationControl/Windows/MainWindow.xaml index 2adafca11..bb650eeea 100644 --- a/AgroBase/OperationControl/Windows/MainWindow.xaml +++ b/AgroBase/OperationControl/Windows/MainWindow.xaml @@ -147,6 +147,7 @@