Ajustes pontuais no OPControl e enxugada nos dados de telemetria

This commit is contained in:
Diego Freitas 2026-03-04 15:55:52 -03:00
parent 8ea61c158e
commit 4f387a834a
20 changed files with 1206 additions and 65 deletions

View File

@ -499,9 +499,6 @@ namespace AgroBase.Forms.Operacoes
gridDados.Rows.Add("Roll", "", "");
gridDados.Rows.Add("Pitch", "", "");
gridDados.Rows.Add("Yaw", "", "");
gridDados.Rows.Add("Temperatura", "", "");
gridDados.Rows.Add("Pressao", "", "");
gridDados.Rows.Add("Altitude", "", "");
gridDados.Rows.Add("Temperatura ET", "", "");
gridDados.Rows.Add("Temperatura EF", "", "");
gridDados.Rows.Add("Temperatura DT", "", "");
@ -558,9 +555,6 @@ namespace AgroBase.Forms.Operacoes
gridDados.Rows[37].Cells[1].Value = (_Sensoriamento.IMU.InclinacaoLateral).ToString("0.00");
gridDados.Rows[38].Cells[1].Value = (_Sensoriamento.IMU.InclinacaoFrontal).ToString("0.00");
gridDados.Rows[39].Cells[1].Value = (_Sensoriamento.IMU.Rotacao).ToString("0.00");
gridDados.Rows[40].Cells[1].Value = (_Sensoriamento.IMU.Temperatura).ToString("0.00");
gridDados.Rows[41].Cells[1].Value = (_Sensoriamento.IMU.Pressao).ToString("0.00");
gridDados.Rows[42].Cells[1].Value = (_Sensoriamento.IMU.Altitude).ToString("0.00");
}
#endregion

View File

@ -1444,9 +1444,9 @@ namespace AgroBase.Forms.Operacoes
pnlOrientacaoMagnetometro.Invalidate();
pnlInclinacao.Invalidate();
visualizador3D.AtualizarAngulos(LogImu.InclinacaoFrontal, LogImu.InclinacaoLateral, -LogsOperacao[idxMomentoAtual].Gps.OrientacaoReal);
txtTemperatura.Text = LogImu.Temperatura.ToString("0.00");
txtAltitude.Text = LogImu.Altitude.ToString("0.00");
txtPressao.Text = LogImu.Pressao + " Pa (" + (LogImu.Pressao / 101300.0).ToString("0.00") + " atm)";
//txtTemperatura.Text = LogImu.Temperatura.ToString("0.00");
//txtAltitude.Text = LogImu.Altitude.ToString("0.00");
//txtPressao.Text = LogImu.Pressao + " Pa (" + (LogImu.Pressao / 101300.0).ToString("0.00") + " atm)";
}
var LogSen = LogsSensoriamento.FirstOrDefault(x => x.Momento == MomentoAtual);

View File

@ -166,4 +166,16 @@ namespace AgroBase.Models
}
}
public class OAKImuModel
{
public double timestamp { get; set; }
public double roll { get; set; }
public double pitch { get; set; }
public double yaw { get; set; }
public double yaw_fixed { get; set; }
public double vel_mps { get; set; }
public double latencia { get; set; }
public double frequencia { get; set; }
}
}

View File

@ -1006,6 +1006,7 @@ namespace AgroBase.Models
public async Task IniciarOperacao()
{
Variaveis.OperacaoEmAndamento.Sensoriamento.UltimoRegistroLog = DateTime.Now;
tmrLogs?.Start();
Iniciado = true;
@ -1695,6 +1696,7 @@ namespace AgroBase.Models
if (topico != null && !string.IsNullOrEmpty(msg))
{
await Variaveis.MqttServiceBase.PublishAsync(topico, msg);
Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.UltimoEnvioLog = DateTime.Now;
}
}
@ -1733,6 +1735,7 @@ namespace AgroBase.Models
OperacaoSensoriamentoLogModel logGeral = Variaveis.OperacaoEmAndamento.Sensoriamento.Clone();
logGeral.Momento = Agora;
SalvarLog("operacao", logGeral, Fim);
Variaveis.OperacaoEmAndamento.Sensoriamento.UltimoRegistroLog = DateTime.Now;
Variaveis.OperacaoEmAndamento.Controle.TiposControle.ForEach(x => x.Comandos.Clear());
Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.ForEach(Modulo =>
@ -2289,6 +2292,7 @@ namespace AgroBase.Models
public Dictionary<T_Code, Dictionary<string, bool>> ModsCalibragem { get; set; }
public bool CanSerialAtivado { get; set; }
public List<OperacaoSensoriamentoLogErrosModel> Logs { get; set; }
public DateTime UltimoRegistroLog { get; set; } = DateTime.MinValue;
public CoolerControlDataModel CoolerControl { get; set; }
public void InserirLog(T_Code dispositivo, StatusModulo status, double saude, string mensagem, string id = null, string condicoes = null)
@ -2338,7 +2342,8 @@ namespace AgroBase.Models
_Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs);
_Trajetoria?.AtualizarDadosAutonomiaCorredor();
var sIMU = LivoxManagerProcess.DadosLeitura.imu;
//var sIMU = LivoxManagerProcess.DadosLeitura.imu;
var sIMU = JsonConvert.DeserializeObject<OAKImuModel>(RedisService.Get(RedisService.ModKey(T_Code.Imu)));
var dadosIMU = sIMU != null ? new OperacaoSensoriamentoLogImuModel()
{
Iniciado = sIMU.timestamp > 0 && HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Imu)?.status != StatusModulo.Desconectado,
@ -2565,7 +2570,7 @@ namespace AgroBase.Models
ModulosSaude = HealthWorkerService.ModulosSaude.ToList(),
DispositivosMapeados = new List<DispositivoDetalhesModel>(SerialService.DispositivosMapeados),
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(Variaveis.OperacaoEmAndamento.ModsCalibragem),
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
Logs = Logs != null ? Logs.Where(x => x.Momento >= UltimoRegistroLog).ToList() : new List<OperacaoSensoriamentoLogErrosModel>(),
CoolerControl = dadosCooler
};
@ -2616,6 +2621,7 @@ namespace AgroBase.Models
DispositivosMapeados = new List<DispositivoDetalhesModel>(DispositivosMapeados),
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(ModsCalibragem),
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
UltimoRegistroLog = UltimoRegistroLog,
CoolerControl = CoolerControl?.Clone(),
};
}
@ -2629,9 +2635,6 @@ namespace AgroBase.Models
public double InclinacaoFrontal { get; set; }
public double Rotacao { get; set; }
public double RotacaoCorrigida { get; set; }
public double Temperatura { get; set; }
public double Pressao { get; set; }
public double Altitude { get; set; }
public OperacaoSensoriamentoLogImuModel Clone()
{
@ -2642,9 +2645,6 @@ namespace AgroBase.Models
InclinacaoFrontal = InclinacaoFrontal,
Rotacao = Rotacao,
RotacaoCorrigida = RotacaoCorrigida,
Temperatura = Temperatura,
Pressao = Pressao,
Altitude = Altitude
};
}
}

View File

