using AgroBase.Forms; using AgroBase.Models; using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static AgroBase.Models.Enums; namespace AgroBase.Services { public class SerialService { public static int InteraloVerificacao = 5000; public static string BeginLine = "@"; public static string BreakLine = "&"; public static string EndLine = "$"; public static string BeginSensor = "#"; public static string SplitMessage = ";"; public static string SplitParams = ","; public static List DispositivosMotores = new List() { T_Code.Mov, T_Code.Dir }; public static List DispositivosConexaoInicial = new List() { T_Code.Mvd, T_Code.Atu, T_Code.Sen }; public static List DispositivosModbus = new List() { T_Code.Pzm, T_Code.Wit, T_Code.A05 }; public static List DispositivosMultiplos = new List() { T_Code.Bld, T_Code.Mks, T_Code.Mvd }; public class DispositivoDetalhesModel { public string Endereco { get; set; } public TipoConexao Tipo { get { if (Endereco.Contains("USB")) { return TipoConexao.USB; } else if (Endereco.Contains("COM")) { return TipoConexao.PortaCOM; } else if (Endereco.Contains(".")) { return TipoConexao.Ethernet; } else { return TipoConexao.Desconhecido; } } } public T_Code Dispositivo { get; set; } public bool Erro { get; set; } public string Versao { get; set; } public string Mod_ID { get; set; } public bool Conectado { get { bool DispositivoConectado = false; if (Dispositivo == T_Code.Gps) { DispositivoConectado = GPSService.Iniciado; } else if (Dispositivo == T_Code.Pzm) { DispositivoConectado = PZEMService.Iniciado; } else if (Dispositivo == T_Code.A05) { DispositivoConectado = UltrasonicA05Service.Iniciado; } else if (Dispositivo == T_Code.Lra) { DispositivoConectado = LoRaService.Iniciado; } else if (Dispositivo == T_Code.Wit) { DispositivoConectado = WT901CService.Iniciado; } else if (Dispositivo == T_Code.Knt) { DispositivoConectado = KinectService.Iniciado; } else if (Dispositivo == T_Code.Bld) { var Modulo = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == Mod_ID); DispositivoConectado = Modulo?.MovMotor?.BLD_Inicializado ?? false; } else if (Dispositivo == T_Code.Mks) { var Modulo = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == Mod_ID); DispositivoConectado = Modulo?.DirMotor?.MKS_Inicializado ?? false; } else { IDispositivosService dispositivoService = Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Dispositivo && x._Porta.PortName == Endereco); if (dispositivoService != null) { return dispositivoService._Porta != null && dispositivoService._Porta.IsOpen && dispositivoService.Dados.GetStatusConexao(); } else { DispositivoConectado = false; } } return DispositivoConectado; } } } public static List DispositivosMapeados = new List(); private static Dictionary TentativasPortas = new Dictionary(); private static bool VarreduraEmAndamento = false; public static bool EnviarDadosPortaSerial(SerialPort _porta, string Dados, bool DebugMode = false) { bool ForceDebug = false; if (ForceDebug) { DebugMode = true; } // Verifica se a porta está definida if (_porta == null) { Console.WriteLine("A porta serial não está definida."); return false; } // Verifica se a porta está aberta if (!_porta.IsOpen) { Console.WriteLine("A porta serial não está aberta."); return false; } try { // Define o tempo de espera máximo para a operação de escrita _porta.WriteTimeout = 2000; // 2 segundos de timeout para escrita (ajuste conforme necessário) // Verifica se há dados para enviar if (string.IsNullOrEmpty(Dados)) { if (DebugMode) Console.WriteLine("Nenhum dado para enviar."); return false; } // Tenta enviar os dados na porta serial _porta.Write(Dados); if (DebugMode) Console.WriteLine("Dados enviados com sucesso."); return true; } catch (TimeoutException) { // Timeout ocorreu, o que significa que não foi possível escrever os dados no tempo estipulado if (DebugMode) Console.WriteLine("Erro: Timeout ao tentar enviar dados."); return false; } catch (InvalidOperationException ex) { // A porta não estava aberta ou algo relacionado a uma falha de operação na porta if (DebugMode) Console.WriteLine("Erro: A porta serial não está aberta ou houve uma falha na operação. " + ex.Message); return false; } catch (UnauthorizedAccessException ex) { // Caso a porta serial esteja sendo acessada por outro processo if (DebugMode) Console.WriteLine("Erro: Acesso negado à porta serial. " + ex.Message); return false; } catch (Exception ex) { // Captura outros tipos de erro inesperados if (DebugMode) Console.WriteLine("Erro inesperado: " + ex.Message); return false; } } public static bool EnviarDadosPortaSerial(SerialPort _porta, byte[] Dados, int inicio, int comprimento, bool DebugMode = false) { bool ForceDebug = false; if (ForceDebug) { DebugMode = true; } // Verifica se a porta está definida if (_porta == null) { Console.WriteLine("A porta serial não está definida."); return false; } // Verifica se a porta está aberta if (!_porta.IsOpen) { Console.WriteLine("A porta serial não está aberta."); return false; } try { // Define o tempo de espera máximo para a operação de escrita _porta.WriteTimeout = 2000; // 2 segundos de timeout para escrita (ajuste conforme necessário) // Verifica se há dados para enviar if (Dados == null || Dados.Length == 0) { if (DebugMode) Console.WriteLine("Nenhum dado para enviar."); return false; } // Tenta enviar os dados na porta serial _porta.Write(Dados, inicio, comprimento); if (DebugMode) Console.WriteLine("Dados enviados com sucesso."); return true; } catch (TimeoutException) { // Timeout ocorreu, o que significa que não foi possível escrever os dados no tempo estipulado if (DebugMode) Console.WriteLine("Erro: Timeout ao tentar enviar dados."); return false; } catch (InvalidOperationException ex) { // A porta não estava aberta ou algo relacionado a uma falha de operação na porta if (DebugMode) Console.WriteLine("Erro: A porta serial não está aberta ou houve uma falha na operação. " + ex.Message); return false; } catch (UnauthorizedAccessException ex) { // Caso a porta serial esteja sendo acessada por outro processo if (DebugMode) Console.WriteLine("Erro: Acesso negado à porta serial. " + ex.Message); return false; } catch (Exception ex) { // Captura outros tipos de erro inesperados if (DebugMode) Console.WriteLine("Erro inesperado: " + ex.Message); return false; } } public static async Task RealizarVarreduraPortasUSB() // System.Timers.Timer tmr { //tmr.Interval = InteraloVerificacao; if (VarreduraEmAndamento || frmInstancial.Fechando) { return; } VarreduraEmAndamento = true; try { ProcurarDispositivosUSB(); var dispositivosMapeados = DispositivosMapeados.ToList(); var Portas = SerialPort.GetPortNames(); var PortasNaoMapeadas = Portas.Where(x => !dispositivosMapeados.Select(y => y.Endereco).Contains(x)).ToList(); List PortasSemResposta = new List(); for (int i = 0; i < PortasNaoMapeadas.Count(); i++) { string PortaCom = PortasNaoMapeadas[i].ToString(); AtualizarConsole("Procurando dispositivos conectados à porta " + PortaCom + "..."); SerialPort _Porta = new SerialPort() { PortName = PortaCom, BaudRate = 115200 }; if (Variaveis.IsAgroMonitor) { try { bool LoRa = await ProcuraDispositivoLoRa(_Porta); if (!LoRa && !GPSService.Iniciado) { _Porta.Open(); await AguardaRespostaPorta(_Porta, 1100); bool GPS = VerificaRespostaGPS(_Porta); } } catch (Exception ex) { Console.WriteLine("Erro ao abrir a porta " + PortaCom + ": " + ex.Message); } finally { _Porta.Close(); } continue; } bool PortaDispositivoProprio = false; if (Variaveis.OperacaoEmAndamento.DispMvd == null) { continue; } try { string ProtocoloCheck = ""; _Porta.Open(); if (!PortaDispositivoProprio && !DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Atu)) { ProtocoloCheck = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ProtocoloVerificacao(true); AtualizarConsole("Procurando dispositivo ATU"); if (!EnviarDadosPortaSerial(_Porta, ProtocoloCheck)) { continue; } await AguardaRespostaPorta(_Porta, 1000); PortaDispositivoProprio = ProcessarRespostaDispositivo(_Porta); if (PortaDispositivoProprio) { AtualizarConsole("Dispositivo ATU encontrado"); } } if (!PortaDispositivoProprio && !DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Sen)) { ProtocoloCheck = Variaveis.OperacaoEmAndamento.DispSen.Dados.ProtocoloVerificacao(true); AtualizarConsole("Procurando dispositivo SEN"); if (!EnviarDadosPortaSerial(_Porta, ProtocoloCheck)) { continue; } await AguardaRespostaPorta(_Porta, 1000); PortaDispositivoProprio = ProcessarRespostaDispositivo(_Porta); if (PortaDispositivoProprio) { AtualizarConsole("Dispositivo SEN encontrado"); } } if (!PortaDispositivoProprio && !GPSService.Iniciado) { AtualizarConsole("Procurando dispositivo GPS"); await Task.Delay(1000); bool GPSEncontrado = VerificaRespostaGPS(_Porta); if (GPSEncontrado) { _Porta.Close(); continue; } } } catch (Exception ex) { Console.WriteLine("Erro ao identificar dispositivo proprio: " + ex.Message); } finally { _Porta.Close(); await Task.Delay(100); } if (!PortaDispositivoProprio) { await TentarIdentificarDispositivo(_Porta); } } if (Variaveis.IsAgroMonitor) { return; } if (Variaveis.OperacaoEmAndamento.DispMvd != null) { await ProcurarDispositivosEthernet(); } var DispositivosRemovidos = dispositivosMapeados.Where(x => x.Tipo == TipoConexao.PortaCOM && !Portas.Contains(x.Endereco)).ToList(); foreach (var Dispositivo in DispositivosRemovidos) { DispositivosMapeados.Remove(Dispositivo); } /*if (DispositivosMapeados.Any(x => DispositivosConexaoInicial.Contains(x.Dispositivo))) { FilaService.IniciarRotinas(); } else { FilaService.PararRotinas(); }*/ if (DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Knt) && !KinectService.Iniciado) { KinectService.PararRotinas(); DispositivosMapeados.Remove(DispositivosMapeados.First(x => x.Dispositivo == T_Code.Knt)); } AtualizarDispositivos(); // Se algum dispositivo no barramento RS485 para Modbus já foi identificado if (ModbusService.Iniciado) { await ProcuraDispositivoModbus(ModbusService._PortaModbus, false); } } catch (Exception ex) { Console.WriteLine("Erro ao realizar varredura de portas: " + ex.Message); } finally { VarreduraEmAndamento = false; RealizarVerificacaoDeRotina(); } } private static void RealizarVerificacaoDeRotina() { FuncoesGlobais.SafeExecuteAsync(async () => { try { await VersionamentoService.AtualizarArquivoVersionamento(false); } catch (Exception ex) { Console.WriteLine($"Erro ao atualizar arquivo de versionamento: {ex.Message}"); } }).ConfigureAwait(false); FuncoesGlobais.SafeExecuteAsync(async () => { try { await SyncDataService.SincronizarArquivosComServidor(); } catch (Exception ex) { Console.WriteLine($"Erro ao sincronizar arquivos com o servidor: {ex.Message}"); } }).ConfigureAwait(false); } private static bool ProcessarRespostaDispositivo(SerialPort Porta) { if (Porta.BytesToRead <= 15 || Porta.BytesToRead >= 30) { //VerificaRespostaGPS(Porta); VerificarRespostaPortasDesconhecidas(Porta); return false; } string Recebido = ReadLineWithTimeout(Porta, 1000); if (Recebido.Length > 2) { T_Code Dispositivo = T_Code.Vzo; F_Code Verificacao = F_Code.Nda; string Versao = "0"; var Dados = Recebido.Split(SplitMessage[0]); if (Dados.Length <= 1) { return false; } string Mod_ID = Dados[0]; int.TryParse(Dados[1], out int check); if (check == 0) { return false; } Verificacao = (F_Code)check; if (Verificacao == F_Code.Msg) { return true; } Dispositivo = (T_Code)(int.Parse(Dados[2])); Versao = Dados[3]; if (Dispositivo != T_Code.Vzo && !DispositivosMapeados.Any(x => x.Dispositivo == Dispositivo && x.Mod_ID == Mod_ID)) { DispositivosMapeados.Add(new DispositivoDetalhesModel() { Endereco = Porta.PortName, Dispositivo = Dispositivo, Erro = Verificacao == F_Code.Err, Versao = Versao, Mod_ID = Mod_ID, }); } return true; } return false; } public static string ReadLineWithTimeout(SerialPort porta, int timeout) { CancellationTokenSource cts = new CancellationTokenSource(); Task task = Task.Run(() => porta.ReadLine(), cts.Token); if (task.Wait(timeout)) { return task.Result; } else { cts.Cancel(); return ""; // ou string.Empty, dependendo de como você deseja lidar com isso } } public static void AtualizarDispositivos() { var Portas = SerialPort.GetPortNames().ToList(); DispositivosConexaoInicial.ForEach(Dispositivo => { IDispositivosService dispositivoService = Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Dispositivo); if (dispositivoService != null) { dispositivoService.AtualizarPortas(); if ( Portas.Contains(dispositivoService.PortaCOM()) && (!dispositivoService._Porta.IsOpen || (dispositivoService._Porta.IsOpen && !dispositivoService.Dados.GetStatusConexao())) ) { dispositivoService.btnConectar_Click(new object(), new EventArgs()); } } }); } private static async Task TentarIdentificarDispositivo(SerialPort porta) { // Método para tentar identificar dispositivos que não respondem ao comando de verificação padrão try { bool DispModbus = await ProcuraDispositivoModbus(porta, false); if (DispModbus) { return true; } bool DispLoRa = await ProcuraDispositivoLoRa(porta); if (DispLoRa) { return true; } if (TentativasPortas.TryGetValue(porta.PortName, out int tentativas)) { TentativasPortas[porta.PortName] = tentativas + 1; } else { TentativasPortas.Add(porta.PortName, 1); } if (TentativasPortas[porta.PortName] > 5) { TentativasPortas.Remove(porta.PortName); //PortasDesconhecidas.Add(porta); } } catch (Exception ex) { Console.WriteLine("Erro ao tentar identificar dispositivo na porta " + porta.PortName + ": " + ex.Message); porta.Close(); } return false; } private static async Task ProcuraDispositivoMvd(SerialPort porta) { bool DispositivoMvd = false; if (porta == null) { return false; } if (DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mvd) && porta.PortName != DispositivosMapeados.First(x => x.Dispositivo == T_Code.Mvd).Endereco) { return false; } bool conectado = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Conectado; if (!conectado) { porta.Open(); } foreach (var Modulo in Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Where(x => !DispositivosMapeados.Select(y => y.Mod_ID).Contains(x.Modulo_ID))) { try { string ProtocoloCheck = Modulo.ProtocoloVerificacao(true); EnviarDadosPortaSerial(porta, ProtocoloCheck); await AguardaRespostaPorta(porta, 1000); bool respondeu = ProcessarRespostaDispositivo(porta); if (!DispositivoMvd) { DispositivoMvd = respondeu; } } catch (Exception ex) { Console.WriteLine(ex.Message); } } if (!conectado) { porta.Close(); } return DispositivoMvd; } private static async Task ProcuraDispositivoModbus(SerialPort porta, bool PararAoEncontrar) { if (ModbusService.Iniciado && porta.PortName != ModbusService._PortaModbus.PortName) { return false; } bool ProcurarPzm = !PZEMService.Iniciado || !DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Pzm); bool ProcurarWit = !WT901CService.Iniciado || !DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Wit); bool ProcurarA05 = !UltrasonicA05Service.Iniciado || !DispositivosMapeados.Any(x => x.Dispositivo == T_Code.A05); if (!ProcurarPzm && !ProcurarWit && !ProcurarA05) { return false; } AtualizarConsole("Procurando dispositivos Modbus"); if (ProcurarPzm) { AtualizarConsole("Procurando dispositivo PZM"); bool _encontrado = await PZEMService.VerificaPortaPZEM(ModbusService.Iniciado ? ModbusService._PortaModbus : porta); if (_encontrado && PararAoEncontrar) { AtualizarConsole("Dispositivo PZM encontrado"); return _encontrado; } } if (ProcurarWit) { AtualizarConsole("Procurando dispositivo WIT"); bool _encontrado = await WT901CService.VerificaPortaWT901C(ModbusService.Iniciado ? ModbusService._PortaModbus : porta); if (_encontrado && PararAoEncontrar) { AtualizarConsole("Dispositivo WIT encontrado"); return _encontrado; } } if (ProcurarA05) { AtualizarConsole("Procurando dispositivo A05"); bool _encontrado = await UltrasonicA05Service.VerificaPortaA05(ModbusService.Iniciado ? ModbusService._PortaModbus : porta); if (_encontrado && PararAoEncontrar) { AtualizarConsole("Dispositivo A05 encontrado"); return _encontrado; } } return ModbusService.Iniciado; } private static async Task ProcuraDispositivoLoRa(SerialPort porta) { if (LoRaService.Iniciado && porta.PortName != LoRaService._PortaLoRa.PortName) { return false; } if (!LoRaService.Iniciado) { AtualizarConsole("Procurando dispositivo LRA"); bool Encontrado = await LoRaService.VerificaPortaLoRa(porta); if (Encontrado) { AtualizarConsole("Dispositivo LRA encontrado"); } return Encontrado; } else { return false; } } private static void ProcurarDispositivosUSB() { if (!Variaveis.IsAgroMonitor) { if (!KinectService.Iniciado) { KinectService.InicializarKinect(); } if (GeneralJoystick.JoystickConectado == null) { GeneralJoystick.AtualizaDispositivo(); } } } private static async Task ProcurarDispositivosEthernet() { if (!Variaveis.IsAgroMonitor) { bool ethernetEncontrado = false; bool DispBld = await ProcuraDispositivoBLD(); if (DispBld) { ethernetEncontrado = true; } bool DispMks = await ProcuraDispositivoMKS(); if (DispMks) { ethernetEncontrado = true; } return ethernetEncontrado; } return false; } private static async Task ProcuraDispositivoBLD() { if (!BLD300RService.Iniciado || BLD300RService.DadosLeitura.Any(x => !x.Iniciado)) { AtualizarConsole("Procurando dispositivos BLD"); bool Encontrado = await BLD300RService.VerificaPortaBLD(); if (Encontrado) { AtualizarConsole("Dispositivo BLD encontrado"); return Encontrado; } } return BLD300RService.Iniciado; } private static async Task ProcuraDispositivoMKS() { if (!MKS057DService.Referenciando && (!MKS057DService.Iniciado || MKS057DService.DadosLeitura.Any(x => !x.Iniciado))) { AtualizarConsole("Procurando dispositivos MKS"); bool Encontrado = await MKS057DService.VerificaPortaMKS(); if (Encontrado) { AtualizarConsole("Dispositivo MKS encontrado"); return Encontrado; } } return MKS057DService.Iniciado; } private static bool VerificaRespostaGPS(SerialPort Porta, string Recebido = null) { if (string.IsNullOrEmpty(Recebido)) { //Recebido = Porta.ReadLine(); byte[] buffer = LerDadosDaPortaSerial(Porta, 15); Recebido = Encoding.ASCII.GetString(buffer); } if (Recebido.Contains("$GPTXT") || Recebido.Contains("$GPRMC") || Recebido.Contains("$GPGGA") || Recebido.Contains("$GPGLL")) { GPSService.AtualizarPortaCOM(Porta); AtualizarConsole("Dispositivo GPS encontrado"); return true; } return false; } public static byte[] VerificarRespostaPortasDesconhecidas(SerialPort Porta) { if (Porta != null && Porta.IsOpen) { int bytesToRead = Porta.BytesToRead; byte[] buffer = new byte[bytesToRead]; Porta.Read(buffer, 0, bytesToRead); //Porta.DiscardInBuffer(); return buffer; } else { return new byte[] { }; } } public static byte[] LerDadosDaPortaSerial(SerialPort porta, int tamanhoEsperado, int Timeout = 500) { DateTime inicio = DateTime.Now; List buffer = new List(); while (buffer.Count < tamanhoEsperado && inicio.AddMilliseconds(Timeout) > DateTime.Now) { if (porta == null) { break; } int bytesDisponiveis = porta.BytesToRead; if (bytesDisponiveis > 0) { byte[] tempBuffer = new byte[bytesDisponiveis]; int bytesLidos = porta.Read(tempBuffer, 0, bytesDisponiveis); buffer.AddRange(tempBuffer.Take(bytesLidos)); } } return buffer.ToArray(); } public static async Task LerDadosDaPortaSerialAsync(SerialPort porta, int tamanhoEsperado, int Timeout = 500) { DateTime inicio = DateTime.Now; List buffer = new List(); while (buffer.Count < tamanhoEsperado && inicio.AddMilliseconds(Timeout) > DateTime.Now) { await Task.Delay(50); if (porta == null || !porta.IsOpen) { break; } int bytesDisponiveis = porta.BytesToRead; if (bytesDisponiveis > 0) { byte[] tempBuffer = new byte[bytesDisponiveis]; int bytesLidos = porta.Read(tempBuffer, 0, bytesDisponiveis); buffer.AddRange(tempBuffer.Take(bytesLidos)); } } return buffer.ToArray(); } public static async Task AguardaRespostaPorta(SerialPort _Porta, int Timeout) { DateTime inicio = DateTime.Now; while (_Porta.BytesToRead == 0 && DateTime.Now < inicio.AddMilliseconds(Timeout)) { await Task.Delay(50); } } private static void AtualizarConsole(string msg) { Console.WriteLine(msg); if (!Variaveis.IsAgroMonitor) { frmInstancial.frmPrincipal.Invoke((MethodInvoker)(() => { frmInstancial.frmPrincipal.lblStatusConexao.Text = msg; frmInstancial.frmIHM.lblStatus.Text = msg; })); } } public static void MostrarComandoResposta(T_Code tipo, byte[] comando, byte[] resposta) { bool showCommands = true; if (showCommands) { Console.WriteLine(tipo.ToString() + " - TX: " + string.Join(" ", comando.Select(x => x.ToString("x"))) + ", RX: " + string.Join(" ", (resposta != null ? resposta : new byte[] { }).Select(x => x.ToString("x")))); } } } }