alguns guards e limpeza na operacao atual como instancia

This commit is contained in:
Diego Freitas 2026-07-02 09:36:51 -03:00
parent 719a71917d
commit c98972129c
32 changed files with 527 additions and 519 deletions

View File

@ -76,8 +76,6 @@ namespace AgroBase.Forms.Direcional
chbUsar.Checked = Modulo.DirMotor.UsarAnguloSensor;
}
}
txtIP.Text = Disp.Dados.IP_Dir;
}
private void frmDirConfig_FormClosing(object sender, FormClosingEventArgs e)
@ -126,14 +124,12 @@ namespace AgroBase.Forms.Direcional
}
}
Disp.Dados.IP_Dir = txtIP.Text;
Disp.SalvarParametros(Disp.Dados);
}
private void cmbTipoMovimento_SelectedIndexChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = (TipoMovimentoDirecional)cmbTipoMovimento.SelectedIndex;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle((TipoMovimentoDirecional)cmbTipoMovimento.SelectedIndex);
AtualizarConfiguracaoSentido();
}
}

View File

@ -707,7 +707,7 @@ namespace AgroBase.Forms.IHM
TipoMovimentoDirecional _oldTipoMovimento = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento;
double _oldPercentualVelocidade = Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP;
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = TipoMovimentoDirecional.Diagnostico;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle(TipoMovimentoDirecional.Diagnostico);
Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = 20;
DispositivosService<MovimentacaoUnificadaModel> Dispositivo = (DispositivosService<MovimentacaoUnificadaModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Enums.T_Code.Mvd);
@ -788,7 +788,7 @@ namespace AgroBase.Forms.IHM
}
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = _oldTipoMovimento;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle(_oldTipoMovimento);
Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = _oldPercentualVelocidade;
return true;
@ -952,7 +952,7 @@ namespace AgroBase.Forms.IHM
return false;
}
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = TipoMovimentoDirecional.Diagnostico;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle(TipoMovimentoDirecional.Diagnostico);
Variaveis.OperacaoEmAndamento.Controle.Angulo = 25;
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento = 30;
@ -1001,7 +1001,7 @@ namespace AgroBase.Forms.IHM
}
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = _oldTipoMovimento;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle(_oldTipoMovimento);
Variaveis.OperacaoEmAndamento.Controle.Angulo = _oldAngulo;
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento = _oldVelocidadeMP;

View File

@ -624,7 +624,7 @@ namespace AgroBase.Forms.IHM
private void CmbModoControle_SelectedIndexChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = (Enums.TipoMovimentoDirecional)cmbModoControle.SelectedIndex;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle((Enums.TipoMovimentoDirecional)cmbModoControle.SelectedIndex);
}
private void tkbVelocidade_Scroll(object sender, EventArgs e)

View File

@ -211,7 +211,7 @@ namespace AgroBase.Forms.Operacoes
frmDialogo = new frmDialogoMapa();
frmDialogo.Show();
frmDialogo.Hide();
(bool sucesso, List<string> ruas) = Variaveis.OperacaoEmAndamento.CarregarParametrizacaoOperacao(frmDialogo.pnlMapa, frmDialogo.lblMapaCarregado, path);
bool sucesso = Variaveis.OperacaoEmAndamento.CarregarParametrizacaoOperacao(frmDialogo.pnlMapa, frmDialogo.lblMapaCarregado, path);
bool condicaoOperacaoCarregada() => Variaveis.OperacaoEmAndamento.Trajetoria?.CorredorAtual != null;
bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoOperacaoCarregada, 15000, 200);
@ -221,7 +221,7 @@ namespace AgroBase.Forms.Operacoes
throw new Exception("Erro ao carregar a trajetória do mapa!");
}
ruasSelecionadas = ruas;
ruasSelecionadas = new List<string>();
foreach (var chb in fpnlInformacoes.Controls.OfType<CheckBox>())
{

View File

@ -89,7 +89,6 @@ namespace AgroBase.Forms.Movimentacao
nudRPMMax.Value = (int)Disp.Dados.RPM_Max_MotorBLDC;
nudReducao.Value = (int)Disp.Dados.ReducaoMotorBLDC;
nudDiametroRoda.Value = (int)(Disp.Dados.DiametroRoda * 1000);
txtIP.Text = Disp.Dados.IP_Mov;
}
private void frmMovConfig_FormClosing(object sender, FormClosingEventArgs e)
@ -153,14 +152,13 @@ namespace AgroBase.Forms.Movimentacao
Disp.Dados.RPM_Max_MotorBLDC = Convert.ToInt32(nudRPMMax.Value);
Disp.Dados.ReducaoMotorBLDC = Convert.ToInt32(nudReducao.Value);
Disp.Dados.DiametroRoda = Convert.ToDouble(nudDiametroRoda.Value / 1000);
Disp.Dados.IP_Mov = txtIP.Text;
Disp.SalvarParametros(Disp.Dados);
}
private void cmbTipoMovimento_SelectedIndexChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = (TipoMovimentoDirecional)cmbTipoMovimento.SelectedIndex;
Variaveis.OperacaoEmAndamento.DefinirTipoMovimentoControle((TipoMovimentoDirecional)cmbTipoMovimento.SelectedIndex);
AtualizarConfiguracaoSentido();
}

View File

@ -8,6 +8,7 @@ using AgroBase.Services;
using AgroBase.Models.Modules;
using System.Threading.Tasks;
using AgroBase.Services.Operadores;
using System.Collections.Generic;
namespace AgroBase.Forms.Operacoes
{
@ -761,16 +762,18 @@ namespace AgroBase.Forms.Operacoes
private void cmbTipoMovimento_SelectedIndexChanged(object sender, EventArgs e)
{
op.Controle.TipoMovimento = (TipoMovimentoDirecional)cmbTipoMovimento.SelectedIndex;
op.DefinirTipoMovimentoControle((TipoMovimentoDirecional)cmbTipoMovimento.SelectedIndex);
}
private void chbPulverizador_CheckedChanged(object sender, EventArgs e)
{
op.Parametros.Controle.PulverizadorAutomatico = ((CheckBox)sender).Checked;
if (!op.Parametros.Controle.PulverizadorAutomatico && op.Controle.Bicos.Any(x => x.ComandoAtuar))
var bicos = op.DispAtu?.Dados?.BicosPulverizadores ?? new List<AtuadorBicoModel>();
if (!op.Parametros.Controle.PulverizadorAutomatico && bicos.Any(x => x.ComandoAtuar))
{
op.Controle.Bicos.ForEach(b => b.ComandoAtuar = false);
bicos.ForEach(b => b.ComandoAtuar = false);
}
}

View File

@ -167,7 +167,7 @@ namespace AgroBase.Forms.Operacoes
GPSModel pos = GPSService.UltimaLeitura.Clone();
GPSService.UltimaLeitura = LogsGPS.FirstOrDefault();
(bool sucesso, List<string> ruas) = op.CarregarParametrizacaoOperacao(null, null, ofd.FileName.Replace("data.lgop", "operacao.opr"));
bool sucesso = op.CarregarParametrizacaoOperacao(null, null, ofd.FileName.Replace("data.lgop", "operacao.opr"));
bool condicaoOperacaoCarregada() => op.Trajetoria?.CorredorAtual != null;
bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoOperacaoCarregada, 15000, 200);
GPSService.UltimaLeitura = pos;
@ -1211,7 +1211,7 @@ namespace AgroBase.Forms.Operacoes
txtVelocidade.Text = (LogMov.VelocidadeMediaMs * 3.6).ToString("0.00") + " km/h (" + LogMov.VelocidadeMediaMs.ToString("0.00") + " m/s)";
txtDirecaoControle.Text = (LogCtrl?.TiposControle?.FirstOrDefault(x => x.Tipo == Enums.T_Code.Dir)?.DirecaoAtual ?? Enums.Direcao.Parado).ToString() + " (" + (LogCtrl?.Latencia ?? 0).ToString("0.00") + " s)";
txtVelocidadeControle.Text = ((LogCtrl?.PercentualVelocidadeSP ?? 0) / VariaveisEquipamento.RPM_Max_Roda * 100).ToString() + " rpm";
txtErvasIdentificadas.Text = $"{LogCtrl?.Bicos?.Sum(x => x.Atuacoes) ?? 0}";
txtErvasIdentificadas.Text = $"{LogAtu?.Bicos?.Sum(x => x.Atuacoes) ?? 0}";
txtDistanciasLaterais.Text = (LogTrj.DistanciaEsquerda * 100.0).ToString("0.00") + " cm / " + (LogTrj.DistanciaDireita * 100.0).ToString("0.00") + " cm";
txtErroLateral.Text = (LogCtrl.ErroLateral * 100.0).ToString("0.00") + " cm";

View File