@ -77,8 +77,8 @@ namespace AgroBase.Models.Operacoes
public StatusModulo StatusRover { get; set; }
public bool CanSerial { get; set; }
public OperacaoParametrosDadosOperacaoModel Operacao { get; set; }
public OperacaoSensoriamentoLogTrajetoriaModel Trajetoria { get; set; }
public OperacaoControleModel Controle { get; set; }
public OperacaoParametrosDadosTrajetoriaModel Trajetoria { get; set; }
public OperacaoParametrosDadosControleModel Controle { get; set; }
public List<ManagerWorkerMessageResponseModulosPendentesModel> ModulosSaude { get; set; }
public List<DispositivoDetalhesModel> DispositivosMapeados { get; set; }
public OperacaoSensoriamentoLogImuModel Imu { get; set; }
@ -91,6 +91,7 @@ namespace AgroBase.Models.Operacoes
public OperacaoParametrosDadosGNSSModel Gnss { get; set; }
public PerformanceModel PerformanceNcp { get; set; }
public LivoxModel LivoxLidar { get; set; }
public DateTime UltimoEnvioLog { get; set; } = DateTime.MinValue;
public List<OperacaoSensoriamentoLogErrosModel> Logs { get; set; }
public void Atualizar()
@ -122,14 +123,57 @@ namespace AgroBase.Models.Operacoes
ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>(op.Parametros.ModulosMandatorios ?? new List<OperacaoModulosMandatoriosModel>()),
ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>(op.Parametros.ParametrosMandatorios ?? new List<OperacaoParametrosMandatoriosModel>())
};
Trajetoria = sen?.Trajetoria?.Clone();
Controle = op.Controle?.Clone();
var t = sen?.Trajetoria;
Trajetoria = t != null ? new OperacaoParametrosDadosTrajetoriaModel()
{
AutonomiaCorredor = new OperacaoParametrosDadosTrajetoriaAutonomiaCorredorModel()
{
BateriaSuficiente = t.AutonomiaCooredor.BateriaSuficiente,
DistanciaCorredor_m = t.AutonomiaCooredor.DistanciaSeguraBateria_m,
DistanciaSeguraBateria_m = t.AutonomiaCooredor.DistanciaSeguraBateria_m,
DistanciaSeguraHerbicida_m = t.AutonomiaCooredor.DistanciaSeguraBateria_m,
HerbicidaSuficiente = t.AutonomiaCooredor.HerbicidaSuficiente,
Liberado = t.AutonomiaCooredor.Liberado,
Motivo = t.AutonomiaCooredor.Motivo,
Status = t.AutonomiaCooredor.Status
},
AnguloCaminho = t.AnguloCaminho,
CorredorAtualDentro = t.CorredorAtual.Dentro,
CorredorAtualDistanciaPercorrida = t.CorredorAtual.DistanciaPercorridaCorredor,
CorredorAtualDistanciaTotal = t.CorredorAtual.DistanciaTotal,
CorredorAtualIdx = t.CorredorAtual.Idx,
DistanciaDireita = t.DistanciaDireita,
DistanciaEsquerda = t.DistanciaEsquerda,
DistanciaPercorrida = t.DistanciaPercorrida,
DistanciaTotal = t.DistanciaTotal,
NaMargemDoCorredor = t.NaMargemDoCorredor,
PercentualOperacao = t.PercentualOperacao,
PercentualRuaAtual = t.PercentualRuaAtual,
PontoAtualDistanciaAtual = t.PontoAtual.DistanciaAtual,
PontoAtualIdx = t.PontoAtual.idxPonto,
ProximoPontoAproximando = t.ProximoPonto.Aproximando,
ProximoPontoDistanciaAtual = t.ProximoPonto.DistanciaAtual,
ProximoPontoIdx = t.ProximoPonto.idxPonto,
QtdPontos = t.QtdPontos,
StatusCarro = t.StatusCarro,
TempoEstimadoOperacao = t.TempoEstimadoOperacao
} : new OperacaoParametrosDadosTrajetoriaModel();
var c = op.Controle?.Clone();
Controle = c != null ? new OperacaoParametrosDadosControleModel()
{
Angulo = c.Angulo,
AlturaBarra = c.AlturaBarra,
PercentualVelocidadeSPKmh = c.PercentualVelocidadeSPKmh,
TipoMovimento = c.TipoMovimento,
SimulacaoMPC = c.SimulacaoMPC,
} : new OperacaoParametrosDadosControleModel();
ModulosSaude = new List<ManagerWorkerMessageResponseModulosPendentesModel>(sen?.ModulosSaude ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>());
DispositivosMapeados = new List<DispositivoDetalhesModel>(sen?.DispositivosMapeados ?? new List<DispositivoDetalhesModel>());
Imu = sen?.IMU?.Clone();
Atuador = new OperacaoParametrosDadosAtuadorModel()
{
Iniciado = dAtu?.Conectado ?? false,
Latencia = dAtu?.DadosLeitura?.LatenciaLoop ?? 0,
AnguloBarraAltura = sen?.Atuador?.AnguloBarraAltura ?? 0,
AnguloBarraDireita = sen?.Atuador?.AnguloBarraDireita ?? 0,
@ -208,6 +252,8 @@ namespace AgroBase.Models.Operacoes
Sensoriamento = new OperacaoParametrosDadosSensoriamentoModel()
{
Iniciado = dSen?.Conectado ?? false,
Latencia = dSen?.DadosLeitura?.LatenciaLoop ?? 0,
Sensores = dSen?.Sensores?.Select(x => new OperacaoParametrosDadosSensorModel()
{
Componente = x.Componente,
@ -322,7 +368,8 @@ namespace AgroBase.Models.Operacoes
};
PerformanceNcp = sen?.DadosPerformance?.Clone();
LivoxLidar = sen?.LivoxLidar?.Clone();
Logs = new List<OperacaoSensoriamentoLogErrosModel>(sen?.Logs ?? new List<OperacaoSensoriamentoLogErrosModel>());
var l = sen?.Logs;
Logs = l != null ? l.Where(x => x.Momento >= UltimoEnvioLog).ToList() : new List<OperacaoSensoriamentoLogErrosModel>();
}
public OperacaoParametrosDadosModel Clone()
@ -347,7 +394,8 @@ namespace AgroBase.Models.Operacoes
Gnss = Gnss,
PerformanceNcp = PerformanceNcp?.Clone(),
LivoxLidar = LivoxLidar?.Clone(),
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>())
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
UltimoEnvioLog = UltimoEnvioLog
};
}
@ -370,9 +418,97 @@ namespace AgroBase.Models.Operacoes
public List<OperacaoParametrosMandatoriosModel> ParametrosMandatorios { get; set; }
}
public class OperacaoParametrosDadosTrajetoriaModel
{
public StatusCarroMapa StatusCarro { get; set; }
public int QtdPontos { get; set; }
public double AnguloCaminho { get; set; }
public bool NaMargemDoCorredor { get; set; }
public OperacaoParametrosDadosTrajetoriaAutonomiaCorredorModel AutonomiaCorredor { get; set; }
public int ProximoPontoIdx { get; set; }
public bool ProximoPontoAproximando { get; set; }
public double ProximoPontoDistanciaAtual { get; set; }
public int PontoAtualIdx { get; set; }
public double PontoAtualDistanciaAtual { get; set; }
public double DistanciaEsquerda { get; set; }
public double DistanciaDireita { get; set; }
public double PercentualRuaAtual { get; set; }
public double PercentualOperacao { get; set; }
public double DistanciaPercorrida { get; set; }
public double DistanciaTotal { get; set; }
public string TempoEstimadoOperacao { get; set; }
public bool CorredorAtualDentro { get; set; }
public double CorredorAtualIdx { get; set; }
public double CorredorAtualDistanciaTotal { get; set; }
public double CorredorAtualDistanciaPercorrida { get; set; }
public OperacaoParametrosDadosTrajetoriaModel Clone()
{
return new OperacaoParametrosDadosTrajetoriaModel()
{
TempoEstimadoOperacao = TempoEstimadoOperacao,
StatusCarro = StatusCarro,
QtdPontos = QtdPontos,
ProximoPontoIdx = ProximoPontoIdx,
ProximoPontoDistanciaAtual = ProximoPontoDistanciaAtual,
AnguloCaminho = AnguloCaminho,
AutonomiaCorredor = AutonomiaCorredor,
CorredorAtualDentro = CorredorAtualDentro,
CorredorAtualDistanciaPercorrida = CorredorAtualDistanciaPercorrida,
CorredorAtualDistanciaTotal = CorredorAtualDistanciaTotal,
CorredorAtualIdx = CorredorAtualIdx,
DistanciaDireita = DistanciaDireita,
DistanciaEsquerda = DistanciaEsquerda,
DistanciaPercorrida = DistanciaPercorrida,
DistanciaTotal = DistanciaTotal,
NaMargemDoCorredor = NaMargemDoCorredor,
PercentualOperacao = PercentualOperacao,
PercentualRuaAtual = PercentualRuaAtual,
PontoAtualDistanciaAtual = PontoAtualDistanciaAtual,
PontoAtualIdx = PontoAtualIdx,
ProximoPontoAproximando = ProximoPontoAproximando,
};
}
}
public class OperacaoParametrosDadosTrajetoriaAutonomiaCorredorModel
{
public AutonomiaCorredorStatus Status { get; set; }
public double DistanciaCorredor_m { get; set; }
public double DistanciaSeguraBateria_m { get; set; }
public double DistanciaSeguraHerbicida_m { get; set; }
public bool BateriaSuficiente { get; set; }
public bool HerbicidaSuficiente { get; set; }
public bool Liberado { get; set; }
public string Motivo { get; set; }
}
public class OperacaoParametrosDadosControleModel
{
public double AlturaBarra { get; set; }
public double Angulo { get; set; }
public TipoMovimentoDirecional TipoMovimento { get; set; }
public double PercentualVelocidadeSPKmh { get; set; }
public List<MPCSimulacaoModel> SimulacaoMPC { get; set; } = new List<MPCSimulacaoModel>();
public OperacaoParametrosDadosControleModel Clone()
{
return new OperacaoParametrosDadosControleModel()
{
AlturaBarra = AlturaBarra,
Angulo = Angulo,
PercentualVelocidadeSPKmh = PercentualVelocidadeSPKmh,
TipoMovimento = TipoMovimento,
SimulacaoMPC = SimulacaoMPC
};
}
}
public class OperacaoParametrosDadosAtuadorModel
{
public bool Iniciado { get; set; }
public double Latencia { get; set; }
public double CapacidadeReservatorio { get; set; }
@ -510,6 +646,7 @@ namespace AgroBase.Models.Operacoes
public class OperacaoParametrosDadosSensoriamentoModel
{
public bool Iniciado { get; set; }
public double Latencia { get; set; }
public List<OperacaoParametrosDadosSinaleiroModel> Sinaleiros { get; set; }
public List<OperacaoParametrosDadosSensorModel> Sensores { get; set; }

View File

@ -113,6 +113,7 @@ namespace OperationControl.Controls
if (VariaveisControleOperacao.RoverEmFoco != null)
{
VariaveisControleOperacao.RoverEmFoco!.Controle.MovimentoAutomatico = !manual_on;
VariaveisControleOperacao.RoverEmFoco!.Controle.DirecionalAutomatico = !manual_on;
VariaveisControleOperacao.EnviarParametrosOperacao(new AgroBase.Models.Operacoes.OperacaoParametrosModel()
{
Controle = VariaveisControleOperacao.RoverEmFoco?.Controle

View File

@ -0,0 +1,28 @@
// Helpers/RelayCommand.cs
using System;
using System.Windows.Input;
namespace OperationControl.Helpers
{
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute?.Invoke(parameter) ?? true;
public void Execute(object parameter) => _execute(parameter);
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
}

View File

@ -13,6 +13,7 @@ namespace OperationControl.Models
private bool tmrComunicacaoTicking = false;
public MainWindow Main { get; private set; }
public DockWindow Dock { get; private set; }
public void Inicializar()
{
@ -29,7 +30,8 @@ namespace OperationControl.Models
{
// Aqui você decide qual janela é a inicial de fato
Main = new MainWindow();
Main.Show();
Dock = new DockWindow();
Dock.Show();
}
private void tmrComunicacao_Elapsed()

View File

@ -43,6 +43,15 @@
<Compile Update="Controls\TemperatureIndicator.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\ConfigConexaoView.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Windows\DockWindow.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Windows\NetworkConfigWindow.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\AttitudeIndicator.xaml">
@ -81,8 +90,17 @@
<Page Update="Controls\TemperatureIndicator.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Views\ConfigConexaoView.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Windows\DockWindow.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Windows\MainWindow.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Windows\NetworkConfigWindow.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>

View File

@ -75,7 +75,7 @@ namespace OperationControl.Services
bool achou = await TryConnectOnPortAsync(portName, timeoutPorPortaMs, ct);
if (achou)
{
await ConfigurarModulo();
await ConfigurarModulo(false);
return true;
}
}
@ -240,11 +240,13 @@ namespace OperationControl.Services
private List<byte> _rtcmMsg = new();
private int _rtcmTotalBytes = -1;
public async Task ConfigurarModulo()
public async Task ConfigurarModulo(bool fixar)
{
Models.Variaveis.MostrarLog("Iniciando configuração do módulo GPS...");
LeverArm = new GeoLeverArm(VariaveisControleOperacao.LeverArmFrontal, VariaveisControleOperacao.LeverArmLateral);
BaseFix = new BaseFixService(PortaGps, this);
if (fixar)
{
bool sucesso = await BaseFix.FixarBaseViaNtripAsync(
portaUsb: "com3",
portaSaida: "com3",
@ -271,6 +273,12 @@ namespace OperationControl.Services
BaseFix.inicioFix = DateTime.UtcNow;
}
}
else
{
await BaseFix.ConfigurarComoRoverParadoAsync(portaUsb: "com3", portaEntrada: "com3");
}
}
private async Task ConfigurarModuloBase(string porta_usb = "com3", string porta_saida = "com2", int tempo_fixacao = 60)
{
@ -309,9 +317,17 @@ namespace OperationControl.Services
await Task.Delay(2000);
foreach (string cmd in comandos)
{
try
{
byte[] bytes = Encoding.ASCII.GetBytes(cmd);
PortaGps.Write(bytes, 0, bytes.Length);
}
catch (Exception ex)
{
Models.Variaveis.MostrarLog($"Erro ao enviar comando para o GNSS: {ex.Message}");
}
await Task.Delay(500);
}
}
@ -1066,6 +1082,8 @@ namespace OperationControl.Services
byte[] buffer = new byte[4096];
int bytesRead;
while (CorrecaoRTK_Ntrip && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
try
{
if (PortaGps?.IsOpen ?? false)
{
@ -1073,6 +1091,11 @@ namespace OperationControl.Services
//Console.WriteLine($"Enviando {bytesRead} bytes de correção RTCM para o GPS");
}
}
catch (Exception ex)
{
Models.Variaveis.MostrarLog($"Erro ao enviar correção RTCM para o módulo GNSS: {ex.Message}");
}
}
}
else
{
@ -1211,13 +1234,13 @@ namespace OperationControl.Services
try
{
if (!gpsService.Ntrip_Conectado)
{
Models.Variaveis.MostrarLog("Ntrip não conectado.");
CorrecaoAbsoluta = false;
FixLiberado = false;
return CorrecaoAbsoluta;
}
//if (!gpsService.Ntrip_Conectado)
//{
// Models.Variaveis.MostrarLog("Ntrip não conectado.");
// CorrecaoAbsoluta = false;
// FixLiberado = false;
// return CorrecaoAbsoluta;
//}
// 2) Esperar FIX sustentado e coletar GNGGA
var amostras = await EsperarFixEAmostrarAsync();
@ -1251,7 +1274,7 @@ namespace OperationControl.Services
}
// ===== 1.1 Rover parado + NMEA + limpar logs =====
private async Task ConfigurarComoRoverParadoAsync(string portaUsb, string portaEntrada)
public async Task ConfigurarComoRoverParadoAsync(string portaUsb, string portaEntrada)
{
Models.Variaveis.MostrarLog("Configurando base como modo rover parado...");
string freq = "1.0";
@ -1277,9 +1300,16 @@ namespace OperationControl.Services
await Task.Delay(1000);
foreach (var c in cmds)
{
try
{
var b = Encoding.ASCII.GetBytes(c);
_Porta.Write(b, 0, b.Length);
}
catch (Exception ex)
{
Models.Variaveis.MostrarLog($"Erro ao enviar comando de configuração GNSS: {ex.Message}");
}
await Task.Delay(250);
}
}

View File

@ -0,0 +1,232 @@
// ViewModels/ConfigConexaoViewModel.cs
using System;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows.Threading;
using OperationControl.Helpers;
using OperationControl.Models;
namespace OperationControl.ViewModels
{
public class ConfigConexaoViewModel : INotifyPropertyChanged
{
public event Action SolicitarConfigRede;
private readonly DispatcherTimer _timerGnss;
public ConfigConexaoViewModel()
{
AbrirConfigRedeCommand = new RelayCommand(_ => AbrirConfigRede());
AbrirDetalhesGnssCommand = new RelayCommand(_ => AbrirDetalhesGnss());
// aqui você já pode chamar um serviço real depois
CarregarStatusInicial();
_timerGnss = new DispatcherTimer();
_timerGnss.Interval = TimeSpan.FromMilliseconds(800); // 0.8s fica responsivo
_timerGnss.Tick += (_, __) => AtualizarStatusGnss();
_timerGnss.Start();
}
// ====== PROPRIEDADES DE REDE ======
private bool _redeOk;
public bool RedeOk
{
get => _redeOk;
set
{
if (_redeOk != value)
{
_redeOk = value;
OnPropertyChanged(nameof(RedeOk));
OnPropertyChanged(nameof(StatusRedeTexto));
OnPropertyChanged(nameof(CorStatusRede));
OnPropertyChanged(nameof(CorBordaRede));
OnPropertyChanged(nameof(TudoOk));
OnTudoOkChanged();
}
}
}
private string _detalhesRede;
public string DetalhesRede
{
get => _detalhesRede;
set { _detalhesRede = value; OnPropertyChanged(nameof(DetalhesRede)); }
}
public string StatusRedeTexto => RedeOk ? "Rede configurada" : "Rede com problema";
public Brush CorStatusRede => RedeOk ? Brushes.LightGreen : Brushes.OrangeRed;
public Brush CorBordaRede => RedeOk ? Brushes.LightGreen : Brushes.OrangeRed;
// ====== PROPRIEDADES DE GNSS ======
private bool _gnssOk;
public bool GnssOk
{
get => _gnssOk;
set
{
if (_gnssOk != value)
{
_gnssOk = value;
OnPropertyChanged(nameof(GnssOk));
OnPropertyChanged(nameof(StatusGnssTexto));
OnPropertyChanged(nameof(CorStatusGnss));
OnPropertyChanged(nameof(CorBordaGnss));
OnPropertyChanged(nameof(TudoOk));
OnTudoOkChanged();
}
}
}
private string _detalhesGnss;
public string DetalhesGnss
{
get => _detalhesGnss;
set { _detalhesGnss = value; OnPropertyChanged(nameof(DetalhesGnss)); }
}
public string StatusGnssTexto => GnssOk ? "GNSS conectado" : "GNSS não detectado";
public Brush CorStatusGnss => GnssOk ? Brushes.LightGreen : Brushes.OrangeRed;
public Brush CorBordaGnss => GnssOk ? Brushes.LightGreen : Brushes.OrangeRed;
// ====== MENSAGEM GERAL ======
private string _mensagemGeral;
public string MensagemGeral
{
get => _mensagemGeral;
set { _mensagemGeral = value; OnPropertyChanged(nameof(MensagemGeral)); }
}
// ====== COMANDOS ======
public ICommand AbrirConfigRedeCommand { get; }
public ICommand AbrirDetalhesGnssCommand { get; }
private void AbrirConfigRede()
{
// depois você pode abrir uma janelinha de config
//MessageBox.Show("Aqui vai abrir a tela de configuração de rede.");
SolicitarConfigRede?.Invoke();
}
private void AbrirDetalhesGnss()
{
MessageBox.Show("Aqui vai abrir uma tela com detalhes do GNSS/UM982.");
}
// ====== STATUS GERAL PARA AVANÇAR ======
public bool TudoOk => RedeOk && GnssOk;
// Evento para o DockWindow saber quando ficou tudo ok
public event Action<bool> TudoOkChanged;
private void OnTudoOkChanged()
{
TudoOkChanged?.Invoke(TudoOk);
}
// ====== STATUS INICIAL (fake por enquanto) ======
public void CarregarStatusInicial()
{
// aqui você pluga de verdade nos seus serviços:
// var statusRede = NetworkService.Get();
// var statusGnss = GnssService.Get();
AtualizarStatusRede();
AtualizarStatusGnss();
}
private void AtualizarStatusGnss()
{
try
{
// Exemplo de checks (troca pelo teu serviço):
// bool conectado = GnssService.Um982Conectado();
// string porta = GnssService.PortaAtual();
// string fix = GnssService.FixMode(); // "No Fix", "3D", "RTK Float", "RTK Fixed"
// double? hdop = GnssService.Hdop();
bool conectado = Variaveis.GpsService?.IsConnected ?? false; // <-- seu método real aqui
//conectado = true;
if (!conectado)
{
GnssOk = false;
DetalhesGnss = "UM982 não detectado. Verifique cabo USB e alimentação.";
MensagemGeral = "Conecte o GNSS e ajuste a rede para avançar.";
return;
}
// Se conectou:
GnssOk = true;
// Se você tiver mais infos, mostra aqui:
// DetalhesGnss = $"Conectado ({porta}) | Fix: {fix} | HDOP: {hdop:0.0}";
DetalhesGnss = "Conectado. Recebendo dados GNSS.";
// Mensagem geral pode ficar mais positiva se Rede também estiver ok
MensagemGeral = TudoOk
? "Tudo OK. Você pode avançar para a fixação da base."
: "GNSS OK. Agora ajuste a rede para avançar.";
}
catch (Exception ex)
{
GnssOk = false;
DetalhesGnss = "Erro ao verificar GNSS: " + ex.Message;
MensagemGeral = "Erro ao ler GNSS. Verifique conexões.";
}
}
public void AtualizarStatusRede()
{
try
{
// 1) Escolhe a interface “ativa” ou a que você usa pra ponte IP
// Se você já tem isso fixo, melhor ainda: use sempre a mesma.
var interfaces = EthernetService.ObterNomesInterfaces().Where(x => x.Contains("Ativa")).Select(x => x.Split('(')[0].Trim()).ToList();
var iface = interfaces[0]; // <-- se tiver
// ou se você já sabe o nome: var iface = "Ethernet 2";
var ip = EthernetService.ObterIpAtual(iface);
var sub = EthernetService.ObterSubnetMaskAtual(iface);
var gw = EthernetService.ObterIpGateway(iface);
DetalhesRede = $"{iface}\nIP: {ip}\nMáscara: {sub}\nGateway: {gw}";
// 2) Define RedeOk do jeito que faz sentido pra você:
// exemplo simples: tem IP válido + gateway válido
RedeOk = !string.IsNullOrWhiteSpace(ip) && !string.IsNullOrWhiteSpace(gw);
}
catch (Exception ex)
{
RedeOk = false;
DetalhesRede = "Não foi possível ler a configuração.\n" + ex.Message;
}
}
// ====== INotifyPropertyChanged ======
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string nome)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nome));
}
public void Dispose()
{
_timerGnss?.Stop();
}
}
}

View File

@ -0,0 +1,118 @@
using System.ComponentModel;
using System.Windows.Input;
using System.Windows;
using OperationControl.Views;
using OperationControl.Helpers;
using OperationControl.Models;
namespace OperationControl.ViewModels
{
public class DockWindowViewModel : INotifyPropertyChanged
{
private readonly ConfigConexaoView _viewConfig;
public DockWindowViewModel()
{
// 1) Cria a view do passo 1
_viewConfig = new ConfigConexaoView();
// 2) Escuta quando RedeOk && GnssOk mudar
_viewConfig._vm.TudoOkChanged += OnTudoOkChanged;
// 3) Conteúdo inicial
CenterContent = _viewConfig;
TopContent = null;
BottomContent = null;
// 4) Commands já usando CanGoBack / CanGoNext
BackCommand = new RelayCommand(_ => GoBack(), _ => CanGoBack);
NextCommand = new RelayCommand(_ => GoNext(), _ => CanGoNext);
// 5) Estado inicial do Next (caso já venha tudo ok no boot)
ConfigConexaoOk = _viewConfig._vm.TudoOk;
}
private void OnTudoOkChanged(bool ok)
{
ConfigConexaoOk = ok;
// avisa bindings
OnPropertyChanged(nameof(CanGoNext));
// força o WPF a reavaliar CanExecute dos botões
CommandManager.InvalidateRequerySuggested();
}
// ====== ESTADO ======
private bool _configConexaoOk;
public bool ConfigConexaoOk
{
get => _configConexaoOk;
set
{
if (_configConexaoOk != value)
{
_configConexaoOk = value;
OnPropertyChanged(nameof(ConfigConexaoOk));
OnPropertyChanged(nameof(CanGoNext));
}
}
}
public bool CanGoBack => false; // passo 1 não volta
public bool CanGoNext => ConfigConexaoOk; // libera quando tudo ok
// ====== CONTEÚDOS ======
private object _centerContent;
public object CenterContent
{
get => _centerContent;
set { _centerContent = value; OnPropertyChanged(nameof(CenterContent)); }
}
private object _topContent;
public object TopContent
{
get => _topContent;
set { _topContent = value; OnPropertyChanged(nameof(TopContent)); }
}
private object _bottomContent;
public object BottomContent
{
get => _bottomContent;
set { _bottomContent = value; OnPropertyChanged(nameof(BottomContent)); }
}
// ====== COMMANDS ======
public ICommand BackCommand { get; }
public ICommand NextCommand { get; }
private void GoBack()
{
// depois você implementa quando tiver passo 2/3
}
private void GoNext()
{
if (!CanGoNext) return;
// Aqui depois você troca para a próxima tela:
// CenterContent = new FixacaoBaseView();
// e atualiza CanGoBack/CanGoNext conforme o step
//System.Windows.MessageBox.Show("Avançou! Próximo passo: Fixação da Base (ainda vamos implementar).");
((App)System.Windows.Application.Current).Shell.Dock?.Hide();
((App)System.Windows.Application.Current).Shell.Main?.Show();
}
// ====== INotifyPropertyChanged ======
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string nome)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nome));
}
}
}

