using AgroBase.Models; using Newtonsoft.Json; using System.Diagnostics; using OperationControl.Services; using AgroMonitor; using Application = System.Windows.Application; using AgroBase.Models.Operacoes; using OperationControl.ViewModels; namespace OperationControl.Models { public class Variaveis { public static MqttService MqttService; public static GpsService GpsService; public static UdpReliableChannel UdpChannel; public static ManualControlSender ControlSenderDir; public static ManualControlSender ControlSenderMov; public static void MostrarLog(string message) { Debug.WriteLine(message); } public static async void IniciarMQTT() { if (MqttService != null) { foreach (var topico in MqttService.Topicos.Where(x => x.Inscrever)) { await MqttService.UnsubscribeAsync(topico); } MqttService.Topicos.Clear(); } MqttService = new MqttService("localhost", 1883, "base", true, msg => MostrarLog($"[MQTT localhost:1883] - {msg}")); await MqttService.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttPosicao); await MqttService.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM); await MqttService.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos, true, 1, async (message) => { try { var p = message.Mensagem.Split(','); if (string.IsNullOrEmpty(message.Mensagem) || p.Length < 2) return; string device_id = p[0]; string device_ip = p[1]; VariaveisControleOperacao.AdicionarNovoRoverNaRede(device_id, device_ip); } catch (Exception ex) { MostrarLog($"Erro ao deserializar ping do rover: {ex.Message}"); } }); GpsService = new GpsService(); } public static void IniciarUDP() { UdpChannel = new UdpReliableChannel { EnableHeartbeat = true, HeartbeatIntervalMs = 1000, HeartbeatPayload = new byte[] { 0 } }; UdpChannel.Start(VariaveisPortas.Ethernet_UDP_TX); ControlSenderDir = new ManualControlSender(UdpChannel, (byte)AgroBase.Models.Enums.T_Code.Dir); ControlSenderDir.Start(); ControlSenderMov = new ManualControlSender(UdpChannel, (byte)AgroBase.Models.Enums.T_Code.Mov); ControlSenderMov.Start(); } } public class VariaveisControleOperacao { public static double LeverArmFrontal { get; } = 0.0; // cm public static double LeverArmLateral { get; } = 0.0; // cm public static readonly string BaseMarkerID = "BASE"; private static readonly object _RoversLock = new object(); private static double TempoRoverVivo = 5.0; private static bool AdicionandoNovoRover = false; private static bool AtualizandoListaRovers = false; public static AgroBase.Models.Enums.StatusModulo StatusBase { get { if ((Variaveis.GpsService?.IsConnected ?? false) && (Variaveis.GpsService?.BaseFix?.CorrecaoAbsoluta ?? false)) return AgroBase.Models.Enums.StatusModulo.Operante; if (Variaveis.GpsService?.IsConnected ?? false) return AgroBase.Models.Enums.StatusModulo.Alerta; return AgroBase.Models.Enums.StatusModulo.Desconectado; } } public static List RoversNaRede { get; set; } = new List(); public static string SelectedRoverId { get; set; } = BaseMarkerID; public static OperacaoParametrosModel? RoverEmFoco => RoversNaRede.FirstOrDefault(x => x.RoverId == SelectedRoverId); public static bool BaseEmFoco => SelectedRoverId == BaseMarkerID; public static async void AdicionarNovoRoverNaRede(string device_id, string device_ip) { if (AdicionandoNovoRover) return; AdicionandoNovoRover = true; try { if (string.IsNullOrEmpty(device_id)) return; bool rover_ja_adicionado = false; lock (_RoversLock) { rover_ja_adicionado = RoversNaRede.Any(x => x.RoverId == device_id); } if (!rover_ja_adicionado) { lock (_RoversLock) { RoversNaRede.Add(new OperacaoParametrosModel() { RoverId = device_id, IP = device_ip, Configurado = false, Alive = true, DadosLeitura = new OperacaoParametrosDadosModel() { Momento = DateTime.Now } }); } bool t_hbt_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttHeartbeat.Replace("", device_id)); if (!t_hbt_added) await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttHeartbeat.Replace("", device_id)); bool t_cmd_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttComandos.Replace("", device_id)); if (!t_cmd_added) await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("", device_id)); bool t_tel_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttTelemetria.Replace("", device_id)); if (!t_tel_added) await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("", device_id), true, 1, async (message) => { try { string json = message.Mensagem; if (string.IsNullOrEmpty(json)) return; var obj = JsonConvert.DeserializeObject(json); if (obj == null) return; OperacaoParametrosModel rover; lock (_RoversLock) { rover = RoversNaRede.FirstOrDefault(x => x.RoverId == device_id); if (rover != null) { obj.Momento = DateTime.Now; var logs = rover.DadosLeitura?.Logs ?? new List(); obj.Logs?.InsertRange(0, logs); rover.DadosLeitura = obj; rover.UltimoContato = DateTime.Now; } } ((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(device_id); Application.Current.Dispatcher.BeginInvoke(new Action(() => { ((App)Application.Current).Shell.Dock?._vm?.AtualizarDadosTela(rover); })); } catch (Exception ex) { Variaveis.MostrarLog($"Erro ao deserializar dados de telemetria do rover {device_id}: {ex.Message}"); } }); bool t_par_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttParametros.Replace("", device_id)); if (!t_par_added) await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttParametros.Replace("", device_id), true, 1, async (message) => { try { string json = message.Mensagem; if (string.IsNullOrEmpty(json)) return; var obj = JsonConvert.DeserializeObject(json); lock (_RoversLock) { var rover = RoversNaRede.FirstOrDefault(x => x.RoverId == device_id); if (rover != null) { obj.UltimoContato = DateTime.Now; obj.IP = rover.IP; RoversNaRede.Remove(rover); RoversNaRede.Add(obj); } } ((App)Application.Current).Shell.Main?.AtualizarDadosTela_ParametrosOperacao(obj.Controle); ((App)Application.Current).Shell.Main?.MAP?.CarregarDadosMapa(obj.Mapa, obj.RuasPercorrer); ((App)Application.Current).Shell.Dock?._vm?.AtualizarParametrosRover(obj); } catch (Exception ex) { Variaveis.MostrarLog($"Erro ao deserializar dados de parametros do rover {device_id}: {ex.Message}"); } }); List dispositivos_ids = new List() { "BASE" }; lock (_RoversLock) { dispositivos_ids = dispositivos_ids.Union(RoversNaRede.Select(x => x.RoverId).ToList()).ToList(); } ((App)Application.Current).Shell.Main?.AtualizarListaDispositivos(dispositivos_ids); RequisitarParametrosOperacao(); } } finally { AdicionandoNovoRover = false; } } public static async void AtualizarListaRoversNaRede() { if (AtualizandoListaRovers) return; AtualizandoListaRovers = true; try { var rovers_atual = new List(); lock (_RoversLock) { rovers_atual = new List(RoversNaRede); } foreach (var rover in rovers_atual) { rover.Alive = AppShell.Mock || (DateTime.Now - rover.UltimoContato).TotalSeconds < TempoRoverVivo; if (!rover.Alive) { //((App)Application.Current).Shell.Main?.MAP?.markers?.UpdateMarkerInfo(rover.RoverId, status: AgroBase.Models.Enums.StatusOperacao.Erro); rover.DadosLeitura = new OperacaoParametrosDadosModel(); rover.DadosLeitura.Momento = DateTime.Now; if (rover.DadosLeitura.Operacao == null) rover.DadosLeitura.Operacao = new OperacaoParametrosDadosOperacaoModel(); rover.DadosLeitura.Operacao.Status = AgroBase.Models.Enums.StatusOperacao.Erro; ((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(rover.RoverId); ((App)Application.Current).Shell.Main?.AdicionarAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb, SeveridadeAlerta.Critical, "Perda de comunicação com o equipamento!"); ((App)Application.Current).Shell?.AdicionarAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb, SeveridadeAlerta.Critical, "Perda de comunicação com o equipamento!"); } else { ((App)Application.Current).Shell.Main?.RemoverAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb); ((App)Application.Current).Shell.RemoverAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb); } } Application.Current.Dispatcher.BeginInvoke(new Action(() => { ((App)Application.Current).Shell.Dock?._vm?.AtualizarListaRovers(rovers_atual); })); } finally { AtualizandoListaRovers = false; } } public static async void EnviarDadosHeartbeat() { var topicos = Variaveis.MqttService.Topicos.Where(x => x.Topico.Contains(VariaveisEquipamento.TopicoMqttHeartbeat.Split("/")[VariaveisEquipamento.TopicoMqttHeartbeat.Split("/").Length - 1])); foreach (var topico in topicos) { await Variaveis.MqttService.PublishAsync(topico, "0"); } } private static async void EnviarDadosControle(string rover_id, OperacaoComandoBaseModel controle) { var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttComandos.Replace("", rover_id)); if (topico != null) { string json = JsonConvert.SerializeObject(controle); await Variaveis.MqttService.PublishAsync(topico, json); } } public static async void EnviarDadosPosicao(GPSModel posicao) { var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisMonitoramento.TopicoMqttPosicao); if (topico != null) { string json = JsonConvert.SerializeObject(posicao); await Variaveis.MqttService.PublishAsync(topico, json); } } public static async void EnviarDadosCorrecaoRTCM(byte[] correcao) { var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisMonitoramento.TopicoMqttRTCM); if (topico != null) { await Variaveis.MqttService.PublishAsync(topico, correcao); } } #region Controle public static void EnviarComandoIniciarUDP(string ipRover, bool iniciar) { if (iniciar) Variaveis.UdpChannel.SetRemote(ipRover, VariaveisPortas.Ethernet_UDP_RX); else Variaveis.UdpChannel.SetRemote(null, VariaveisPortas.Ethernet_UDP_RX); EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Ipb, _comp_value = iniciar }); } public static void EnviarComandoIniciarOperacao(bool iniciar, bool simulador = false) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Mod, Tecla = simulador ? AgroBase.Models.Enums.BotoesJoystick.L1 : iniciar ? AgroBase.Models.Enums.BotoesJoystick.L2 : AgroBase.Models.Enums.BotoesJoystick.L3 }); } public static void EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code disp, bool ligar, AgroBase.Models.Enums.TipoFrameCamera tipoFrame) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = disp, Tecla = ligar ? AgroBase.Models.Enums.BotoesJoystick.L1 : AgroBase.Models.Enums.BotoesJoystick.Vazio, _comp_value = tipoFrame }); } public static void EnviarComandoParada(bool? emergencia = null, bool? pausa = null) { var cmd = new OperacaoComandoBaseModel() { Momento = DateTime.Now }; if (emergencia != null) cmd.Emergencia = (bool)emergencia; if (pausa != null) cmd.Pausa = (bool)pausa; if (emergencia != null || pausa != null) EnviarDadosControle(SelectedRoverId, cmd); } public static Task EnviarComandoParadaUDP(bool emergencia = false, bool pausa = false) { var msg = new UdpCtrlMessage { Device = (byte)AgroBase.Models.Enums.T_Code.Vzo, Flags = (emergencia ? UdpCtrlFlags.Emergencia : 0) | (pausa ? UdpCtrlFlags.Pausa : 0) }; return Variaveis.UdpChannel.SendBurstAsync(0x01, msg.ToBytes(), count: 6, intervalMs: 25, requestAck: false); } public static void EnviarComandoReferenciamento(string mod_id = null) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Dir, Tecla = AgroBase.Models.Enums.BotoesJoystick.R3, _comp_id = mod_id }); } public static void EnviarComandoLeverArm(double? lateral = null, double? frontal = null) { var cmd = new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Gps, _comp_value = (lateral, frontal) }; EnviarDadosControle(SelectedRoverId, cmd); } public static void EnviarParametrosOperacao(OperacaoParametrosModel parametros) { bool operacao_iniciada = (RoverEmFoco?.DadosLeitura?.Operacao?.Iniciada ?? false); bool parametros_parciais = parametros.Modo == null; EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Mod, Parametros = parametros, Tecla = (operacao_iniciada || parametros_parciais ? AgroBase.Models.Enums.BotoesJoystick.Touchpad : AgroBase.Models.Enums.BotoesJoystick.Options) }); } public static void EnviarConfirmacaoHumanaTrajetoria(int idx_corredor, bool bat_liberada, bool herb_liberado) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Mod, Tecla = AgroBase.Models.Enums.BotoesJoystick.R1, _comp_value = (idx_corredor, bat_liberada, herb_liberado) }); } public static void EnviarComandoCoolerControl(AgroBase.Services.CoolerControlService.CoolerMode modo, AgroBase.Models.Enums.Estado? entrada = null, AgroBase.Models.Enums.Estado? saida = null, double? temp_on = null, double? temp_turbo = null) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Npc, _comp_value = (modo, entrada, saida, temp_on, temp_turbo) }); } public static void RequisitarParametrosOperacao() { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Mod, Tecla = AgroBase.Models.Enums.BotoesJoystick.Share }); } private static AgroBase.Models.Enums.BotoesJoystick DeParaDirecaoTecla(AgroBase.Models.Enums.Direcao direcao) { switch (direcao) { case AgroBase.Models.Enums.Direcao.Esquerda: return AgroBase.GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.key == Keys.Left)?.botaoJoy ?? AgroBase.Models.Enums.BotoesJoystick.Vazio; case AgroBase.Models.Enums.Direcao.Direita: return AgroBase.GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.key == Keys.Right)?.botaoJoy ?? AgroBase.Models.Enums.BotoesJoystick.Vazio; case AgroBase.Models.Enums.Direcao.Cima: return AgroBase.GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.key == Keys.Up)?.botaoJoy ?? AgroBase.Models.Enums.BotoesJoystick.Vazio; case AgroBase.Models.Enums.Direcao.Baixo: return AgroBase.GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.key == Keys.Down)?.botaoJoy ?? AgroBase.Models.Enums.BotoesJoystick.Vazio; default: return AgroBase.Models.Enums.BotoesJoystick.Vazio; } } public static void EnviarComandoDirecional(AgroBase.Models.Enums.Direcao direcao, double angulo, AgroBase.Models.Enums.TipoMovimentoDirecional movimento, string mod_id = null) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Dir, Tecla = DeParaDirecaoTecla(direcao), _comp_id = mod_id, Controle = new OperacaoComandoBaseControleModel() { AnguloSP = angulo, TipoMovimentoDirecional = movimento }, }); } public static void EnviarComandoDirecionalUDP(AgroBase.Models.Enums.Direcao direcao, double angulo, AgroBase.Models.Enums.TipoMovimentoDirecional tipoMov) { var key = DeParaDirecaoTecla(direcao); var msg = new UdpCtrlMessage { Device = (byte)AgroBase.Models.Enums.T_Code.Dir, Flags = UdpCtrlFlags.HasKey | UdpCtrlFlags.HasPayload, Key = key, P1 = (short)Math.Max(short.MinValue, Math.Min(short.MaxValue, (int)Math.Round(angulo * 100.0))), P2 = (short)tipoMov }; //return Variaveis.UdpChannel.SendBurstAsync(0x01, msg.ToBytes(), count: 6, intervalMs: 25, requestAck: false); Variaveis.ControlSenderDir.Update(msg); } public static void EnviarComandoMovimentacao(AgroBase.Models.Enums.Direcao direcao, double velocidade) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Mov, Tecla = DeParaDirecaoTecla(direcao), Controle = new OperacaoComandoBaseControleModel() { PercentualVelocidadeSP = velocidade } }); } public static void EnviarComandoMovimentacaoUDP(AgroBase.Models.Enums.Direcao direcao, double velPct) { var key = DeParaDirecaoTecla(direcao); var msg = new UdpCtrlMessage { Device = (byte)AgroBase.Models.Enums.T_Code.Mov, Flags = UdpCtrlFlags.HasKey | UdpCtrlFlags.HasPayload, Key = key, P1 = (short)Math.Max(short.MinValue, Math.Min(short.MaxValue, (int)Math.Round(velPct * 100.0))), P2 = 0 }; //return Variaveis.UdpChannel.SendBurstAsync(0x01, msg.ToBytes(), count: 6, intervalMs: 25, requestAck: false); Variaveis.ControlSenderMov.Update(msg); } public static void EnviarComandoAtuador(string componente_id, bool? status = null, int? angulo_controle = null, double? angulo_abertura = null, double? altura = null) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Atu, _comp_id = componente_id, _comp_value = angulo_abertura, Controle = new OperacaoComandoBaseControleModel() { AnguloSP = angulo_controle, Estado = status, Altura = altura, } }); } public static void EnviarComandoSensoriamento(string componente_id, dynamic status) { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Sen, _comp_id = componente_id, _comp_value = status }); } public static void EnviarComandoRetornoBase(double? lat = null, double? lon = null, List pontosRetorno = null) { var cmd = new OperacaoComandoBaseModel() { Momento = DateTime.Now, Dispositivo = AgroBase.Models.Enums.T_Code.Trj, _comp_value = (lat, lon, pontosRetorno) }; EnviarDadosControle(SelectedRoverId, cmd); } #endregion } }