@ -1,7 +1,6 @@
using AgroBase.Forms.IHM;
using AgroBase.Models;
using AgroBase.Services;
using AgroBase.Services.Operadores;
using System;
using System.Threading;
using System.Threading.Tasks;
@ -11,8 +10,6 @@ namespace AgroBase.Forms
{
public partial class frmInstancial : Form
{
public static readonly bool IniciarWorkers = true;
public static AsyncTaskTimerModel tmrVarreduraDispositivos;
public static frmPrincipal frmPrincipal = new frmPrincipal();
@ -105,6 +102,8 @@ namespace AgroBase.Forms
if (_startupConcluido)
return;
Variaveis.OperacaoEmAndamento = OperacaoModel.CarregarParametrosOperacaoPadrao(Enums.ModoOperacao.NaoDefinido, true);
_shutdownIniciado = false;
Variaveis.Fechando = false;
@ -142,7 +141,7 @@ namespace AgroBase.Forms
LivoxManagerProcess.Start();
await VariaveisOperacao.Operadores.IniciarProcessamento(IniciarWorkers).ConfigureAwait(false);
await VariaveisOperacao.Operadores.IniciarProcessamento(Variaveis.IniciarWorkers).ConfigureAwait(false);
AudioAlertaService.SelecionarVoz(VariaveisEquipamento.VozAlerta);

View File

@ -43,7 +43,7 @@ namespace AgroBase.Forms
private async Task AtualizarParametros()
{
(bool sucesso, LoRaParametrosModel par) = (false, null);
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
{
(sucesso, par) = await LoRaBaseService.RequisitarParametrosModuloAsync();
}
@ -86,7 +86,7 @@ namespace AgroBase.Forms
private async Task tmrLeitura_Tick()
{
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
{
var MensagemDisponivel = LoRaBaseService.MensagemPendente;
if (MensagemDisponivel != null)
@ -152,7 +152,7 @@ namespace AgroBase.Forms
private async Task ConfigurarModulo()
{
(bool Sucesso, LoRaParametrosModel par) = (false, null);
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
{
(Sucesso, par) = await LoRaBaseService.ConfigurarModuloAsync(Parametros);
}
@ -202,7 +202,7 @@ namespace AgroBase.Forms
}
}
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
{
LoRaBaseService.EnviarDadosLoRa(payload.ToArray(), destinatario);
}

View File

@ -34,7 +34,7 @@ namespace AgroBase
cmbModoOperacao.Items.Clear();
cmbModoOperacao.Items.AddRange(Enum.GetNames(typeof(ModoOperacao)));
cmbModoOperacao.SelectedIndex = (int)(Variaveis.OperacaoEmAndamento.Parametros?.Modo ?? ModoOperacao.NaoDefinido);
cmbModoOperacao.SelectedIndex = (int)(Variaveis.OperacaoEmAndamento?.Parametros?.Modo ?? ModoOperacao.NaoDefinido);
}
private async void frmPrincipal_FormClosing(object sender, FormClosingEventArgs e)

View File

@ -37,7 +37,7 @@ namespace AgroBase.Models
public void AtualizarDados()
{
var saude = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorSaude?.ModulosSaude;
var saude = Variaveis.OperacaoEmAndamento?.Sensoriamento?.OperadorSaude?.ModulosSaude ?? new System.Collections.Generic.List<Operadores.ManagerWorkerMessageResponseModulosPendentesModel>();
Status = saude?.FirstOrDefault(x => x.modulo == Dispositivo)?.status ?? StatusModulo.Desconectado;
Saude = saude?.FirstOrDefault(x => x.modulo == Dispositivo)?.saude ?? 0;

View File

@ -1895,6 +1895,8 @@ namespace AgroBase.Models.Modules
{
var op = Variaveis.OperacaoEmAndamento;
if (!op.Sensoriamento.Operacao.ModsCalibragem.ContainsKey(T_Code.Atu))
op.Sensoriamento.Operacao.ModsCalibragem.Add(T_Code.Atu, new Dictionary<string, bool>());
var calAtu = op.Sensoriamento.Operacao.ModsCalibragem[Dispositivo];
// Ligar bomba

View File

@ -677,9 +677,9 @@ namespace AgroBase.Models.Modules
{
var op = Variaveis.OperacaoEmAndamento;
var ctrl = op.Controle;
var disp = op.DispMvd?.Dados?.Modulos;
if (op.Sensoriamento?.Operacao?.StatusOperacaoAtual != StatusOperacao.EmAndamento || ctrl == null || disp == null || !MovimentosCompensar.Contains(ctrl.TipoMovimento))
var ctrl = op?.Controle;
var disp = op?.DispMvd?.Dados?.Modulos;
if (op?.Sensoriamento?.Operacao?.StatusOperacaoAtual != StatusOperacao.EmAndamento || ctrl == null || disp == null || !MovimentosCompensar.Contains(ctrl.TipoMovimento))
{
compensacoes = (disp ?? Enumerable.Empty<ModuloMvdModel>()).ToDictionary(x => x.Modulo_ID, x => 1.0);
return;

View File

@ -36,8 +36,6 @@ namespace AgroBase.Models.Modules
public double ReducaoMotorBLDC { get; set; } = 5;
public double RPM_Max_MotorBLDC { get; set; } = 500;
public string IP_Mov { get; set; } = Variaveis.FaixaIPethernet + ".10";
public string IP_Dir { get; set; } = Variaveis.FaixaIPethernet + ".11";
public DateTime UltimoTickRegistrador = DateTime.MinValue;
public static int LogsManter { get; set; } = 60;
@ -506,7 +504,7 @@ namespace AgroBase.Models.Modules
TipoMovimentoDirecional tipoControle = op.Controle.TipoMovimento;
op.Controle.TipoMovimento = TipoMovimentoDirecional.Diagnostico;
op.DefinirTipoMovimentoControle(TipoMovimentoDirecional.Diagnostico);
var ModsRef = Modulos.Where(x => x.DirMotor.Comandar && x.DirMotor.Inicializado && (ModsReferenciar != null ? ModsReferenciar.Contains(x.DirMotor.Mod_ID) : true)).ToList();
foreach (var Modulo in ModsRef)
{
@ -515,7 +513,7 @@ namespace AgroBase.Models.Modules
bool ReferenciamentoConcluido() => !MKS057DCanService.Referenciando;
await FuncoesGlobais.AguardarCondicaoAsync(ReferenciamentoConcluido, 2 * 1000 * 60, 1000);
op.Controle.TipoMovimento = tipoControle;
op.DefinirTipoMovimentoControle(tipoControle);
}
return Modulos.All(x => x.DirMotor.Referenciado);
@ -568,7 +566,7 @@ namespace AgroBase.Models.Modules
if (DispMvd.Dados.Modulos.Any(x => x.DirMotor.Inicializado))
{
op.Controle.TipoMovimento = TipoMovimentoDirecional.Diagnostico;
op.DefinirTipoMovimentoControle(TipoMovimentoDirecional.Diagnostico);
var ModsRef = Modulos.Where(x => x.DirMotor.Comandar).ToList(); // && x.DirMotor.Inicializado
foreach (var Modulo in ModsRef)
{

View File

@ -25,6 +25,72 @@ namespace AgroBase.Models
{
public class OperacaoModel
{
#region TIMERS
public double tmrLeiturasInterval
{
get
{
return tmrLeituras?.Interval ?? 500;
}
set
{
tmrLeituras?.SetInterval((int)value);
}
}
private AsyncTaskTimerModel tmrLeituras;
private AsyncTaskTimerModel tmrComunicacao;
public void IniciarTimersSistema()
{
if (!Variaveis.IsAgroBase)
return;
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
{
Variaveis.MostrarLog(
$"[OperacaoModel.IniciarTimersSistema] Ignorado: instância não é atual. " +
$"Hash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
);
return;
}
tmrLeituras?.Stop();
tmrLeituras?.Dispose();
tmrLeituras = new AsyncTaskTimerModel($"tmrLeitura_{GetHashCode()}", tmrLeituras_Tick, 500);
tmrLeituras.Start();
tmrComunicacao?.Stop();
tmrComunicacao?.Dispose();
tmrComunicacao = new AsyncTaskTimerModel($"tmrComunicacao_{GetHashCode()}", tmrComunicacao_Tick, 1000);
tmrComunicacao.Start();
Variaveis.MostrarLog(
$"[OperacaoModel.IniciarTimersSistema] Timers iniciados. Hash={GetHashCode()}, Modo={Parametros?.Modo}"
);
}
public void PararTimersSistema()
{
try
{
tmrLeituras?.Stop();
tmrLeituras?.Dispose();
tmrLeituras = null;
tmrComunicacao?.Stop();
tmrComunicacao?.Dispose();
tmrComunicacao = null;
Variaveis.MostrarLog(
$"[OperacaoModel.PararTimersSistema] Timers do sistema parados. Operacao={ID}, Hash={GetHashCode()}, idxLog={idxLog}"
);
}
catch (Exception ex)
{
Variaveis.MostrarLog("[OperacaoModel.PararTimersSistema] Erro ao parar timers do sistema: " + ex.Message);
}
}
public double tmrLogsInterval
{
get
@ -39,40 +105,35 @@ namespace AgroBase.Models
private AsyncTaskTimerModel _tmrLogsOperacao;
private int idxLog = 0;
private readonly SemaphoreSlim _salvarLogsGate = new SemaphoreSlim(1, 1);
public double tmrLeiturasInterval
private void IniciarTimerLogsOperacao()
{
get
if (!Variaveis.IsAgroBase)
return;
_tmrLogsOperacao?.Stop();
_tmrLogsOperacao?.Dispose();
_tmrLogsOperacao = new AsyncTaskTimerModel($"tmrLogs_{ID}", tmrLogs_Tick, 1000);
_tmrLogsOperacao.Start();
Variaveis.MostrarLog($"[OperacaoModel.IniciarTimerLogsOperacao] Timer de logs iniciado. Operacao={ID}, Hash={GetHashCode()}");
}
private void PararTimerLogsOperacao()
{
try
{
return tmrLeituras.Interval;
_tmrLogsOperacao?.Stop();
Variaveis.MostrarLog($"[OperacaoModel.PararTimerLogsOperacao] Timer de logs parado. Operacao={ID}, Hash={GetHashCode()}, idxLog={idxLog}");
}
set
catch (Exception ex)
{
tmrLeituras.SetInterval((int)value);
Variaveis.MostrarLog("[OperacaoModel.PararTimerLogsOperacao] Erro ao parar timer de logs: " + ex.Message);
}
}
private static AsyncTaskTimerModel tmrLeituras;
private static AsyncTaskTimerModel tmrComunicacao;
public OperacaoModel()
{
Variaveis.MostrarLog("[OperacaoModel.ctor] StackTrace: " + Environment.StackTrace);
Variaveis.MostrarLog(
$"[OperacaoModel.ctor] Nova instância. Hash={GetHashCode()}, " +
$"OperacaoAtual={Variaveis.OperacaoEmAndamento?.ID}, " +
$"HashAtual={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
);
tmrLeituras?.Dispose();
tmrLeituras = new AsyncTaskTimerModel("tmrLeitura", tmrLeituras_Tick, 500);
tmrLeituras.Start();
tmrComunicacao?.Dispose();
tmrComunicacao = new AsyncTaskTimerModel("tmrComunicacao", tmrComunicacao_Tick, 1000);
tmrComunicacao.Start();
}
#endregion
public StatusModulo Status { get; set; }
public string Descricao { get; set; }
@ -105,8 +166,27 @@ namespace AgroBase.Models
#region PARAMETRIZACAO
public (bool, List<string>) CarregarParametrizacaoOperacao(Panel pnlMapa, Label lblMapa, string opPath = "")
private bool EhOperacaoAtual(string origem)
{
if (ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
return true;
Variaveis.MostrarLog(
$"[OperacaoModel.{origem}] Ignorado: instância não é atual. " +
$"Hash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}, ID={ID}, AtualID={Variaveis.OperacaoEmAndamento?.ID}"
);
return false;
}
public bool CarregarParametrizacaoOperacao(Panel pnlMapa, Label lblMapa, string opPath = "")
{
if (Variaveis.OperacaoEmAndamento?.Sensoriamento?.Operacao?.OperacaoIniciada == true)
{
Variaveis.MostrarLog("[OperacaoModel.CarregarParametrizacaoOperacao] Ignorado: tentativa de carregar operação com operação iniciada.");
return false;
}
string path = Variaveis.CaminhoSistema + Variaveis.CaminhoOperacoes + MapasVariaveisModel.NomeArquivoMapaInterativoSaida;
OpenFileDialog openFileDialog = new OpenFileDialog();
@ -118,54 +198,35 @@ namespace AgroBase.Models
{
string opr_path = !string.IsNullOrEmpty(opPath) ? opPath : openFileDialog.FileName;
if (!File.Exists(opr_path)) return (false, new List<string>());
if (!File.Exists(opr_path)) return false;
string ParametrosJson = File.ReadAllText(opr_path, Encoding.UTF8);
var Parametros = JsonConvert.DeserializeObject<OperacaoParametrosModel>(ParametrosJson);
if (Parametros.Modo == null) return (false, new List<string>());
if (Parametros.Modo == null) return false;
Variaveis.OperacaoEmAndamento = CarregarParametrosOperacaoPadrao((ModoOperacao)Parametros.Modo, CarregarModulos: true);
var op = Variaveis.OperacaoEmAndamento;
var newOp = CarregarParametrosOperacaoPadrao((ModoOperacao)Parametros.Modo, CarregarModulos: true);
op.Parametros = Parametros;
op.DefinirComponentesEmUso();
newOp.Parametros = Parametros;
newOp.DefinirComponentesEmUso();
op.Descricao = Parametros.Descricao;
op.OprPath = opr_path;
if (op.DispSen == null)
newOp.Descricao = Parametros.Descricao;
newOp.OprPath = opr_path;
if (newOp.DispSen == null)
{
op.DispSen = new DispositivosService<SensoriamentoModel>();
newOp.DispSen = new DispositivosService<SensoriamentoModel>();
}
//Variaveis.OperacaoEmAndamento.DispSen.Dados.ConfiguracaoSensorUltrassom = Parametros.ConfiguracaoUltrassom;
List<string> ruasSelecionadas = new List<string>();
//if (Parametros.Mapa.mapaService.DadosMapa != null)
//{
// ruasSelecionadas = Parametros.Mapa.RuasPercorrer.ToList();
// string geoJson = JsonConvert.SerializeObject(Parametros.Mapa.mapaService.DadosMapa, Formatting.None);
// File.WriteAllText(path, geoJson, Encoding.UTF8);
// Variaveis.OperacaoEmAndamento.Mapa = Parametros.Mapa;
//
// /*Panel pnlMapa = FuncoesGlobais.FindControlRecursive<Panel>(Variaveis.OperacaoEmAndamento.frmOperacao, "pnlMapa");
// Label lblMapa = FuncoesGlobais.FindControlRecursive<Label>(Variaveis.OperacaoEmAndamento.frmOperacao, "lblMapaCarregado");*/
// Variaveis.OperacaoEmAndamento.Mapa.pnlMapa = pnlMapa;
// Variaveis.OperacaoEmAndamento.Mapa.lblMapa = lblMapa;
//
// Variaveis.OperacaoEmAndamento.Mapa.btnCarregar_Click(new object(), new EventArgs(), path);
//
// //bool condicaoMapaCarregado() => Variaveis.OperacaoEmAndamento.Mapa.mapaService.Carregado;
// //bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoMapaCarregado, 5000, 200);
//}
Variaveis.OperacaoEmAndamento = newOp;
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
return (true, ruasSelecionadas);
return true;
}
else
{
return (false, new List<string>());
return false;
}
}
@ -256,7 +317,7 @@ namespace AgroBase.Models
AtuDuracaoAtuacao = 200,
AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 70,
AtuPercentualInicioPulverizacao = 85,
AtuPressaoLinha = 22,
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
AtuModoControle = ModoControleBomba.PID
@ -367,7 +428,7 @@ namespace AgroBase.Models
AtuDuracaoAtuacao = 200,
AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 70,
AtuPercentualInicioPulverizacao = 85,
AtuPressaoLinha = 22,
AtuAgitadorModo = ModoAgitadorCalda.Continuo,
AtuModoControle = ModoControleBomba.PID,
@ -646,7 +707,7 @@ namespace AgroBase.Models
AtuDuracaoAtuacao = 200,
AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 70,
AtuPercentualInicioPulverizacao = 85,
AtuPressaoLinha = 22,
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
AtuModoControle = ModoControleBomba.PID,
@ -745,7 +806,7 @@ namespace AgroBase.Models
AtuDuracaoAtuacao = 200,
AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 70,
AtuPercentualInicioPulverizacao = 85,
AtuPressaoLinha = 22,
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
AtuModoControle = ModoControleBomba.PID,
@ -966,47 +1027,60 @@ namespace AgroBase.Models
});
}
public (bool, List<string>) CarregarParamerosOperacaoBase(OperacaoParametrosModel Parametros)
public static OperacaoModel CarregarParamerosOperacaoBase(OperacaoParametrosModel parametros)
{
if (Parametros.Modo == null) return (false, new List<string>());
if (parametros?.Modo == null)
return null;
Variaveis.OperacaoEmAndamento = CarregarParametrosOperacaoPadrao((ModoOperacao)Parametros.Modo, CarregarModulos: true);
var op = Variaveis.OperacaoEmAndamento;
var novaOp = CarregarParametrosOperacaoPadrao((ModoOperacao)parametros.Modo, CarregarModulos: true);
op.Descricao = Parametros.Descricao;
op.OprPath = $"Base ({VariaveisEquipamento.Parametros.base_ip})";
var p = op.Parametros;
p.Descricao = Parametros.Descricao;
p.CapacidadeReservatorio = Parametros.CapacidadeReservatorio;
p.Controle = Parametros.Controle;
p.QtdBicos = Parametros.QtdBicos;
p.QtdCamerasSolo = Parametros.QtdCamerasSolo;
p.TipoMapa = Parametros.TipoMapa;
p.Mapa = Parametros.Mapa;
p.RuasPercorrer = Parametros.RuasPercorrer;
p.PontosRetorno = Parametros.PontosRetorno;
p.ModulosMandatorios = Parametros.ModulosMandatorios;
p.ParametrosMandatorios = Parametros.ParametrosMandatorios;
novaOp.Descricao = parametros.Descricao;
novaOp.OprPath = "";
op.DefinirComponentesEmUso();
novaOp.Parametros.Descricao = parametros.Descricao;
novaOp.Parametros.CapacidadeReservatorio = parametros.CapacidadeReservatorio;
novaOp.Parametros.Controle = parametros.Controle;
novaOp.Parametros.QtdBicos = parametros.QtdBicos;
novaOp.Parametros.QtdCamerasSolo = parametros.QtdCamerasSolo;
novaOp.Parametros.TipoMapa = parametros.TipoMapa;
novaOp.Parametros.Mapa = parametros.Mapa;
novaOp.Parametros.RuasPercorrer = parametros.RuasPercorrer;
novaOp.Parametros.PontosRetorno = parametros.PontosRetorno;
novaOp.Parametros.ModulosMandatorios = parametros.ModulosMandatorios;
novaOp.Parametros.ParametrosMandatorios = parametros.ParametrosMandatorios;
List<string> ruasSelecionadas = Parametros.RuasPercorrer ?? new List<string>();
if (Parametros.Mapa != null)
novaOp.DefinirComponentesEmUso();
var ruasSelecionadas = parametros.RuasPercorrer ?? new List<string>();
if (parametros.Mapa != null)
{
op.Mapa = new MapasModel() { RuasPercorrer = ruasSelecionadas };
op.Mapa.TipoMapa = p.TipoMapa;
op.Mapa.PopularTrajetoriaMapa(Parametros.Mapa);
novaOp.Mapa = new MapasModel() { RuasPercorrer = ruasSelecionadas };
novaOp.Mapa.TipoMapa = novaOp.Parametros.TipoMapa;
novaOp.Mapa.PopularTrajetoriaMapa(parametros.Mapa);
}
Variaveis.OperacaoEmAndamento = novaOp;
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
return (true, ruasSelecionadas);
return novaOp;
}
public async Task IniciarOperacao()
{
if (!EhOperacaoAtual(nameof(IniciarOperacao)))
return;
var op = this;
if (op.Sensoriamento?.Operacao?.OperacaoIniciada == true)
{
Variaveis.MostrarLog("[OperacaoModel.IniciarOperacao] Ignorado: operação já iniciada.");
return;
}
DateTime agora = DateTime.Now;
var dispSen = op.DispSen;
var dispAtu = op.DispAtu;
@ -1045,6 +1119,7 @@ namespace AgroBase.Models
VisualWorkerService.ReiniciarLeituraAnalise();
op.Controle.Reiniciar();
op.DefinirTipoMovimentoControle(TipoMovimentoDirecional.RodasDianteiras);
op.ControleAnterior.Reiniciar();
double distanciaPercorrida = dispMvd?.Dados?.DistanciaPercorridaTotal ?? 0;
@ -1071,6 +1146,9 @@ namespace AgroBase.Models
{
var op = this;
if (!EhOperacaoAtual(nameof(FinalizarOperacao)))
return;
if (op.Sensoriamento.Operacao.Finalizando)
return;
@ -1107,6 +1185,9 @@ namespace AgroBase.Models
public void ReiniciarOperacao(bool daBase)
{
if (!EhOperacaoAtual(nameof(ReiniciarOperacao)))
return;
var op = this;
RedisService.AtualizarCampos(
@ -1115,14 +1196,23 @@ namespace AgroBase.Models
("iniciado", false)
);
CarregarParamerosOperacaoBase(op.Parametros);
var novaOp = CarregarParamerosOperacaoBase(op.Parametros);
if (novaOp == null)
{
Variaveis.MostrarLog("[OperacaoModel.ReiniciarOperacao] Falha ao recriar operação.");
return;
}
if (daBase)
op.EnviarParametorsOperacao();
novaOp.EnviarParametorsOperacao();
}
public async Task IniciarSimulacao()
{
if (!EhOperacaoAtual(nameof(IniciarSimulacao)))
return;
var op = this;
var dispSen = op.DispSen;
var dispAtu = op.DispAtu;
@ -1148,6 +1238,7 @@ namespace AgroBase.Models
VisualWorkerService.ReiniciarLeituraAnalise();
op.Controle.Reiniciar();
op.DefinirTipoMovimentoControle(TipoMovimentoDirecional.RodasDianteiras);
op.ControleAnterior.Reiniciar();
op.GPSTrajetoria = new List<GPSModel>();
@ -1159,6 +1250,9 @@ namespace AgroBase.Models
public void ReiniciarSimulacao()
{
if (!EhOperacaoAtual(nameof(ReiniciarSimulacao)))
return;
this.ReiniciarOperacao(false);
var Topico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa);
@ -1171,6 +1265,9 @@ namespace AgroBase.Models
public void IniciarTreinamento()
{
if (!EhOperacaoAtual(nameof(IniciarTreinamento)))
return;
var op = this;
var dispSen = op.DispSen;
var dispAtu = op.DispAtu;
@ -1194,34 +1291,6 @@ namespace AgroBase.Models
op.GPSTrajetoria = new List<GPSModel>();
}
private void IniciarTimerLogsOperacao()
{
_tmrLogsOperacao?.Stop();
_tmrLogsOperacao?.Dispose();
_tmrLogsOperacao = new AsyncTaskTimerModel($"tmrLogs_{ID}", tmrLogs_Tick, 1000);
_tmrLogsOperacao.Start();
Variaveis.MostrarLog($"[OperacaoModel.IniciarTimerLogsOperacao] Timer de logs iniciado. Operacao={ID}, Hash={GetHashCode()}");
}
private void PararTimerLogsOperacao()
{
try
{
_tmrLogsOperacao?.Stop();
Variaveis.MostrarLog($"[OperacaoModel.PararTimerLogsOperacao] Timer de logs parado. Operacao={ID}, Hash={GetHashCode()}, idxLog={idxLog}");
}
catch (Exception ex)
{
Variaveis.MostrarLog("[OperacaoModel.PararTimerLogsOperacao] Erro ao parar timer de logs: " + ex.Message);
}
}
public static string DeserializarDadosOperacao(string caminho, string arquivo)
{
string pastaBase = Path.GetDirectoryName(caminho) ?? "";
@ -1279,16 +1348,32 @@ namespace AgroBase.Models
{
var op = this;
if (string.IsNullOrEmpty(op.OprPath)) return;
if (string.IsNullOrWhiteSpace(op.ID))
return;
var Caminho = Variaveis.CaminhoOperacoes + op.ID;
if (!Directory.Exists(Caminho))
string pastaOperacao = Path.Combine(Variaveis.CaminhoOperacoes, op.ID);
Directory.CreateDirectory(pastaOperacao);
string caminhoOperacao = Path.Combine(pastaOperacao, "operacao.opr");
try
{
Directory.CreateDirectory(Caminho);
}
if (!string.IsNullOrWhiteSpace(op.OprPath) && File.Exists(op.OprPath))
{
File.Copy(op.OprPath, caminhoOperacao, overwrite: true);
return;
}
Caminho += "/operacao.opr";
File.Copy(op.OprPath, Caminho);
// Operação recebida da base: salva os parâmetros como .opr
string json = JsonConvert.SerializeObject(op.Parametros, Formatting.Indented);
File.WriteAllText(caminhoOperacao, json, Encoding.UTF8);
Variaveis.MostrarLog($"[OperacaoModel.SalvarOperacao] Operação salva a partir dos parâmetros. OprPath='{op.OprPath}'");
}
catch (Exception ex)
{
Variaveis.MostrarLog("[OperacaoModel.SalvarOperacao] Erro ao salvar operação: " + ex);
}
}
@ -1459,7 +1544,7 @@ namespace AgroBase.Models
}
finally
{
op.Controle.TipoMovimento = tipoControle;
op.DefinirTipoMovimentoControle(tipoControle);
if (entrouEmCalibragem)
{
@ -1510,8 +1595,54 @@ namespace AgroBase.Models
#region CONTROLE DA OPERACAO
public void DefinirTipoMovimentoControle(TipoMovimentoDirecional value)
{
if (!EhOperacaoAtual(nameof(DefinirTipoMovimentoControle)))
return;
var dispMvd = DispMvd;
if (dispMvd?.Dados?.Modulos != null && value != Controle.TipoMovimento)
{
switch (value)
{
case TipoMovimentoDirecional.RodasDianteiras:
dispMvd.Dados.Modulos.ForEach(x =>
{
x.MovMotor.Comandar = true;
x.DirMotor.Comandar = x.Modulo_ID.Contains("F");
x.DirMotor.Angulo_SP = x.DirMotor.Comandar ? Controle.Angulo : 0;
});
break;
case TipoMovimentoDirecional.RodasTraseiras:
dispMvd.Dados.Modulos.ForEach(x =>
{
x.MovMotor.Comandar = true;
x.DirMotor.Comandar = x.Modulo_ID.Contains("T");
x.DirMotor.Angulo_SP = x.DirMotor.Comandar ? Controle.Angulo : 0;
});
break;
default:
dispMvd.Dados.Modulos.ForEach(x =>
{
x.MovMotor.Comandar = true;
x.DirMotor.Comandar = true;
x.DirMotor.Angulo_SP = Controle.Angulo;
});
break;
}
}
Controle.TipoMovimento = value;
}
public void AtualizaInformacoesControleOperacao()
{
if (!EhOperacaoAtual(nameof(AtualizaInformacoesControleOperacao)))
return;
var op = this;
var pControle = op.Parametros.Controle;
@ -1531,6 +1662,9 @@ namespace AgroBase.Models
public void AtualizarDadosControle(bool ForcarEnvio, List<T_Code> Dispositivos)
{
if (!EhOperacaoAtual(nameof(AtualizarDadosControle)))
return;
var op = this;
DateTime Agora = DateTime.Now;
@ -1566,6 +1700,9 @@ namespace AgroBase.Models
public List<string> EnviarProtocoloComando(T_Code Tipo, bool ForcarEnvio)
{
if (!EhOperacaoAtual(nameof(EnviarProtocoloComando)))
return new List<string>();
var op = this;
if (!op.Sensoriamento.Operacao.OperacaoIniciada && !ForcarEnvio)
@ -1641,19 +1778,20 @@ namespace AgroBase.Models
case T_Code.Atu:
{
op.DispAtu?.Dados?.SincronizarBombaPressurizadoraAutomatica();
var bicos = op.DispAtu?.Dados?.BicosPulverizadores ?? new List<AtuadorBicoModel>();
for (int i = 0; i < _Controle.Bicos.Count; i++)
for (int i = 0; i < bicos.Count; i++)
{
Estado comandoEstado = _Controle.Bicos[i].ComandoAtuar ? Estado.Ligado : Estado.Desligado;
if (ForcarEnvio || comandoEstado != _Controle.Bicos[i]._EstadoLeitura)
Estado comandoEstado = bicos[i].ComandoAtuar ? Estado.Ligado : Estado.Desligado;
if (ForcarEnvio || comandoEstado != bicos[i]._EstadoLeitura)
{
GeneralJoystick.EnviarComandoAtuador(_Controle.Bicos[i].Componente, _Controle.Bicos[i].ID, Status: _Controle.Bicos[i].ComandoAtuar);
GeneralJoystick.EnviarComandoAtuador(bicos[i].Componente, bicos[i].ID, Status: bicos[i].ComandoAtuar);
}
}
Protocolos = new List<string>()
{
string.Join(";", _Controle.Bicos.Select(x => x.ComandoAtuar ? "1" : "0")) + ";" + (ForcarEnvio ? "1": "0")
string.Join(";", bicos.Select(x => x.ComandoAtuar ? "1" : "0")) + ";" + (ForcarEnvio ? "1": "0")
};
break;
}
@ -1664,11 +1802,22 @@ namespace AgroBase.Models
return Protocolos;
}
private async Task tmrLeituras_Tick()
{
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
return;
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
{
Variaveis.MostrarLog(
$"[OperacaoModel.{nameof(tmrLeituras_Tick)}] Timer órfão ignorado. " +
$"TimerHash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
);
return;
}
var op = this;
op.Sensoriamento?.AtualizarDados();
@ -1707,10 +1856,21 @@ namespace AgroBase.Models
}
}
private async Task tmrComunicacao_Tick()
{
if (!Variaveis.IsAgroBase)
return;
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
{
Variaveis.MostrarLog(
$"[OperacaoModel.{nameof(tmrComunicacao_Tick)}] Timer órfão ignorado. " +
$"TimerHash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
);
return;
}
var service = Variaveis.MqttServiceBase;
if (service == null)
@ -1788,9 +1948,9 @@ namespace AgroBase.Models
// CAMPOS
// ============================================================================
private readonly SemaphoreSlim _baseCommandGate = new SemaphoreSlim(1, 1);
private readonly object _baseCommandDedupeLock = new object();
private readonly Dictionary<string, DateTime> _baseCommandDedupe = new Dictionary<string, DateTime>();
private static readonly SemaphoreSlim _baseCommandGate = new SemaphoreSlim(1, 1);
private static readonly object _baseCommandDedupeLock = new object();
private static readonly Dictionary<string, DateTime> _baseCommandDedupe = new Dictionary<string, DateTime>();
private static readonly TimeSpan BaseCommandDedupeWindow = TimeSpan.FromMilliseconds(1500);
@ -1859,14 +2019,34 @@ namespace AgroBase.Models
public async Task ExecutaComandoDaBaseAsync(OperacaoComandoBaseModel controleBase)
{
var op = this;
if (controleBase == null)
return;
if (Variaveis.Fechando)
return;
var opAtual = Variaveis.OperacaoEmAndamento;
if (opAtual == null)
{
Variaveis.MostrarLog("[OperacaoModel.ExecutaComandoDaBaseAsync] Ignorado: não existe OperacaoEmAndamento.");
return;
}
if (!ReferenceEquals(this, opAtual))
{
Variaveis.MostrarLog(
$"[OperacaoModel.ExecutaComandoDaBaseAsync] Comando recebido por instância antiga. " +
$"ReceiverHash={GetHashCode()}, AtualHash={opAtual.GetHashCode()}, " +
$"Cmd={controleBase.Dispositivo}/{controleBase.Tecla}. Redirecionando."
);
await opAtual.ExecutaComandoDaBaseAsync(controleBase).ConfigureAwait(false);
return;
}
var op = opAtual;
if (op.EhComandoDuplicado(controleBase))
return;
@ -1874,22 +2054,14 @@ namespace AgroBase.Models
try
{
/*
* Comando remoto é rota crítica.
* Processar em série evita:
* - iniciar e finalizar operação ao mesmo tempo;
* - atualizar parâmetros enquanto inicia operação;
* - dois comandos de atuador disputando o mesmo estado local.
*/
await _baseCommandGate.WaitAsync().ConfigureAwait(false);
entered = true;
await op.ExecutaComandoDaBaseInternoAsync(controleBase).ConfigureAwait(false);
}
catch (Exception ex)
{
Variaveis.MostrarLog("[ComandoBase] Erro ao executar comando: " + ex);
Variaveis.MostrarLog("[OperacaoModel.ExecutaComandoDaBaseAsync] Erro ao executar comando: " + ex);
}
finally
{
@ -1962,6 +2134,14 @@ namespace AgroBase.Models
private async Task ExecutarComandoModuloAsync(OperacaoComandoBaseModel controleBase, OperacaoModel op)
{
op = Variaveis.OperacaoEmAndamento;
if (op == null)
return;
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, op))
return;
var parametros = controleBase.Parametros;
switch (controleBase.Tecla)
@ -1974,19 +2154,17 @@ namespace AgroBase.Models
if (parametros == null)
return;
/*
* Carga completa de parâmetros. Idealmente antes
* da operação estar iniciada.
*/
if (op.Sensoriamento.Operacao.OperacaoIniciada)
if (Variaveis.OperacaoEmAndamento?.Sensoriamento?.Operacao?.OperacaoIniciada == true)
{
Variaveis.MostrarLog("[ComandoBase] Ignorando carga completa de parâmetros com operação iniciada.");
Variaveis.MostrarLog("[OperacaoModel.ExecutarComandoModuloAsync] Ignorando carga completa de parâmetros com operação iniciada.");
return;
}
op.CarregarParamerosOperacaoBase(parametros);
var novaOp = CarregarParamerosOperacaoBase(parametros);
if (novaOp != null)
await novaOp.EnviarParametrosOperacaoAsync().ConfigureAwait(false);
await op.EnviarParametrosOperacaoAsync().ConfigureAwait(false);
return;
case BotoesJoystick.Touchpad:
@ -2200,7 +2378,7 @@ namespace AgroBase.Models
if (TryDeserializeValue(controleBase._comp_value, out angulo))
{
var bico = op.Controle.Bicos.FirstOrDefault(x => x.ID == controleBase._comp_id);
var bico = dadosAtu.BicosPulverizadores?.FirstOrDefault(x => x.ID == controleBase._comp_id);
if (bico != null)
bico.AnguloAbertura = angulo;
@ -2367,7 +2545,7 @@ namespace AgroBase.Models
controle.Angulo = (double)controleBase.Controle.AnguloSP;
if (controleBase.Controle.TipoMovimentoDirecional != null)
controle.TipoMovimento = (TipoMovimentoDirecional)controleBase.Controle.TipoMovimentoDirecional;
op.DefinirTipoMovimentoControle((TipoMovimentoDirecional)controleBase.Controle.TipoMovimentoDirecional);
if (controleBase.Controle.EmFreio != null)
controle.EmFreio = (bool)controleBase.Controle.EmFreio;
@ -2660,7 +2838,7 @@ namespace AgroBase.Models
{
Variaveis.MostrarLog($"[OperacaoModel.tmrLogs_Tick] Timer órfão parado. TimerHash={GetHashCode()}, OperacaoTimer={ID}, OperacaoAtual={Variaveis.OperacaoEmAndamento?.ID}");
PararTimerLogsOperacao();
_tmrLogsOperacao?.Dispose();
return;
}
@ -3246,57 +3424,8 @@ namespace AgroBase.Models
}
}
public bool EmFreio { get; set; } = false;
//public Direcao Direcao { get; set; } = Direcao.Parado;
[JsonIgnore]
public List<AtuadorBicoModel> Bicos => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores;
public double AlturaBarra { get; set; }
private TipoMovimentoDirecional _tipoMovimento = TipoMovimentoDirecional.Diagnostico;
public TipoMovimentoDirecional TipoMovimento
{
get
{
return _tipoMovimento;
}
set
{
var DispMvd = Variaveis.OperacaoEmAndamento.DispMvd;
if (DispMvd != null)
{
if (value != _tipoMovimento)
{
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
switch (value)
{
case TipoMovimentoDirecional.RodasDianteiras:
DispMvd.Dados.Modulos.ForEach(x =>
{
x.MovMotor.Comandar = true;
x.DirMotor.Comandar = x.Modulo_ID.Contains("F");
x.DirMotor.Angulo_SP = x.DirMotor.Comandar ? _Controle.Angulo : 0;
});
break;
case TipoMovimentoDirecional.RodasTraseiras:
DispMvd.Dados.Modulos.ForEach(x =>
{
x.MovMotor.Comandar = true;
x.DirMotor.Comandar = x.Modulo_ID.Contains("T");
x.DirMotor.Angulo_SP = x.DirMotor.Comandar ? _Controle.Angulo : 0;
});
break;
default:
DispMvd.Dados.Modulos.ForEach(x =>
{
x.MovMotor.Comandar = true;
x.DirMotor.Comandar = true;
x.DirMotor.Angulo_SP = _Controle.Angulo;
});
break;
}
}
}
_tipoMovimento = value;
}
}
public TipoMovimentoDirecional TipoMovimento { get; set; } = TipoMovimentoDirecional.Diagnostico;
public List<OperacaoControleTipoModel> TiposControle { get; set; } = new List<OperacaoControleTipoModel>();
public List<MPCSimulacaoModel> SimulacaoMPC { get; set; } = new List<MPCSimulacaoModel>();
public double Latencia { get; set; }
@ -3306,11 +3435,9 @@ namespace AgroBase.Models
public void Reiniciar()
{
var _Parametros = Variaveis.OperacaoEmAndamento.Parametros.Controle;
PercentualVelocidadeSP = 0; // _Parametros.MovimentoAutomatico ? 0 : _Parametros.MovVelocidadeCErvasPercent;
Angulo = 0; // _Parametros.DirecionalAutomatico ? 0 : _Parametros.DirAnguloMaximo;
PercentualVelocidadeSP = 0;
Angulo = 0;
EmFreio = false;
TipoMovimento = TipoMovimentoDirecional.RodasDianteiras;
TiposControle.ForEach(x =>
{
x.DirecaoAtual = Direcao.Parado;
@ -3348,8 +3475,6 @@ namespace AgroBase.Models
Motivos = new List<string>(Motivos ?? new List<string>())
};
clone._tipoMovimento = _tipoMovimento;
return clone;
}
}
@ -3472,6 +3597,7 @@ namespace AgroBase.Models
OperacaoLiberada = RedisService.GetField(CtxKey.DadosOperacao, "liberado", false),
OperacaoConfigurada = RedisService.GetField(CtxKey.DadosOperacao, "configurado", false),
ErroOperacaoLiberada = RedisService.GetField<string>(CtxKey.DadosOperacao, "motivo_nao_liberado"),
OperacaoLiberacaoDebug = RedisService.GetField<JObject>(CtxKey.DadosOperacao, "operacao_liberacao_debug"),
StatusOperacaoAtual = (StatusOperacao)RedisService.GetField<int>(CtxKey.DadosOperacao, "status", 0),
TempoAguardandoSeg = RedisService.GetField<long>(CtxKey.DadosOperacao, "tempo_aguardando", 0),
@ -3490,7 +3616,7 @@ namespace AgroBase.Models
var saude = OperadorSaude.ModulosSaude;
var saudeAnterior = new List<ManagerWorkerMessageResponseModulosPendentesModel>(saude ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>());
saude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos").ToList();
saude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos")?.ToList() ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>();
foreach (var mod in saude)
{
@ -4544,7 +4670,7 @@ namespace AgroBase.Models
{
if (op == null) return;
HealthWorkerService.DadosLeitura.ModulosSaude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos").ToList();
HealthWorkerService.DadosLeitura.ModulosSaude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos")?.ToList() ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>();
OperadorSaude = HealthWorkerService.DadosLeitura.Clone();
OperadorSaude.Momento = agora;
OperadorVisual = VisualWorkerService.DadosLeitura.Clone();
@ -4743,6 +4869,7 @@ namespace AgroBase.Models
public StatusOperacao StatusOperacaoAtual { get; set; }
public StatusOperacao StatusOperacaoAnterior { get; set; }
public string ErroOperacaoLiberada { get; set; }
public JObject OperacaoLiberacaoDebug { get; set; }
public bool OperacaoConfigurada { get; set; }
public bool OperacaoLiberada { get; set; }
public bool OperacaoIniciada { get; set; }
@ -4779,6 +4906,7 @@ namespace AgroBase.Models
ControleAutomatico = ControleAutomatico,
Status = Status,
ErroOperacaoLiberada = ErroOperacaoLiberada,
OperacaoLiberacaoDebug = OperacaoLiberacaoDebug,
OperacaoConfigurada = OperacaoConfigurada,
OperacaoLiberada = OperacaoLiberada,
OperacaoIniciada = OperacaoIniciada,

View File

@ -968,12 +968,12 @@ namespace AgroBase.Models.Operacoes
private void AtualizarMovimentacao(OperacaoSensoriamentoConjuntoModel sen)
{
Movimentacao = sen.Movimentacao?.Clone();
Movimentacao = sen?.Movimentacao?.Clone();
}
private void AtualizarDirecional(OperacaoSensoriamentoConjuntoModel sen)
{
Direcional = sen.Direcional?.Clone();
Direcional = sen?.Direcional?.Clone();
}
private void AtualizarGnss(OperacaoSensoriamentoConjuntoModel sen)
@ -1049,8 +1049,8 @@ namespace AgroBase.Models.Operacoes
Imu = Imu?.Clone(),
Atuador = CloneAtuador(Atuador),
Sensoriamento = CloneSensoriamento(Sensoriamento),
Movimentacao = Movimentacao.Clone(),
Direcional = Direcional.Clone(),
Movimentacao = Movimentacao?.Clone(),
Direcional = Direcional?.Clone(),
Bateria = Bateria?.Clone(),
Refrigeracao = Refrigeracao?.Clone(),

View File

@ -27,7 +27,8 @@ namespace AgroBase.Models
{
public class Variaveis
{
public static bool Producao { get; set; } = false;
public static readonly bool IniciarWorkers = true;
public static readonly bool Producao = false;
public static bool DebugMode { get; set; } = true;
public static bool Fechando { get; set; } = false;
@ -57,11 +58,35 @@ namespace AgroBase.Models
public static string CaminhoParametros { get; } = "Parametros/";
public static string CaminhoModelos { get; } = "C:\\AgroBaseModels\\";
public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>();
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel();
public static MqttService MqttServiceLocal { get; private set; }
public static MqttService MqttServiceBaseCritical { get; private set; }
public static MqttService MqttServiceBaseTelemetry { get; private set; }
private static readonly object _opLock = new object();
private static OperacaoModel _op;
public static OperacaoModel OperacaoEmAndamento
{
get
{
lock (_opLock)
return _op;
}
set
{
lock (_opLock)
{
if (ReferenceEquals(_op, value))
return;
_op?.PararTimersSistema();
_op = value;
_op?.IniciarTimersSistema();
}
}
}
/// <summary>
/// Compatibilidade temporária com o restante do projeto.
/// Publicações antigas feitas por MqttServiceBase seguem pelo canal
@ -105,16 +130,11 @@ namespace AgroBase.Models
// return OperacaoEmAndamento.DispSen?.Dados?.LoRaParametrosBase;
// }
//}
public static string FaixaIPwifi { get; set; } = "192.168.100";
public static string FaixaIPethernet { get; set; } = "192.168.105";
public static string IP_Host { get; set; } = FaixaIPwifi + ".105";
public static string NomeRedeWifiEquipamento { get; set; } = "Agrobot";
public static string SenhaRedeWifiEquipamento { get; set; } = "4321agro";
public static bool IsAgroMonitor
public static bool IsAgroBase
{
get
{
return CaminhoSistema.Contains("AgroMonitor");
return CaminhoSistema.Contains("AgroBase");
}
}

View File

@ -208,7 +208,7 @@ namespace AgroBase.Services
// Inicializa o serviço Ethernet com IP e porta específicos
public static async Task<bool> InicializarEthernetService()
{
string ipAddress = Variaveis.OperacaoEmAndamento.DispMvd.Dados.IP_Mov;
string ipAddress = ""; // Variaveis.OperacaoEmAndamento.DispMvd.Dados.IP_Mov;
int port = VariaveisPortas.Ethernet_TCP;
_ethernetService?.Disconnect();

View File

@ -598,7 +598,7 @@ public class EthernetService
_Interface = _Interface.Split('(')[0].Trim();
string gateway = ObterIpGateway(_Interface);
string ipAtual = ObterIpAtual(_Interface);
string ip = Variaveis.IP_Host;
string ip = VariaveisEquipamento.Parametros.rover_ip;
string submask = ObterSubnetMaskAtual(_Interface);
if (fixo)

View File

@ -85,20 +85,11 @@ namespace AgroBase.Services
private static readonly object _workerLock = new object();
private static readonly object _portLifecycleLock = new object();
private static readonly SemaphoreSlim _serialWriteLock =
new SemaphoreSlim(1, 1);
private static readonly SemaphoreSlim _configurationLock =
new SemaphoreSlim(1, 1);
private static readonly SemaphoreSlim _rtcmSignal =
new SemaphoreSlim(0, int.MaxValue);
private static readonly SemaphoreSlim _logSignal =
new SemaphoreSlim(0, int.MaxValue);
private static readonly SemaphoreSlim _localPublishSignal =
new SemaphoreSlim(0, int.MaxValue);
private static readonly SemaphoreSlim _serialWriteLock = new SemaphoreSlim(1, 1);
private static readonly SemaphoreSlim _configurationLock = new SemaphoreSlim(1, 1);
private static readonly SemaphoreSlim _rtcmSignal = new SemaphoreSlim(0, int.MaxValue);
private static readonly SemaphoreSlim _logSignal = new SemaphoreSlim(0, int.MaxValue);
private static readonly SemaphoreSlim _localPublishSignal = new SemaphoreSlim(0, int.MaxValue);
private static CancellationTokenSource _serviceCts;
private static Task _nmeaWorkerTask;
@ -118,20 +109,16 @@ namespace AgroBase.Services
// BUFFERS E FILAS
// ============================================================
private static readonly StringBuilder _nmeaBuffer =
new StringBuilder(8192);
private static readonly StringBuilder _nmeaBuffer = new StringBuilder(8192);
private const int MaxNmeaBufferChars = 64 * 1024;
private static readonly object _nmeaQueueLock = new object();
private static readonly Queue<string> _nmeaQueue =
new Queue<string>();
private static readonly SemaphoreSlim _nmeaSignal =
new SemaphoreSlim(0, int.MaxValue);
private static readonly Queue<string> _nmeaQueue = new Queue<string>();
private static readonly SemaphoreSlim _nmeaSignal = new SemaphoreSlim(0, int.MaxValue);
private const int NmeaQueueCapacity = 512;
private static readonly Queue<RtcmEnvelope> _rtcmQueue =
new Queue<RtcmEnvelope>();
private static readonly Queue<RtcmEnvelope> _rtcmQueue = new Queue<RtcmEnvelope>();
private const int RtcmQueueCapacity = 48;
private const int RtcmMaxAgeMs = 2500;
@ -139,12 +126,10 @@ namespace AgroBase.Services
private static long _rtcmSequence;
private static readonly ConcurrentQueue<string> _gpsLogQueue =
new ConcurrentQueue<string>();
private static readonly ConcurrentQueue<string> _gpsLogQueue = new ConcurrentQueue<string>();
private static readonly object _localPublishLock = new object();
private static readonly Dictionary<string, string> _localLatestPayload =
new Dictionary<string, string>(StringComparer.Ordinal);
private static readonly Dictionary<string, string> _localLatestPayload = new Dictionary<string, string>(StringComparer.Ordinal);
// ============================================================
// MÉTRICAS
@ -291,7 +276,7 @@ namespace AgroBase.Services
if (generation != Interlocked.Read(ref _portGeneration))
return;
if (!Variaveis.IsAgroMonitor && CorrecaoRTK_Ntrip)
if (Variaveis.IsAgroBase && CorrecaoRTK_Ntrip)
await IniciarNtripAsync().ConfigureAwait(false);
}
catch (Exception ex)
@ -366,12 +351,7 @@ namespace AgroBase.Services
).ConfigureAwait(false);
}
private static async Task ConfigurarModuloRover(
string porta_usb = "com3",
string porta_entrada = "com2",
int comprimento_antena = 100,
int tolerancia_antena = 5,
CancellationToken cancellationToken = default(CancellationToken))
private static async Task ConfigurarModuloRover(string porta_usb = "com3", string porta_entrada = "com2", int comprimento_antena = 100, int tolerancia_antena = 5, CancellationToken cancellationToken = default(CancellationToken))
{
await _configurationLock.WaitAsync(cancellationToken)
.ConfigureAwait(false);
@ -464,14 +444,9 @@ namespace AgroBase.Services
}
}
private static async Task ConfigurarModuloBase(
string porta_usb = "com3",
string porta_saida = "com2",
int tempo_fixacao = 60,
CancellationToken cancellationToken = default(CancellationToken))
private static async Task ConfigurarModuloBase(string porta_usb = "com3", string porta_saida = "com2", int tempo_fixacao = 60, CancellationToken cancellationToken = default(CancellationToken))
{
await _configurationLock.WaitAsync(cancellationToken)
.ConfigureAwait(false);
await _configurationLock.WaitAsync(cancellationToken).ConfigureAwait(false);
Interlocked.Increment(ref _configurationRuns);
@ -537,9 +512,7 @@ namespace AgroBase.Services
// RECEPÇÃO SERIAL / NMEA
// ============================================================
private static void PortaGPS_DataReceived(
object sender,
SerialDataReceivedEventArgs e)
private static void PortaGPS_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort porta = sender as SerialPort;
@ -599,8 +572,7 @@ namespace AgroBase.Services
catch (SemaphoreFullException) { }
}
private static async Task NmeaWorkerLoopAsync(
CancellationToken cancellationToken)
private static async Task NmeaWorkerLoopAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
@ -638,8 +610,7 @@ namespace AgroBase.Services
}
}
private static List<string> ExtrairSentencasCompletas(
string recebido)
private static List<string> ExtrairSentencasCompletas(string recebido)
{
var resultado = new List<string>();
@ -1487,14 +1458,9 @@ namespace AgroBase.Services
// RTCM VIA MQTT / FILA DE ESCRITA
// ============================================================
public static void AplicarCorrecaoRTK_Mqtt(
byte[] correcao,
int bytesRead)
public static void AplicarCorrecaoRTK_Mqtt(byte[] correcao, int bytesRead)
{
if (correcao == null ||
bytesRead <= 0 ||
bytesRead > correcao.Length ||
bytesRead > RtcmMaxPayloadBytes)
if (correcao == null || bytesRead <= 0 || bytesRead > correcao.Length || bytesRead > RtcmMaxPayloadBytes)
{
Interlocked.Increment(ref _rtcmDroppedInvalid);
return;
@ -1506,9 +1472,7 @@ namespace AgroBase.Services
EnfileirarRtcm(copia, RtcmSource.Mqtt);
}
private static void EnfileirarRtcm(
byte[] bytes,
RtcmSource source)
private static void EnfileirarRtcm(byte[] bytes, RtcmSource source)
{
EnsureBackgroundWorkersStarted();
@ -1547,8 +1511,7 @@ namespace AgroBase.Services
catch (SemaphoreFullException) { }
}
private static async Task RtcmWriterLoopAsync(
CancellationToken cancellationToken)
private static async Task RtcmWriterLoopAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
@ -1684,8 +1647,7 @@ namespace AgroBase.Services
public static async Task IniciarNtripAsync()
{
if (Variaveis.IsAgroMonitor ||
!CorrecaoRTK_Ntrip)
if (!Variaveis.IsAgroBase || !CorrecaoRTK_Ntrip)
{
return;
}
@ -1756,12 +1718,9 @@ namespace AgroBase.Services
cts.Dispose();
}
private static async Task AplicarCorrecaoRTK_Ntrip(
CancellationToken cancellationToken)
private static async Task AplicarCorrecaoRTK_Ntrip(CancellationToken cancellationToken)
{
if (!Iniciado ||
LoopRTK_Ntrip ||
!APIService.HasInternet)
if (!Iniciado || LoopRTK_Ntrip || !APIService.HasInternet)
{
return;
}
@ -2003,10 +1962,7 @@ namespace AgroBase.Services
}
}
private static async Task<NtripHeaderResult>
ReadNtripHeaderAsync(
NetworkStream stream,
CancellationToken cancellationToken)
private static async Task<NtripHeaderResult> ReadNtripHeaderAsync(NetworkStream stream, CancellationToken cancellationToken)
{
var bytes = new List<byte>(2048);
byte[] buffer = new byte[512];
@ -2112,8 +2068,7 @@ namespace AgroBase.Services
return PenultimaLeitura.Clone();
}
private static bool PossuiHeadingValido(
GPSModel leitura)
private static bool PossuiHeadingValido(GPSModel leitura)
{
if (leitura == null)
return false;
@ -2161,6 +2116,9 @@ namespace AgroBase.Services
public static void AtualizarCoordenadasGPS()
{
if (!Variaveis.IsAgroBase)
return;
var op = Variaveis.OperacaoEmAndamento;
PenultimaLeitura.Ntrip_ativado = UltimaLeitura.Ntrip_ativado;
@ -2173,9 +2131,6 @@ namespace AgroBase.Services
UltimaLeitura.LeverArmFrontal = LeverArm != null ? LeverArm.FrontalTotalCm : 0;
UltimaLeitura.LeverArmLateral = LeverArm != null ? LeverArm.LateralTotalCm : 0;
if (Variaveis.IsAgroMonitor)
return;
UltimasLeituras.Add(UltimaLeitura.Clone());
while (UltimasLeituras.Count > Math.Max(1, TaxaAmostragemHz))
@ -2548,27 +2503,14 @@ namespace AgroBase.Services
UltimaLeitura.AnguloCarroDefinido = anguloFinal;
}
public static double FundirHeadingComMovimento(
double headingDeg,
double angMovDeg,
double distLinearJanela,
double velPercent = 0.0,
bool rtkFix = true,
double angFundidoAnterior = double.NaN,
double alfaLowPass = 0.25)
public static double FundirHeadingComMovimento(double headingDeg, double angMovDeg, double distLinearJanela, double velPercent = 0.0, bool rtkFix = true, double angFundidoAnterior = double.NaN, double alfaLowPass = 0.25)
{
double distMin = 0.03;
double distFull = 0.25;
double pesoMinHeading = 0.30;
double fatorConfMovSemFix = 0.80;
double fd = Smoothstep(
Norm(
distLinearJanela,
distMin,
distFull
)
);
double fd = Smoothstep(Norm(distLinearJanela, distMin, distFull));
double fv =
FuncoesMatematicas.Clamp(
@ -2612,10 +2554,7 @@ namespace AgroBase.Services
return Normalize0To360(angMisto);
}
private static double Norm(
double value,
double min,
double max)
private static double Norm(double value, double min, double max)
{
if (max <= min)
return value >= max ? 1.0 : 0.0;
@ -2639,10 +2578,7 @@ namespace AgroBase.Services
return x * x * (3.0 - 2.0 * x);
}
private static double MisturarAngulosCircular(
double aDeg,
double bDeg,
double pesoA)
private static double MisturarAngulosCircular(double aDeg, double bDeg, double pesoA)
{
double a = aDeg * Math.PI / 180.0;
double b = bDeg * Math.PI / 180.0;
@ -2659,23 +2595,14 @@ namespace AgroBase.Services
180.0 / Math.PI;
}
private static double LowPassAngle0to360(
double atualDeg,
double novoDeg,
double alfa)
private static double LowPassAngle0to360(double atualDeg, double novoDeg, double alfa)
{
double diff =
NormalizeSigned180(
novoDeg - atualDeg
);
double diff = NormalizeSigned180(novoDeg - atualDeg);
return Normalize0To360(
atualDeg + alfa * diff
);
return Normalize0To360(atualDeg + alfa * diff);
}
private static double NormalizeSigned180(
double angDeg)
private static double NormalizeSigned180(double angDeg)
{
angDeg = (angDeg + 180.0) % 360.0;
@ -2685,8 +2612,7 @@ namespace AgroBase.Services
return angDeg - 180.0;
}
private static double Normalize0To360(
double angDeg)
private static double Normalize0To360(double angDeg)
{
angDeg %= 360.0;
@ -2702,7 +2628,7 @@ namespace AgroBase.Services
{
GPSModel posicaoAtual;
if (Variaveis.OperacaoEmAndamento.Simulando)
if (Variaveis.OperacaoEmAndamento?.Simulando == true)
{
lock (_stateLock)
{
@ -2835,8 +2761,7 @@ namespace AgroBase.Services
}
}
private static async Task LogWriterLoopAsync(
CancellationToken cancellationToken)
private static async Task LogWriterLoopAsync(CancellationToken cancellationToken)
{
var lote = new List<string>(300);
@ -3064,8 +2989,7 @@ namespace AgroBase.Services
// MÉTRICAS
// ============================================================
public static GpsTransportMetrics
GetTransportMetrics()
public static GpsTransportMetrics GetTransportMetrics()
{
int queueDepth;
int nmeaQueueDepth;
@ -3236,9 +3160,7 @@ namespace AgroBase.Services
// HELPERS
// ============================================================
private static void WriteSerialUnsafe(
byte[] bytes,
int count)
private static void WriteSerialUnsafe(byte[] bytes, int count)
{
SerialPort porta = PortaGPS;
@ -3265,10 +3187,7 @@ namespace AgroBase.Services
Stopwatch.Frequency;
}
private static string GetField(
string[] fields,
int index,
string fallback = "")
private static string GetField(string[] fields, int index, string fallback = "")
{
return fields != null &&
index >= 0 &&
@ -3289,16 +3208,11 @@ namespace AgroBase.Services
: value;
}
private static bool TryParseDmm(
string raw,
string hemisphere,
int degreeDigits,
out double result)
private static bool TryParseDmm(string raw, string hemisphere, int degreeDigits, out double result)
{
result = 0;
if (string.IsNullOrWhiteSpace(raw) ||
raw.Length <= degreeDigits)
if (string.IsNullOrWhiteSpace(raw) || raw.Length <= degreeDigits)
{
return false;
}
@ -3338,14 +3252,11 @@ namespace AgroBase.Services
!double.IsInfinity(result);
}
private static bool TryParseNmeaTime(
string raw,
out DateTime result)
private static bool TryParseNmeaTime(string raw, out DateTime result)
{
result = default(DateTime);
if (string.IsNullOrWhiteSpace(raw) ||
raw.Length < 6)
if (string.IsNullOrWhiteSpace(raw) || raw.Length < 6)
{
return false;
}
@ -3397,17 +3308,11 @@ namespace AgroBase.Services
}
}
private static bool TryParseRmcDateTime(
string dateRaw,
string timeRaw,
out DateTime result)
private static bool TryParseRmcDateTime(string dateRaw, string timeRaw, out DateTime result)
{
result = default(DateTime);
if (string.IsNullOrWhiteSpace(dateRaw) ||
dateRaw.Length != 6 ||
string.IsNullOrWhiteSpace(timeRaw) ||
timeRaw.Length < 6)
if (string.IsNullOrWhiteSpace(dateRaw) || dateRaw.Length != 6 || string.IsNullOrWhiteSpace(timeRaw) || timeRaw.Length < 6)
{
return false;
}
@ -3595,12 +3500,7 @@ namespace AgroBase.Services
get { return (yFisico + yCampo) * 100.0; }
}
public (double lat, double lon)
FixLeverArmLatLon_Fast(
double latAnt_deg,
double lonAnt_deg,
double headingDeg,
double headingFreq)
public (double lat, double lon) FixLeverArmLatLon_Fast(double latAnt_deg, double lonAnt_deg, double headingDeg, double headingFreq)
{
if (headingFreq < 1)
return (latAnt_deg, lonAnt_deg);
@ -3652,11 +3552,7 @@ namespace AgroBase.Services
);
}
public (double x, double y) GeodeticToENU(
double lat,
double lon,
double lat0,
double lon0)
public (double x, double y) GeodeticToENU(double lat, double lon, double lat0, double lon0)
{
double latR = ToRad(lat);
double lonR = ToRad(lon);

View File

@ -56,7 +56,7 @@ namespace AgroBase.Services
// Inicializa o serviço Ethernet com IP e porta específicos
public static async Task<bool> InicializarEthernetService()
{
string ipAddress = Variaveis.OperacaoEmAndamento.DispMvd.Dados.IP_Dir;
string ipAddress = ""; // Variaveis.OperacaoEmAndamento.DispMvd.Dados.IP_Dir;
int port = VariaveisPortas.Ethernet_TCP;
_ethernetService?.Disconnect();

View File

@ -517,7 +517,7 @@ namespace AgroBase.Services
// Inicializa o serviço Ethernet com IP e porta específicos
public static async Task<bool> InicializarEthernetService()
{
string ipAddress = Variaveis.OperacaoEmAndamento.DispMvd.Dados.IP_Mov;
string ipAddress = ""; // Variaveis.OperacaoEmAndamento.DispMvd.Dados.IP_Mov;
int port = VariaveisPortas.Ethernet_TCP;
_ethernetService?.Disconnect();

View File

@ -95,7 +95,7 @@ namespace AgroBase.Services.Operadores
private static void AtualizarDadosContextoLocal()
{
var op = Variaveis.OperacaoEmAndamento;
if (op.Sensoriamento == null) return;
if (op?.Sensoriamento == null) return;
try
{
@ -130,7 +130,7 @@ namespace AgroBase.Services.Operadores
AtualizarDadosModulos();
AtualizarDadosControleOperacao();
var _Sensoriamento = op.Sensoriamento;
var _Sensoriamento = op?.Sensoriamento;
if (_Sensoriamento == null)
{
@ -378,7 +378,7 @@ namespace AgroBase.Services.Operadores
{
try
{
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
var pControle = Variaveis.OperacaoEmAndamento?.Parametros?.Controle;
if (pControle == null)
return;
RedisService.AtualizarCampos(
@ -414,9 +414,9 @@ namespace AgroBase.Services.Operadores
var op = Variaveis.OperacaoEmAndamento;
try
{
if (op.DispMvd == null) return;
if (op.DispAtu == null) return;
if (op.DispSen == null) return;
if (op?.DispMvd == null) return;
if (op?.DispAtu == null) return;
if (op?.DispSen == null) return;
var _Sensoriamento = op.Sensoriamento;
var agora_dt = DateTime.Now;

View File

@ -420,13 +420,14 @@ namespace AgroBase.Services.Operadores
if (op.Parametros.Controle.PulverizadorAutomatico)
{
if (controle.Bicos != null && controle.Bicos.Any(x => x.ComandoAtuar))
var bicos = op.DispAtu?.Dados?.BicosPulverizadores ?? new List<Models.Modules.AtuadorBicoModel>();
if (bicos != null && bicos.Any(x => x.ComandoAtuar))
{
controle.Bicos.ForEach(x => x.ComandoAtuar = false);
bicos.ForEach(x => x.ComandoAtuar = false);
RedisService.AtualizarCampos(
CtxKey.DadosControle,
("controle_bicos", controle.Bicos.ToDictionary(x => x.Posicao - 1, x => x.ComandoAtuar))
("controle_bicos", bicos.ToDictionary(x => x.Posicao - 1, x => x.ComandoAtuar))
);
}
}

View File

@ -148,7 +148,7 @@ namespace AgroBase.Services.Operadores
{
AtualizarImu();
DadosLeitura.Status = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorSaude?.ModulosSaude?.FirstOrDefault(x => x.modulo == Enums.T_Code.Snr)?.status ?? Enums.StatusModulo.Desconectado;
DadosLeitura.Status = Variaveis.OperacaoEmAndamento?.Sensoriamento?.OperadorSaude?.ModulosSaude?.FirstOrDefault(x => x.modulo == Enums.T_Code.Snr)?.status ?? Enums.StatusModulo.Desconectado;
string json = RedisService.Get(CtxKey.DadosVisualWorker);

View File

@ -67,7 +67,7 @@ namespace AgroBase.Services.Operadores
bool comandoMudou = false;
var _Controle = op.Controle;
foreach (var bico in _Controle.Bicos ?? new List<Models.Modules.AtuadorBicoModel>())
foreach (var bico in op.DispAtu?.Dados.BicosPulverizadores ?? new List<Models.Modules.AtuadorBicoModel>())
{
novoComando.TryGetValue(bico.Posicao, out bool atuado);
if (!(op.DispAtu?.Dados?.ContadorCarga?.PulverizadorLiberado ?? false)) atuado = false;

View File

@ -19,6 +19,13 @@ namespace AgroBase.Services
{
_redis = ConnectionMultiplexer.Connect(conexao);
_db = _redis.GetDatabase();
AtualizarCampos(
CtxKey.DadosOperacao,
("motivo_nao_liberado", "Iniciando..."),
("liberado", false),
("configurado", false)
);
}
public static string ModKey(T_Code dispositivo)
@ -159,13 +166,15 @@ namespace AgroBase.Services
{
if (!(Variaveis.OperacaoEmAndamento?.Sensoriamento?.OperadorSaude?.ModulosSaude?.Any() ?? false)) return;
var saude = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorSaude?.ModulosSaude;
var saude = Variaveis.OperacaoEmAndamento?.Sensoriamento?.OperadorSaude?.ModulosSaude;
AtualizarCampos(
CtxKey.DadosOperacao,
("motivo_nao_liberado", "Sem comunicação com o núcleo de processamento central"),
("liberado", false),
("configurado", false)
);
Variaveis.OperacaoEmAndamento.Sensoriamento.Operacao.OperacaoLiberada = false;
foreach (var Mod in saude)
{
Mod.conectado = false;

View File

@ -522,8 +522,7 @@ namespace AgroBase.Services
);
}
public static async Task RealizarVarreduraPortasUSB(
CancellationToken cancellationToken)
public static async Task RealizarVarreduraPortasUSB(CancellationToken cancellationToken)
{
if (Variaveis.Fechando ||
Volatile.Read(ref _isClosing) == 1)
@ -643,9 +642,7 @@ namespace AgroBase.Services
}
}
private static async Task ExecutarVarreduraAsync(
long generation,
CancellationToken cancellationToken)
private static async Task ExecutarVarreduraAsync(long generation, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@ -654,15 +651,12 @@ namespace AgroBase.Services
* consulta CAN. Assim a descoberta não precisa esperar
* uma segunda varredura para encontrar os módulos.
*/
if (!Variaveis.IsAgroMonitor)
if (Variaveis.IsAgroBase)
{
await AtualizarDispositivosAsync(
cancellationToken
).ConfigureAwait(false);
await AtualizarDispositivosAsync(cancellationToken).ConfigureAwait(false);
}
List<DispositivoDetalhesModel> mappedSnapshot =
GetDispositivosMapeadosSnapshot();
List<DispositivoDetalhesModel> mappedSnapshot = GetDispositivosMapeadosSnapshot();
string[] ports = SerialPort.GetPortNames()
.Where(x => !string.IsNullOrWhiteSpace(x))
@ -670,10 +664,7 @@ namespace AgroBase.Services
.OrderBy(PortSortKey)
.ToArray();
Interlocked.Add(
ref _portsEnumerated,
ports.Length
);
Interlocked.Add(ref _portsEnumerated, ports.Length);
HashSet<string> mappedComPorts =
new HashSet<string>(
@ -696,19 +687,15 @@ namespace AgroBase.Services
{
cancellationToken.ThrowIfCancellationRequested();
if (generation !=
Interlocked.Read(ref _scanGeneration))
if (generation != Interlocked.Read(ref _scanGeneration))
{
return;
}
await ProbePortAsync(
portName,
cancellationToken
).ConfigureAwait(false);
await ProbePortAsync(portName, cancellationToken).ConfigureAwait(false);
}
if (!Variaveis.IsAgroMonitor)
if (Variaveis.IsAgroBase)
{
ProcurarDispositivosUSB();
ProcurarDispositivosEthernet();
@ -718,30 +705,18 @@ namespace AgroBase.Services
* Se estiver em Ethernet, Inicializar() resolve o transporte
* sem depender de uma porta COM candidata.
*/
if (CanManager.TipoServico !=
CanServiceTipo.Serial ||
CanManager.CanService.Iniciado)
if (CanManager.TipoServico != CanServiceTipo.Serial || CanManager.CanService.Iniciado)
{
await ProcurarDispositivosCAN(
null,
cancellationToken
).ConfigureAwait(false);
await ProcurarDispositivosCAN(null, cancellationToken).ConfigureAwait(false);
}
}
await RemoverDispositivosAusentesAsync(
ports,
cancellationToken
).ConfigureAwait(false);
await RemoverDispositivosAusentesAsync(ports, cancellationToken).ConfigureAwait(false);
await AtualizarDispositivosAsync(
cancellationToken
).ConfigureAwait(false);
await AtualizarDispositivosAsync(cancellationToken).ConfigureAwait(false);
}
private static async Task ProbePortAsync(
string portName,
CancellationToken cancellationToken)
private static async Task ProbePortAsync(string portName, CancellationToken cancellationToken)
{
Interlocked.Increment(ref _portsProbed);
@ -757,13 +732,9 @@ namespace AgroBase.Services
{
candidate = CriarPortaCandidata(portName);
if (Variaveis.IsAgroMonitor &&
!LoRaBaseService.Iniciado)
if (!Variaveis.IsAgroBase && !LoRaBaseService.Iniciado)
{
if (await ProcurarDispositivoLoRa(
candidate,
cancellationToken)
.ConfigureAwait(false))
if (await ProcurarDispositivoLoRa(candidate, cancellationToken).ConfigureAwait(false))
{
claimed = true;
Interlocked.Increment(ref _loraFound);
@ -773,10 +744,7 @@ namespace AgroBase.Services
if (!GPSService.Iniciado)
{
if (await ProcurarDispositivoGPS(
candidate,
cancellationToken)
.ConfigureAwait(false))
if (await ProcurarDispositivoGPS(candidate, cancellationToken).ConfigureAwait(false))
{
Interlocked.Increment(ref _gpsFound);
@ -788,22 +756,15 @@ namespace AgroBase.Services
}
}
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
return;
if (CanManager.TipoServico ==
CanServiceTipo.Serial &&
!CanManager.CanService.Iniciado)
if (CanManager.TipoServico == CanServiceTipo.Serial && !CanManager.CanService.Iniciado)
{
if (await ProcurarDispositivosCAN(
candidate,
cancellationToken)
.ConfigureAwait(false))
if (await ProcurarDispositivosCAN(candidate, cancellationToken).ConfigureAwait(false))
{
claimed = true;
Interlocked.Increment(
ref _canAdapterFound
);
Interlocked.Increment(ref _canAdapterFound);
AtualizarConsole(
"Dispositivo encontrado no barramento CAN"
@ -954,7 +915,7 @@ namespace AgroBase.Services
private static void ProcurarDispositivosUSB()
{
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
return;
if (GeneralJoystick.JoystickConectado == null)
@ -1746,7 +1707,7 @@ namespace AgroBase.Services
{
Variaveis.MostrarLog(message);
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
return;
_pendingUiMessage = message;

View File

@ -1163,20 +1163,16 @@ namespace AgroBase.Services
await Task.CompletedTask;
}
private static void AtualizarConsole(
string msg,
int val)
private static void AtualizarConsole(string msg, int val)
{
Console.WriteLine(msg);
try
{
if (Variaveis.IsAgroMonitor)
if (!Variaveis.IsAgroBase)
return;
if (frmInstancial.frmPrincipal == null ||
!frmInstancial.frmPrincipal.Created ||
frmInstancial.frmPrincipal.IsDisposed)
if (frmInstancial.frmPrincipal == null || !frmInstancial.frmPrincipal.Created || frmInstancial.frmPrincipal.IsDisposed)
{
return;
}
@ -1221,8 +1217,7 @@ namespace AgroBase.Services
catch { }
}
private static void AtualizarProgressoSeguro(
double progresso)
private static void AtualizarProgressoSeguro(double progresso)
{
try
{

View File

@ -17,6 +17,10 @@ namespace AgroBase.Services
public static bool Conectando { get; set; } = false;
private static string InterfaceAtual { get; set; } = "";
private static string NomeRedeWifiEquipamento = "";
private static string IP_Host = "";
public static void IniciarRotinas()
{
tmrMonitoramento?.Dispose();
@ -26,7 +30,7 @@ namespace AgroBase.Services
private static async Task tmrMonitoramento_Tick()
{
string nomeRede = Variaveis.NomeRedeWifiEquipamento;
string nomeRede = NomeRedeWifiEquipamento;
if (!PerfilExiste)
{
@ -63,7 +67,7 @@ namespace AgroBase.Services
}
var ip = EthernetService.ObterIpAtual(InterfaceAtual);
if (!string.IsNullOrEmpty(ip) && ip != Variaveis.IP_Host)
if (!string.IsNullOrEmpty(ip) && ip != IP_Host)
{
bool configurado = await EthernetService.ConfigurarIP(true, false);
Variaveis.IniciarMQTT();
@ -112,7 +116,7 @@ namespace AgroBase.Services
if (!PerfilExiste)
{
string nomeRede = Variaveis.NomeRedeWifiEquipamento;
string nomeRede = NomeRedeWifiEquipamento;
string xmlPerfil = $@"<?xml version=""1.0""?>
<WLANProfile xmlns=""http://www.microsoft.com/networking/WLAN/profile/v1"">
<name>{nomeRede}</name>
@ -267,7 +271,7 @@ namespace AgroBase.Services
await Task.Delay(3000); // tempo para o sistema conectar de fato
string ssidDepois = await ObterNomeRedeWifiAtual();
WifiConectado = ssidDepois == Variaveis.NomeRedeWifiEquipamento;
WifiConectado = ssidDepois == NomeRedeWifiEquipamento;
//WifiConectado = output.Contains("successfully");

View File

@ -127,6 +127,7 @@ WEED_DEFAULT_CONFIG = {
# Gate global: só libera bicos quando existe alvo suficiente no frame.
"usar_radar_global_gate": True,
"inverter_ordem_bicos": True,
"inverter_sentido_vertical_bicos": True,
# Histerese global da fração de alvo no frame completo.
"min_frac_erva_global_on": 0.0020,

View File

@ -71,9 +71,6 @@ class WeedDetector:
self.config.get("inverter_ordem_bicos", False)
)
# TESTE INLINE:
# False = lógica atual: erva caminha topo -> pé
# True = lógica invertida: erva caminha pé -> topo
self.inverter_sentido_vertical_bicos = bool(
self.config.get("inverter_sentido_vertical_bicos", True)
)