View File

@ -0,0 +1,203 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net;
using System.Windows;
using System.Windows.Input;
using OperationControl.Helpers;
namespace OperationControl.ViewModels
{
public class NetworkConfigViewModel : INotifyPropertyChanged
{
public NetworkConfigViewModel()
{
Interfaces = new ObservableCollection<string>();
AtualizarCommand = new RelayCommand(_ => Atualizar(), _ => PodeAtualizar);
SalvarCommand = new RelayCommand(async _ => await SalvarAsync(), _ => PodeSalvar);
FecharCommand = new RelayCommand(_ => Fechar());
CarregarInterfaces();
}
// Lista de interfaces
public ObservableCollection<string> Interfaces { get; }
private string _interfaceSelecionada;
public string InterfaceSelecionada
{
get => _interfaceSelecionada;
set
{
if (_interfaceSelecionada != value)
{
_interfaceSelecionada = value;
OnPropertyChanged(nameof(InterfaceSelecionada));
OnPropertyChanged(nameof(PodeAtualizar));
OnPropertyChanged(nameof(PodeSalvar));
MensagemStatus = "Clique em Atualizar para ler os dados da interface selecionada.";
}
}
}
private string _ip;
public string Ip
{
get => _ip;
set { _ip = value; OnPropertyChanged(nameof(Ip)); OnPropertyChanged(nameof(PodeSalvar)); }
}
private string _subnet;
public string Subnet
{
get => _subnet;
set { _subnet = value; OnPropertyChanged(nameof(Subnet)); OnPropertyChanged(nameof(PodeSalvar)); }
}
private string _gateway;
public string Gateway
{
get => _gateway;
set { _gateway = value; OnPropertyChanged(nameof(Gateway)); OnPropertyChanged(nameof(PodeSalvar)); }
}
private string _mensagemStatus;
public string MensagemStatus
{
get => _mensagemStatus;
set { _mensagemStatus = value; OnPropertyChanged(nameof(MensagemStatus)); }
}
// Comandos
public ICommand AtualizarCommand { get; }
public ICommand SalvarCommand { get; }
public ICommand FecharCommand { get; }
private bool _isBusy;
public bool IsBusy
{
get => _isBusy;
set
{
_isBusy = value;
OnPropertyChanged(nameof(IsBusy));
OnPropertyChanged(nameof(PodeSalvar));
OnPropertyChanged(nameof(PodeAtualizar));
}
}
public bool PodeAtualizar => !IsBusy && !string.IsNullOrEmpty(InterfaceSelecionada);
public bool PodeSalvar => !IsBusy &&
!string.IsNullOrEmpty(InterfaceSelecionada) &&
!string.IsNullOrWhiteSpace(Ip) &&
!string.IsNullOrWhiteSpace(Subnet) &&
!string.IsNullOrWhiteSpace(Gateway);
private bool IpValido(string s) => IPAddress.TryParse(s, out _);
// Evento para a janela fechar de fora
public event Action<bool> RequisitarFechamento;
private void CarregarInterfaces()
{
Interfaces.Clear();
// TODO: trocar pelo seu método real pra listar as interfaces
// Exemplo:
// foreach (var iface in NetworkHelper.ListarInterfaces())
// Interfaces.Add(iface.NomeExibicao);
foreach (var i in EthernetService.ObterNomesInterfaces())
{
if (i.Contains("Ativa"))
Interfaces.Add(i.Split('(')[0].Trim());
}
if (Interfaces.Count > 0)
InterfaceSelecionada = Interfaces[0];
MensagemStatus = "Selecione a interface e clique em Atualizar para carregar os dados atuais.";
}
private void Atualizar()
{
if (string.IsNullOrEmpty(InterfaceSelecionada))
{
MensagemStatus = "Selecione uma interface primeiro.";
return;
}
try
{
// TODO: aqui você chama SEUS métodos reais
// var config = NetworkHelper.GetConfig(InterfaceSelecionada);
// Ip = config.Ip;
// Subnet = config.Subnet;
// Gateway = config.Gateway;
// MOCK por enquanto:
Ip = EthernetService.ObterIpAtual(InterfaceSelecionada);
Subnet = EthernetService.ObterSubnetMaskAtual(InterfaceSelecionada);
Gateway = EthernetService.ObterIpGateway(InterfaceSelecionada);
MensagemStatus = "Configuração atual carregada da interface selecionada.";
}
catch (Exception ex)
{
MensagemStatus = "Erro ao ler configuração da interface: " + ex.Message;
}
}
private async Task SalvarAsync()
{
if (!PodeSalvar) { MensagemStatus = "Preencha IP, Máscara e Gateway antes de salvar."; return; }
if (!IpValido(Ip) || !IpValido(Subnet) || !IpValido(Gateway))
{
MensagemStatus = "IP, máscara ou gateway inválidos. Ex: 192.168.0.50 / 255.255.255.0 / 192.168.0.1";
return;
}
try
{
IsBusy = true;
MensagemStatus = "Salvando configuração...";
bool sucesso = await EthernetService.DefinirIpFixo(InterfaceSelecionada, Ip, Subnet, Gateway, false);
if (!sucesso)
{
MensagemStatus = "Falha ao aplicar configuração de rede.";
return;
}
MensagemStatus = "Configuração aplicada com sucesso.";
System.Windows.MessageBox.Show($"Configuração salva para {InterfaceSelecionada}...", "Rede", MessageBoxButton.OK, MessageBoxImage.Information);
RequisitarFechamento?.Invoke(true);
}
catch (Exception ex)
{
MensagemStatus = "Erro ao salvar configuração de rede: " + ex.Message;
}
finally
{
IsBusy = false;
}
}
private void Fechar()
{
// fecha sem "sucesso"
RequisitarFechamento?.Invoke(false);
}
// INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string nome)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nome));
}
}
}

