agrobot_base/AgroBase/AgroBase/Services/SerialService.cs

676 lines
26 KiB
C#

using AgroBase.Forms;
using AgroBase.Models;
using AgroBase.Services.Operadores;
using System;
using System.Collections.Generic;
using System.IO;
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 readonly string BeginLine = "@";
public static readonly string BreakLine = "&";
public static readonly string EndLine = "$";
public static readonly string BeginSensor = "#";
public static readonly string SplitMessage = ";";
public static readonly string SplitParams = ",";
public static readonly string SplitConfig = "*";
public static readonly string SplitSubParams = "~";
public static List<T_Code> DispositivosMotores = new List<T_Code>() { T_Code.Mov, T_Code.Dir };
public static List<T_Code> DispositivosConexaoInicial = new List<T_Code>() { T_Code.Mvd, T_Code.Atu, T_Code.Sen };
public static List<T_Code> DispositivosProprios = new List<T_Code>() { T_Code.Atu, T_Code.Sen };
public static List<T_Code> DispositivosModbus = new List<T_Code>() { T_Code.Pzm, T_Code.Wit, T_Code.A05 };
public static List<T_Code> DispositivosCan = new List<T_Code>() { T_Code.Mov, T_Code.Oid, T_Code.Dir, T_Code.Mks, T_Code.Sen, T_Code.Atu };
public static List<T_Code> DispositivosMultiplos = new List<T_Code>() { T_Code.Bld, T_Code.Mks, T_Code.Mvd, T_Code.Oid, T_Code.Mov, T_Code.Dir };
public static List<DispositivoDetalhesModel> DispositivosMapeados = new List<DispositivoDetalhesModel>()
{
new DispositivoDetalhesModel()
{
Dispositivo = T_Code.Npc,
Endereco = EthernetService.ObterIpAtual(null),
Versao = Variaveis.Versao,
Mod_ID = ""
}
};
private static bool VarreduraEmAndamento = false;
public static bool EnviarDadosPortaSerial(SerialPort _porta, string Dados, bool DebugMode = false, int timeout = 2000)
{
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 = timeout; // 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()
{
if (VarreduraEmAndamento || Variaveis.Fechando)
{
return;
}
VarreduraEmAndamento = true;
try
{
var dispositivosMapeados = DispositivosMapeados.ToList();
var Portas = SerialPort.GetPortNames();
var PortasNaoMapeadas = Portas.Where(x => !dispositivosMapeados.Select(y => y.Endereco).Contains(x)).ToList();
List<string> PortasSemResposta = new List<string>();
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 (!LoRaBaseService.Iniciado && Variaveis.IsAgroMonitor)
{
bool LoRa = await ProcurarDispositivoLoRa(_Porta);
if (LoRa)
{
continue;
}
}
if (!GPSService.Iniciado)
{
bool GPSEncontrado = await ProcurarDispositivoGPS(_Porta);
if (GPSEncontrado)
{
continue;
}
}
if (Variaveis.IsAgroMonitor) continue;
if (CanManager.UseCanSerial && !CanManager.CanService.Iniciado)
{
bool dispositivoCan = await ProcurarDispositivosCAN(_Porta);
if (dispositivoCan)
{
AtualizarConsole("Dispositivo encontrado no barramento CAN");
continue;
}
}
}
if (Variaveis.IsAgroMonitor) return;
ProcurarDispositivosUSB();
ProcurarDispositivosEthernet();
await ProcurarDispositivosCAN();
var DispositivosRemovidos = dispositivosMapeados.Where(x => x.Tipo == TipoConexao.PortaCOM && (!Portas.Contains(x.Endereco))).ToList();
foreach (var Dispositivo in DispositivosRemovidos)
{
DispositivosMapeados.Remove(Dispositivo);
switch (Dispositivo.Dispositivo)
{
case T_Code.Gps:
GPSService.PortaGPS?.Close();
GPSService.PortaGPS = null;
break;
case T_Code.Lra:
LoRaBaseService._PortaLoRa?.Close();
LoRaBaseService._PortaLoRa = null;
break;
}
}
AtualizarDispositivos();
}
catch (Exception ex)
{
Console.WriteLine("Erro ao realizar varredura de portas: " + ex.Message);
}
finally
{
VarreduraEmAndamento = false;
RealizarVerificacaoDeRotina();
AtualizarConsole("Iteração finalizada, aguardando a próxima...");
}
}
private static void RealizarVerificacaoDeRotina()
{
Task.Run(async () =>
{
await FuncoesGlobais.SafeExecuteAsync(async () =>
{
try
{
await VersionamentoService.AtualizarArquivoVersionamento(false);
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao atualizar arquivo de versionamento: {ex.Message}");
}
});
});
Task.Run(async () =>
{
await FuncoesGlobais.SafeExecuteAsync(async () =>
{
try
{
await SyncDataService.SincronizarArquivosComServidor();
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao sincronizar arquivos com o servidor: {ex.Message}");
}
});
});
}
public static string ReadLineWithTimeout(SerialPort porta, int timeout)
{
using (CancellationTokenSource cts = new CancellationTokenSource())
{
try
{
Task<string> task = Task.Run(() =>
{
if (porta.IsOpen) // Verifica se a porta está aberta
{
return porta.ReadLine();
}
throw new IOException("A porta serial não está aberta.");
}, cts.Token);
if (task.Wait(timeout))
{
return task.Result;
}
else
{
cts.Cancel();
return ""; // Retorna vazio se o timeout for atingido
}
}
catch (IOException ex)
{
Console.WriteLine($"Erro de I/O: {ex.Message}");
return ""; // Ou trate como necessário
}
catch (Exception ex)
{
Console.WriteLine($"Erro: {ex.Message}");
return ""; // Ou trate como necessário
}
}
}
public static void AtualizarDispositivos()
{
bool PrimeiraExecucao = !Variaveis.DispositivosConectados.Any();
DispositivosConexaoInicial.ForEach(Dispositivo =>
{
IDispositivosService dispositivoService = Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Dispositivo);
if (dispositivoService == null)
{
dispositivoService = DispositivosServiceFactory.CreateDispositivoService(
Dispositivo,
"Nome: " + Enum.GetName(typeof(T_Code), Dispositivo),
"Descrição: " + string.Join(", ", DispositivosMapeados.Where(x => x.Dispositivo == Dispositivo).Select(x => x.Mod_ID).ToArray())
);
dispositivoService.CarregarParametrosModulos();
Variaveis.DispositivosConectados.Add(dispositivoService);
dispositivoService.Dados.IniciarRegistrador();
}
});
if (PrimeiraExecucao)
{
OperacaoModel.CarregarParametrosOperacaoPadrao(ModoOperacao.MapaGPS, true);
}
//DispositivosMapeados.ForEach(d => d.AtualizarDados());
}
private static async Task<bool> ProcurarDispositivosCAN(SerialPort Porta = null)
{
AtualizarConsole($"{Porta?.PortName ?? CanManager.CanService._portName ?? "CAN"} - Procurando dispositivos no barramento CAN");
bool porta_can = CanManager.CanService.PortaIsCan(Porta);
bool inicializou = !CanManager.CanService.Inicializar(250);
if (!porta_can || inicializou)
{
AtualizarConsole($"Adaptador {CanManager.CanService._portName ?? "CAN"} não conectado!");
var dispositivosRemover = DispositivosMapeados.Where(x => DispositivosCan.Contains(x.Dispositivo)).ToList();
foreach (var d in dispositivosRemover)
{
DispositivosMapeados.Remove(d);
}
return false;
}
if (true && Variaveis.OperacaoEmAndamento.DispSen != null && !Variaveis.OperacaoEmAndamento.DispSen.Dados.Conectado)
{
AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo SEN");
bool DispSen = await Variaveis.OperacaoEmAndamento.DispSen.Dados.VerificaDispositivoConectado();
if (DispSen)
{
AtualizarConsole("Dispositivo SEN encontrado");
}
}
if (true && Variaveis.OperacaoEmAndamento.DispAtu != null && !Variaveis.OperacaoEmAndamento.DispAtu.Dados.Conectado)
{
AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo ATU");
bool DispAtu = await Variaveis.OperacaoEmAndamento.DispAtu.Dados.VerificaDispositivoConectado();
if (DispAtu)
{
AtualizarConsole("Dispositivo ATU encontrado");
}
}
if (true && Variaveis.OperacaoEmAndamento.DispMvd != null && !MKS057DCanService.Referenciando && (!MKS057DCanService.Iniciado || MKS057DCanService.DadosLeitura.Count(x => x.Iniciado) < (Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.Count() ?? 4)))
{
AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivos MKS");
bool DispMks = await MKS057DCanService.VerificaDispositivoConectado();
if (DispMks)
{
AtualizarConsole("Dispositivo MKS encontrado");
}
}
if (true && Variaveis.OperacaoEmAndamento.DispMvd != null && (!OIDCanService.Iniciado || OIDCanService.DadosLeitura.Count(x => x.Iniciado) < (Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.Count() ?? 4)))
{
AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo OID");
bool DispOid = await OIDCanService.VerificaDispositivoConectado();
if (DispOid)
{
AtualizarConsole("Dispositivo OID encontrado");
}
}
if (true && !DalyBMSService.Iniciado)
{
AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo BAT");
bool DispBat = await DalyBMSService.VerificaDispositivoConectado();
if (DispBat)
{
AtualizarConsole("Dispositivo BAT encontrado");
}
}
return CanManager.CanService.Iniciado;
}
private static void ProcurarDispositivosUSB()
{
if (!Variaveis.IsAgroMonitor)
{
if (!KinectService.Iniciado)
{
KinectService.InicializarKinect();
}
if (GeneralJoystick.JoystickConectado == null)
{
GeneralJoystick.AtualizaDispositivo();
}
var _Cameras = CameraWorkerService.ListaCameras;
foreach (var cam in _Cameras)
{
var disp = HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == cam.dispositivo);
if (disp == null) continue;
var added = DispositivosMapeados.FirstOrDefault(x => x.Dispositivo == cam.dispositivo);
bool connected = disp.status != StatusModulo.Desconectado;
if (added == null && connected)
{
DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Dispositivo = cam.dispositivo,
Endereco = "USB",
Versao = cam.versao
});
}
else if (added != null && !connected)
{
DispositivosMapeados.Remove(added);
}
}
/*var _dMap = DispositivosMapeados.Where(x => x.Tipo == TipoConexao.USB).ToList();
foreach (var cam in _dMap)
{
bool camPresente = _Cameras.Any(x => x.Dispositivo == cam.Dispositivo);
if (!camPresente)
{
DispositivosMapeados.Remove(cam);
}
}*/
}
}
private static async Task<bool> ProcurarDispositivoLoRa(SerialPort porta)
{
AtualizarConsole($"{porta.PortName} - Procurando dispositivo LRA");
bool Encontrado = await LoRaBaseService.VerificaPortaLoRa(porta);
if (Encontrado)
{
AtualizarConsole("Dispositivo LRA encontrado");
return true;
}
porta.Close();
return false;
}
private static async Task<bool> ProcurarDispositivoGPS(SerialPort Porta)
{
SerialPort _porta = new SerialPort(Porta.PortName, 115200);
try
{
_porta.ReadTimeout = 500;
_porta.WriteTimeout = 500;
_porta.Handshake = Handshake.None;
_porta.DtrEnable = false;
_porta.RtsEnable = false;
_porta.Open();
await Task.Delay(100);
var nmea = $"gngga com3 1\r\n";
_porta.Write(Encoding.ASCII.GetBytes(nmea), 0, nmea.Length);
AtualizarConsole($"{_porta.PortName} - Procurando dispositivo GPS");
await Task.Delay(1000);
string Recebido = "";
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")) ||
(Recebido.Contains("$GNGGA") || Recebido.Contains("$GPVTG") || Recebido.Contains("$GPGSV") || Recebido.Contains("$GNTHS"))
)
{
GPSService.AtualizarPortaCOM(_porta);
AtualizarConsole("Dispositivo GPS encontrado");
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
finally
{
_porta.Close();
}
}
private static void ProcurarDispositivosEthernet()
{
var Lvx = HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Lvx);
if (Lvx != null)
{
var added = DispositivosMapeados.FirstOrDefault(x => x.Dispositivo == Lvx.modulo);
bool connected = Lvx.status != StatusModulo.Desconectado;
if (added == null && connected)
{
DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Dispositivo = Lvx.modulo,
Endereco = LivoxManagerProcess.DadosLeitura.lidar_ip,
Versao = LivoxManagerProcess.DadosLeitura.firmware_version,
Mod_ID = LivoxManagerProcess.DadosLeitura.dev_type,
});
}
else if (added != null && !connected)
{
DispositivosMapeados.Remove(added);
}
}
}
public static byte[] LerDadosDaPortaSerial(SerialPort porta, int tamanhoEsperado, int Timeout = 500)
{
DateTime inicio = DateTime.Now;
List<byte> buffer = new List<byte>();
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<byte[]> LerDadosDaPortaSerialAsync(SerialPort porta, int tamanhoEsperado, int Timeout = 500)
{
DateTime inicio = DateTime.Now;
List<byte> buffer = new List<byte>();
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();
}
private static void AtualizarConsole(string msg)
{
Console.WriteLine(msg);
if (!Variaveis.IsAgroMonitor)
{
if (frmInstancial.frmPrincipal.IsHandleCreated)
{
frmInstancial.frmPrincipal.Invoke((MethodInvoker)(() =>
{
frmInstancial.frmPrincipal.lblStatusConexao.Text = msg;
if (frmInstancial.frmIHM != null && frmInstancial.frmIHM.IsHandleCreated)
{
frmInstancial.frmIHM.lblStatus.Text = msg;
}
}));
}
else
{
// Opcional: armazenar a mensagem e aplicar depois
Console.WriteLine("frmPrincipal ainda não está pronto para receber Invoke.");
}
}
}
public static string MostrarComandoResposta(T_Code tipo, byte[] comando, byte[] resposta)
{
bool showCommands = true;
string msg = tipo.ToString() + " - TX: " + string.Join(" ", comando.Select(x => x.ToString("x"))) + ", RX: " + string.Join(" ", (resposta != null ? resposta : new byte[] { }).Select(x => x.ToString("x")));
if (showCommands)
{
Console.WriteLine(msg);
}
return msg;
}
}
}