View File

@ -0,0 +1,107 @@
<UserControl x:Class="OperationControl.Views.ConfigConexaoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Blocos principais -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Bloco Rede -->
<Border Grid.Column="0"
Margin="16"
Padding="16"
CornerRadius="8"
BorderThickness="2"
BorderBrush="{Binding CorBordaRede}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="REDE"
FontSize="24"
FontWeight="Bold"
Margin="0,0,0,8"
HorizontalAlignment="Center"/>
<!-- Ícone grandão - pode trocar por Path/Image depois -->
<TextBlock Text="🌐"
FontSize="64"
HorizontalAlignment="Center"
Margin="0,0,0,8"/>
<TextBlock Text="{Binding StatusRedeTexto}"
FontSize="16"
FontWeight="SemiBold"
HorizontalAlignment="Center"
Margin="0,0,0,4"
Foreground="{Binding CorStatusRede}"/>
<TextBlock Text="{Binding DetalhesRede}"
TextWrapping="Wrap"
TextAlignment="Center"
Margin="0,0,0,8"/>
<Button Content="Configurar rede..."
Width="180"
Margin="0,8,0,0"
Command="{Binding AbrirConfigRedeCommand}"/>
</StackPanel>
</Border>
<!-- Bloco GNSS -->
<Border Grid.Column="1"
Margin="16"
Padding="16"
CornerRadius="8"
BorderThickness="2"
BorderBrush="{Binding CorBordaGnss}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="GNSS / UM982"
FontSize="24"
FontWeight="Bold"
Margin="0,0,0,8"
HorizontalAlignment="Center"/>
<!-- Ícone -->
<TextBlock Text="📡"
FontSize="64"
HorizontalAlignment="Center"
Margin="0,0,0,8"/>
<TextBlock Text="{Binding StatusGnssTexto}"
FontSize="16"
FontWeight="SemiBold"
HorizontalAlignment="Center"
Margin="0,0,0,4"
Foreground="{Binding CorStatusGnss}"/>
<TextBlock Text="{Binding DetalhesGnss}"
TextWrapping="Wrap"
TextAlignment="Center"
Margin="0,0,0,8"/>
<Button Content="Ver detalhes GNSS..."
Width="180"
Margin="0,8,0,0"
Command="{Binding AbrirDetalhesGnssCommand}"/>
</StackPanel>
</Border>
</Grid>
<!-- Linha embaixo para uma mensagem geral -->
<TextBlock Grid.Row="1"
Text="{Binding MensagemGeral}"
Margin="16"
FontSize="14"
TextWrapping="Wrap"
TextAlignment="Center"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,38 @@
using OperationControl.ViewModels;
using OperationControl.Windows;
using System.Windows.Controls;
using System.Windows;
namespace OperationControl.Views
{
public partial class ConfigConexaoView : System.Windows.Controls.UserControl
{
public ConfigConexaoViewModel _vm { get; }
public ConfigConexaoView()
{
InitializeComponent();
_vm = new ConfigConexaoViewModel();
_vm.SolicitarConfigRede += OnSolicitarConfigRede;
DataContext = _vm;
}
private void OnSolicitarConfigRede()
{
var wnd = new NetworkConfigWindow
{
Owner = Window.GetWindow(this)
};
var result = wnd.ShowDialog();
if (result == true)
{
// se o usuário salvou com sucesso, recarrega o status de rede
_vm.AtualizarStatusRede(); // deixe esse método public se ainda não estiver
}
}
}
}

View File

@ -0,0 +1,72 @@
<Window x:Class="OperationControl.Windows.DockWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OperationControl.Windows"
mc:Ignorable="d"
Title="DockWindow" Height="1025" Width="1920" WindowStartupLocation="CenterScreen" WindowState="Maximized">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
<!-- Topo -->
<RowDefinition Height="*"/>
<!-- Centro -->
<RowDefinition Height="120"/>
<!-- Rodapé -->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<!-- Lateral esquerda (voltar) -->
<ColumnDefinition Width="*"/>
<!-- Centro -->
<ColumnDefinition Width="60"/>
<!-- Lateral direita (avançar) -->
</Grid.ColumnDefinitions>
<!-- Topo (span em 3 colunas) -->
<Border Grid.Row="0" Grid.ColumnSpan="3"
Background="#222"
Padding="8">
<ContentControl Content="{Binding TopContent}"/>
</Border>
<!-- Área central principal -->
<Border Grid.Row="1" Grid.Column="1"
Margin="8"
BorderThickness="1"
BorderBrush="Gray">
<ContentControl Content="{Binding CenterContent}"/>
</Border>
<!-- Rodapé (span 3 colunas) -->
<Border Grid.Row="2" Grid.ColumnSpan="3"
Background="#181818"
Padding="8">
<ContentControl Content="{Binding BottomContent}"/>
</Border>
<!-- Lateral esquerda: botão voltar -->
<Grid Grid.Row="1" Grid.Column="0">
<Button Content="⮜"
FontSize="24"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="40" Height="40"
Command="{Binding BackCommand}"
IsEnabled="{Binding CanGoBack}"/>
</Grid>
<!-- Lateral direita: botão avançar -->
<Grid Grid.Row="1" Grid.Column="2">
<Button Content="⮞"
FontSize="24"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="40" Height="40"
Command="{Binding NextCommand}"
IsEnabled="{Binding CanGoNext}"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,29 @@
using OperationControl.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace OperationControl.Windows
{
/// <summary>
/// Lógica interna para DockWindow.xaml
/// </summary>
public partial class DockWindow : Window
{
public DockWindow()
{
InitializeComponent();
DataContext = new DockWindowViewModel();
}
}
}

View File

@ -363,7 +363,7 @@ namespace OperationControl.Windows
try
{
pgbResumo_RuaAtual.Value = dados.Trajetoria.PercentualRuaAtual;
lblResumo_RuaAtual.Content = $"{dados.Trajetoria.CorredorAtual.DistanciaPercorridaCorredor:0.00} m / {dados.Trajetoria.CorredorAtual.DistanciaTotal:0.00} m ({dados.Trajetoria.CorredorAtual.Idx + 1})";
lblResumo_RuaAtual.Content = $"{dados.Trajetoria.CorredorAtualDistanciaPercorrida:0.00} m / {dados.Trajetoria.CorredorAtualDistanciaTotal:0.00} m ({dados.Trajetoria.CorredorAtualIdx + 1})";
pgbResumo_AreaTotal.Value = dados.Trajetoria.PercentualOperacao;
lblResumo_AreaTotal.Content = $"{dados.Trajetoria.DistanciaPercorrida:0.00} m / {dados.Trajetoria.DistanciaTotal:0.00} m";
pgbResumo_Bateria.Value = dados.Bateria.PercentualBateria;
@ -417,7 +417,7 @@ namespace OperationControl.Windows
private void AtualizarDadosTela_Diagnosticos(AgroBase.Models.Operacoes.OperacaoParametrosModel dados)
{
lblDiagnosticos_Impedimento.Text = "Impedimento: " + (string.IsNullOrEmpty(dados.DadosLeitura.Operacao.ImpedimentoErro) ? "Nenhum" : dados.DadosLeitura.Operacao.ImpedimentoErro.Replace("\n\n", "; "));
lblDiagnosticos_Impedimento.Text = "Impedimento: " + (string.IsNullOrEmpty(dados.DadosLeitura.Operacao?.ImpedimentoErro) ? "Nenhum" : dados.DadosLeitura.Operacao.ImpedimentoErro.Replace("\n\n", "; "));
// Canvas que está dentro do Border
var canvas = brdDiagnostico.Child as Canvas;
@ -438,7 +438,7 @@ namespace OperationControl.Windows
var individual = _saude?.saude_individual?.FirstOrDefault(x => x.label == mod_label);
bool em_uso = mod_label != "" ? dados.DadosLeitura.Operacao.ModulosMandatorios?.FirstOrDefault(x => x.Dispositivo == modulo)?.ComponentesEmUso?.Any(x => x.Key == mod_label && x.Value.Item2) ?? false : dados.ModulosMandatorios?.Any(x => x.Dispositivo == modulo && x.Utilizar) ?? false;
bool em_uso = mod_label != "" ? dados.DadosLeitura.Operacao?.ModulosMandatorios?.FirstOrDefault(x => x.Dispositivo == modulo)?.ComponentesEmUso?.Any(x => x.Key == mod_label && x.Value.Item2) ?? false : dados.ModulosMandatorios?.Any(x => x.Dispositivo == modulo && x.Utilizar) ?? false;
// Aplica cor de acordo com o status
AplicarStatusModuloNaLabel(lbl, individual?.status ?? _saude?.status ?? AgroBase.Models.Enums.StatusModulo.Desconectado, em_uso);
@ -1270,7 +1270,7 @@ namespace OperationControl.Windows
{
panelOpcoes_Trajetoria.Visibility = Visibility.Visible;
var dados = rover?.Trajetoria?.AutonomiaCooredor;
var dados = rover?.Trajetoria?.AutonomiaCorredor;
txtTrajetoria_DistCorredor.Text = $"{dados?.DistanciaCorredor_m ?? 0:0.00} m";
txtTrajetoria_DistBateria.Text = $"{dados?.DistanciaSeguraBateria_m ?? 0:0.00} m";
txtTrajetoria_DistPulverizador.Text = $"{dados?.DistanciaSeguraHerbicida_m ?? 0:0.00} m";
@ -1506,10 +1506,10 @@ namespace OperationControl.Windows
return;
var _Trajetoria = VariaveisControleOperacao.RoverEmFoco?.DadosLeitura?.Trajetoria;
int idx_corredor = (_Trajetoria?.PontoAtual?.idxCorredor ?? 0);
int idx_corredor = (_Trajetoria?.PontoAtualIdx ?? 0);
bool bat_liberada = chbTrajetoria_BatLiberada.IsChecked ?? false;
bool herb_liberado = chbTrajetoria_HerbLiberado.IsChecked ?? false;
string motivo = _Trajetoria?.AutonomiaCooredor?.Motivo ?? "";
string motivo = _Trajetoria?.AutonomiaCorredor?.Motivo ?? "";
if ((bat_liberada || herb_liberado) && MessageBox.Show($"Tem certeza que deseja liberar a entrada do equipamento na próxima rua?\r\n{motivo}", "Confirmação", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
return;
@ -1693,7 +1693,7 @@ namespace OperationControl.Windows
bool gnss_fixado = Variaveis.GpsService?.BaseFix?.PosicaoBaseFixada ?? false;
bool gnss_fixando = btnGNSS_FixarBase.Content.ToString() == "Parar";
btnGNSS_FixarBase.IsEnabled = (gnss_fix_preciso && !gnss_fixado) || gnss_fixando || gnss_fixado;
btnGNSS_FixarBase.IsEnabled = (gnss_fix_preciso && !gnss_fixado) || gnss_fixando || gnss_fixado || (!gnss_fixado && !gnss_fixando);
btnGNSS_FixarBase.Content = gnss_fixado || !gnss_fixando ? "Fixar" : "Parar";
}
else
@ -1721,13 +1721,14 @@ namespace OperationControl.Windows
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo());
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo(true));
}
}
else
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo(true));
}
}
else
@ -1741,7 +1742,7 @@ namespace OperationControl.Windows
#region CONTROLE
public void AtualizarDadosTela_Controle(AgroBase.Models.OperacaoControleModel controle, double angulo, double velocidade, bool emergencia, bool pausa, bool refing)
public void AtualizarDadosTela_Controle(AgroBase.Models.Operacoes.OperacaoParametrosDadosControleModel controle, double angulo, double velocidade, bool emergencia, bool pausa, bool refing)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
@ -1813,11 +1814,19 @@ namespace OperationControl.Windows
Controle = new AgroBase.Models.Operacoes.OperacaoParametrosControleModel()
{
MovimentoAutomatico = modo != AgroBase.Models.Enums.ModoOperacao.Manual,
DirecionalAutomatico = modo != AgroBase.Models.Enums.ModoOperacao.Manual,
SonarAtivado = chbParametros_Sonar.IsChecked ?? false,
FrenagemAutomaticaAoParar = chbParametros_Frenagem.IsChecked ?? false,
MovVelocidadeCErvasPercent = int.Parse(txtParametros_VelCErvas.Text),
MovVelocidadeSErvasPercent = int.Parse(txtParametros_VelSErvas.Text),
ImuParadaPorInclinacao = false,
MpcHorizonte = 4,
MpcMatrizCusto = false,
OakParadaPorObstaculo = true,
RegistrarDadosPosProcessamento = false,
DirAnguloMaximo = int.Parse(txtParametros_AngMax.Text),
DirTipoMovimento = AgroBase.Models.Enums.TiposControladorDirecional.MPC,
DirVelocidadeMovimento = 50,
@ -1868,15 +1877,15 @@ namespace OperationControl.Windows
Variaveis.MostrarLog($"Rua clicada: {e.StreetId}. Ruas selecionadas: {string.Join(",", e.SelectedStreetsIds)}");
}
private void AtualizarDadosTela_Mapa(AgroBase.Models.OperacaoSensoriamentoLogTrajetoriaModel Trajetoria)
private void AtualizarDadosTela_Mapa(AgroBase.Models.Operacoes.OperacaoParametrosDadosTrajetoriaModel Trajetoria)
{
lblMapaInfo_Debug.Content = $"" +
$"Status: {Trajetoria.AutonomiaCooredor?.Status ?? AgroBase.Models.AutonomiaCorredorStatus.Desconhecido} | " +
$"Próximo Ponto: {Trajetoria.ProximoPonto.idxPonto} | " +
(Trajetoria.ProximoPonto.Aproximando ? "Aproximando" : "Afastando") + " | " +
$"Distância próximo ponto: {Trajetoria.ProximoPonto.DistanciaAtual:2F} m | " +
$"Distância ponto anterior: {Trajetoria.PontoAtual.DistanciaAtual:2F} m | " +
$"Corredor: " + (Trajetoria.CorredorAtual.Dentro ? "Dentro" : "Fora") + " | " +
$"Status: {Trajetoria.AutonomiaCorredor?.Status ?? AgroBase.Models.AutonomiaCorredorStatus.Desconhecido} | " +
$"Próximo Ponto: {Trajetoria.ProximoPontoIdx} | " +
(Trajetoria.ProximoPontoAproximando ? "Aproximando" : "Afastando") + " | " +
$"Distância próximo ponto: {Trajetoria.ProximoPontoDistanciaAtual:2F} m | " +
$"Distância ponto anterior: {Trajetoria.PontoAtualDistanciaAtual:2F} m | " +
$"Corredor: " + (Trajetoria.CorredorAtualDentro ? "Dentro" : "Fora") + " | " +
$"Margem: " + (Trajetoria.NaMargemDoCorredor ? "Sim" : "Não") + " | " +
$"Carro: {Trajetoria.StatusCarro}";

View File

@ -0,0 +1,86 @@
<Window x:Class="OperationControl.Windows.NetworkConfigWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Configuração de Rede"
Height="300" Width="520"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize">
<Grid Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Interface de rede -->
<TextBlock Grid.Row="0" Grid.Column="0"
Text="Interface:"
VerticalAlignment="Center"
Margin="0,0,8,8"/>
<ComboBox Grid.Row="0" Grid.Column="1"
ItemsSource="{Binding Interfaces}"
SelectedItem="{Binding InterfaceSelecionada}"
Margin="0,0,0,8"
MinWidth="250" />
<!-- IP -->
<TextBlock Grid.Row="1" Grid.Column="0"
Text="Endereço IP:"
VerticalAlignment="Center"
Margin="0,0,8,8"/>
<TextBox Grid.Row="1" Grid.Column="1"
Text="{Binding Ip}"
Margin="0,0,0,8" />
<!-- Máscara -->
<TextBlock Grid.Row="2" Grid.Column="0"
Text="Máscara:"
VerticalAlignment="Center"
Margin="0,0,8,8"/>
<TextBox Grid.Row="2" Grid.Column="1"
Text="{Binding Subnet}"
Margin="0,0,0,8" />
<!-- Gateway -->
<TextBlock Grid.Row="3" Grid.Column="0"
Text="Gateway:"
VerticalAlignment="Center"
Margin="0,0,8,8"/>
<TextBox Grid.Row="3" Grid.Column="1"
Text="{Binding Gateway}"
Margin="0,0,0,8" />
<!-- Mensagem / status -->
<TextBlock Grid.Row="4" Grid.ColumnSpan="2"
Text="{Binding MensagemStatus}"
TextWrapping="Wrap"
Foreground="Gray"
Margin="0,4,0,8" />
<!-- Botões -->
<StackPanel Grid.Row="5" Grid.ColumnSpan="2"
Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="0,12,0,0">
<Button Content="Atualizar"
Width="90"
Margin="0,0,8,0"
Command="{Binding AtualizarCommand}"/>
<Button Content="Salvar"
Width="90"
Margin="0,0,8,0"
Command="{Binding SalvarCommand}"/>
<Button Content="Fechar"
Width="90"
Command="{Binding FecharCommand}"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,25 @@
using System.Windows;
using OperationControl.ViewModels;
namespace OperationControl.Windows
{
public partial class NetworkConfigWindow : Window
{
public NetworkConfigWindow()
{
InitializeComponent();
var vm = new NetworkConfigViewModel();
vm.RequisitarFechamento += OnRequisitarFechamento;
DataContext = vm;
}
private void OnRequisitarFechamento(bool salvarComSucesso)
{
// se quiser diferenciar depois, pode usar esse bool
DialogResult = salvarComSucesso;
Close();
}
}
}