diff --git a/AgroBase/AgroBase/Forms/Atuador/frmAtuCalibragem.cs b/AgroBase/AgroBase/Forms/Atuador/frmAtuCalibragem.cs index fe7242d6c..a3b6ddba7 100644 --- a/AgroBase/AgroBase/Forms/Atuador/frmAtuCalibragem.cs +++ b/AgroBase/AgroBase/Forms/Atuador/frmAtuCalibragem.cs @@ -138,8 +138,8 @@ namespace AgroBase.Forms.Atuador var BombaPressurizadora = DispAtu.Dados.BombasPressurizadoras.FirstOrDefault(); grdSensoriamento.Rows[0].Cells[1].Value = BombaPressurizadora.Inicializado; grdSensoriamento.Rows[1].Cells[1].Value = BombaPressurizadora.ComandoAtuar; - grdSensoriamento.Rows[2].Cells[1].Value = BombaPressurizadora.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; - grdSensoriamento.Rows[3].Cells[1].Value = BombaPressurizadora.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia).atual.valor; + grdSensoriamento.Rows[2].Cells[1].Value = BombaPressurizadora._EstadoLeitura; + grdSensoriamento.Rows[3].Cells[1].Value = BombaPressurizadora._Potencia; grdSensoriamento.Rows[4].Cells[1].Value = DispAtu.Dados.PressaoLinha.ToString("0.00000"); grdSensoriamento.Rows[5].Cells[1].Value = DispAtu.Dados.PressaoLinhaCalc.ToString("0.00000"); grdSensoriamento.Rows[6].Cells[1].Value = DispAtu.Dados.VazaoFluxoMLpSMedia.ToString("0.00000"); @@ -178,7 +178,7 @@ namespace AgroBase.Forms.Atuador int circleY = pnl.Height / 4; // Posição Y do círculo (mais próximo ao topo) // Desenhar o círculo - if (DispAtu.Dados.BicosPulverizadores.First(x => x.ID == ID).ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor) + if (DispAtu.Dados.BicosPulverizadores.First(x => x.ID == ID)._EstadoLeitura == Estado.Ligado) g.FillEllipse(Brushes.Green, circleX, circleY, circleDiameter, circleDiameter); // LED aceso (círculo preenchido) else g.DrawEllipse(Pens.Black, circleX, circleY, circleDiameter, circleDiameter); // LED apagado (círculo vazio) diff --git a/AgroBase/AgroBase/Forms/IHM/frmDiagnosticos.cs b/AgroBase/AgroBase/Forms/IHM/frmDiagnosticos.cs index 1292d0ff0..4c716fc0c 100644 --- a/AgroBase/AgroBase/Forms/IHM/frmDiagnosticos.cs +++ b/AgroBase/AgroBase/Forms/IHM/frmDiagnosticos.cs @@ -478,42 +478,42 @@ namespace AgroBase.Forms.IHM double Fluxo = FluxoInicializado ? Dispositivo.Dados.VazaoFluxoMLpSInstantanea : -1; idx = PreencheDadosLinha(grid, Testes, idx, Fluxo); - bool statusB01_1 = B01Inicializado && B01.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB01_1 = B01Inicializado && B01._EstadoLeitura == Estado.Ligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB01_1 ? 1 : -1); await EnviarComandoBico(B01, false, 1000); - bool statusB01_0 = B01Inicializado && !B01.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB01_0 = B01Inicializado && B01._EstadoLeitura == Estado.Desligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB01_0 ? 0 : -1); await EnviarComandoBico(B02, true, 1000); - bool statusB02_1 = B02Inicializado && B02.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB02_1 = B02Inicializado && B02._EstadoLeitura == Estado.Ligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB02_1 ? 1 : -1); await EnviarComandoBico(B02, false, 1000); - bool statusB02_0 = B02Inicializado && !B02.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB02_0 = B02Inicializado && B02._EstadoLeitura == Estado.Desligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB02_0 ? 0 : -1); await EnviarComandoBico(B03, true, 1000); - bool statusB03_1 = B03Inicializado && B03.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB03_1 = B03Inicializado && B03._EstadoLeitura == Estado.Ligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB03_1 ? 1 : -1); await EnviarComandoBico(B03, false, 1000); - bool statusB03_0 = B03Inicializado && !B03.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB03_0 = B03Inicializado && B03._EstadoLeitura == Estado.Desligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB03_0 ? 0 : -1); await EnviarComandoBico(B04, true, 1000); - bool statusB04_1 = B04Inicializado && B04.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB04_1 = B04Inicializado && B04._EstadoLeitura == Estado.Ligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB04_1 ? 1 : -1); await EnviarComandoBico(B04, false, 1000); - bool statusB04_0 = B04Inicializado && B04.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + bool statusB04_0 = B04Inicializado && B04._EstadoLeitura == Estado.Desligado; idx = PreencheDadosLinha(grid, Testes, idx, statusB04_0 ? 0 : -1); @@ -1765,7 +1765,7 @@ namespace AgroBase.Forms.IHM await EnviarComandoRele(Dispositivo, Rele, true, 1000); } - Estado Status = Rele.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + Estado Status = Rele._EstadoLeitura; idx = PreencheDadosLinha(grid, Testes, idx, Iniciado && Status == Estado.Ligado ? 1 : -1); if (Iniciado) @@ -1773,7 +1773,7 @@ namespace AgroBase.Forms.IHM await EnviarComandoRele(Dispositivo, Rele, false, 1000); } - Status = Rele.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor; + Status = Rele._EstadoLeitura; idx = PreencheDadosLinha(grid, Testes, idx, Iniciado && Status == Estado.Desligado ? 0 : -1); } diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs index e9e34b992..4f1e44c6f 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs @@ -539,7 +539,7 @@ namespace AgroBase.Forms.Operacoes gridDados.Rows[19].Cells[1].Value = (_Barramentos.FirstOrDefault(x => x.ID == "AB24V").Tensao).ToString("0.00"); gridDados.Rows[20].Cells[1].Value = (_Barramentos.FirstOrDefault(x => x.ID == "AB24V").Corrente).ToString("0.00"); gridDados.Rows[21].Cells[1].Value = _Sensoriamento.Atuador.PercentualReservatorio.ToString("0.00"); - gridDados.Rows[22].Cells[1].Value = _Sensoriamento.Atuador.VolumeReservatorio.ToString("0.000"); + gridDados.Rows[22].Cells[1].Value = $"{_Sensoriamento.Atuador.VolumeReservatorio:0.000} ({Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ContadorCarga?.MassaAtual_Kg_Calc ?? 0:0.000} Kg)"; gridDados.Rows[23].Cells[1].Value = _Sensoriamento.Atuador.LPorMetro.ToString("0.000"); gridDados.Rows[24].Cells[1].Value = _Sensoriamento.Atuador.LPorMinuto.ToString("0.000"); gridDados.Rows[25].Cells[1].Value = TimeSpan.FromMinutes(_Sensoriamento.Atuador.TempoEstimadoRestanteMinutos).ToString(@"hh\:mm\:ss"); @@ -547,7 +547,7 @@ namespace AgroBase.Forms.Operacoes gridDados.Rows[27].Cells[1].Value = _Sensoriamento.Atuador.PressaoLinha.ToString("0.00"); gridDados.Rows[28].Cells[1].Value = _Sensoriamento.Atuador.LeituraPotenciaBomba.ToString("0.00"); gridDados.Rows[29].Cells[1].Value = _Sensoriamento.Atuador.VazaoInstantanea.ToString("0.00"); - gridDados.Rows[30].Cells[1].Value = _Sensoriamento.Atuador.VazaoMedia.ToString("0.00"); + gridDados.Rows[30].Cells[1].Value = $"{_Sensoriamento.Atuador.VazaoMedia:0.000} ({Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.VazaoFluxoMLpSInstantaneaCalc:0.000})"; gridDados.Rows[31].Cells[1].Value = _Sensoriamento.Atuador.VolumeVazaoMl.ToString("0.00"); gridDados.Rows[32].Cells[1].Value = _Sensoriamento.Atuador.AnguloBarraEsquerda.ToString("0.00"); gridDados.Rows[33].Cells[1].Value = _Sensoriamento.Atuador.AnguloBarraDireita.ToString("0.00"); @@ -660,7 +660,7 @@ namespace AgroBase.Forms.Operacoes { var Atuador = Variaveis.OperacaoEmAndamento.DispAtu.Dados; - bool ligado = Atuador.BombasPressurizadoras.FirstOrDefault()?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor > 0; + bool ligado = Atuador.BombasPressurizadoras.FirstOrDefault()?._Potencia > 0; AtuadorFuncoesGerais.DesenharAtuadores( pnlAtuadores, e, @@ -673,7 +673,7 @@ namespace AgroBase.Forms.Operacoes Inicializado = x.Inicializado, MediaNivelFluxo = x.MediaNivelFluxo, Posicao = x.Posicao, - StatusBico = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor == Estado.Ligado, + StatusBico = x._EstadoLeitura == Estado.Ligado, TempoAtuado = x.TempoAtuado, }).ToList(), ligado, diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs index 129c1f56b..91316b464 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs @@ -178,9 +178,9 @@ namespace AgroBase.Forms.Operacoes Inicializado = x.Inicializado, MediaNivelFluxo = x.MediaNivelFluxo, Posicao = x.Posicao, - StatusBico = x.ValoresLeituras.FirstOrDefault(y => y.funcao == FuncoesPinout.EstadoLeitura).atual.valor ?? false, + StatusBico = x._EstadoLeitura == Enums.Estado.Ligado, TempoAtuado = x.TempoAtuado, - }).ToList(), Atuador.BombasPressurizadoras.FirstOrDefault().ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0 > 0, Atuador.PressaoLinha, Atuador.TempoAtuado); + }).ToList(), Atuador.BombasPressurizadoras.FirstOrDefault()._Potencia > 0, Atuador.PressaoLinha, Atuador.TempoAtuado); } private void pnlCaminho_Paint(object sender, PaintEventArgs e) diff --git a/AgroBase/AgroBase/Models/Enums.cs b/AgroBase/AgroBase/Models/Enums.cs index c2e6967fd..7cdd81485 100644 --- a/AgroBase/AgroBase/Models/Enums.cs +++ b/AgroBase/AgroBase/Models/Enums.cs @@ -134,6 +134,7 @@ sIUV = 31, sQAR = 32, sCHV = 33, + sSRV = 34, } public enum BotoesJoystick diff --git a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs index 86dad763b..4157d6c0f 100644 --- a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs +++ b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs @@ -59,6 +59,7 @@ namespace AgroBase.Models.Modules public List BicosPulverizadores { get; set; } public List BombasPressurizadoras { get; set; } public List Sensores { get; set; } + public List Servos { get; set; } public string ScriptDeteccaoErvas { get; set; } = PythonService.ScriptWeedDetector; public AsyncTaskTimerModel tmrRegistrador; @@ -95,14 +96,29 @@ namespace AgroBase.Models.Modules public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida); #region VAZAO + private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN"); public double VolumeVazaoAferido { get; set; } = 0; public double _FluxoMlRef { get; set; } = 600; public double _FluxoPulsoRef { get; set; } = 538; - public double VazaoFluxoMLpSInstantanea + public double VazaoFluxoMLpSInstantanea => SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0; + public double VazaoFluxoMLpSInstantaneaCalc { get { - return Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX)?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0; + int pulsos = SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0; + int periodo = SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0; + if (pulsos <= 0 || periodo <= 0) return 0.0; + + double frequencia = (double)pulsos / (double)periodo * 1000.0; // Hz + + // Equação do fabricante: F = 8.1*q - 3 (q em L/min) + double q_L_min = (frequencia + 3.0) / 8.1; + // Limites físicos do sensor (do próprio anúncio): 0.3–10 L/min + if (q_L_min < 0) q_L_min = 0; // evita negativo perto do zero + if (q_L_min > 10.0) q_L_min = 10.0; // opcional: clamp no máximo + // Converte para mL/s + double q_mL_s = q_L_min * (1000.0 / 60.0); + return q_mL_s; } } private double _somaVazao; // Acumula a soma da vazão para calcular a média @@ -139,7 +155,8 @@ namespace AgroBase.Models.Modules } public void AtualizaPercentualErvas() { - double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.TempoDecorridoSeg * 1000.0; + //double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.TempoDecorridoSeg * 1000.0; + double tempoTotalOperacao = (Variaveis.OperacaoEmAndamento.Parametros?.DadosLeitura?.Movimentacao?.TempoMovimentoSegs ?? 0) * 1000.0; if (tempoTotalOperacao > 0) { @@ -189,26 +206,24 @@ namespace AgroBase.Models.Modules #endregion #region PRESSAO - public double _PressaoVmin { get; set; } = 0.0; - public double _PressaoVmax { get; set; } = 4.5; - public double _PressaoMax { get; set; } = 174.045; // 1,2 MPa - public double PressaoLinha + private SensorModel SensorPressaoLinha { get { - return Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS)?.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Pressao)?.atual?.valor ?? 0; + return Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS && x.ID == "PRSLN"); } } + public double _PressaoVmin { get; set; } = 0.0; + public double _PressaoVmax { get; set; } = 4.5; + public double _PressaoMax { get; set; } = 174.045; // 1,2 MPa + public double PressaoLinha => SensorPressaoLinha?.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Pressao)?.atual?.valor ?? 0; public double PressaoLinhaCalc { get { - //double _LeituraPressao = ((FirmwareSensorPressao)Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS)?.Leitura)?.Leitura ?? 0; - double _LeituraPressao = 0; + double _LeituraPressao = SensorPressaoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0; double tensao = FuncoesMatematicas.Map(_LeituraPressao, 0, 4095, 0, 3300) / 1000.0; - double pressao = FuncoesMatematicas.Map(tensao, _PressaoVmin, _PressaoVmax, 0, _PressaoMax); - return pressao; } } @@ -224,7 +239,7 @@ namespace AgroBase.Models.Modules _EnderecoCAN_Rx = 0x12, _TaxaAmostragem = 1000, RequisitarDados = true, - // 71 ~ 74 + // 71 ~ 73 BicosPulverizadores = new List(), // 51 ~ 51 BombasPressurizadoras = new List() @@ -304,10 +319,22 @@ namespace AgroBase.Models.Modules indice = 0, }, new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.QtdPulsos, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.Periodo, + posicao = CanMessagePosicaoDados.Dados1, + indice = 1, + }, + new SensorValoresLeituraModel() { funcao = FuncoesPinout.Fluxo, posicao = CanMessagePosicaoDados.Dados1, - indice = 0, + indice = 2, analise_health = true, maximo = 20, minimo = 0, @@ -350,9 +377,15 @@ namespace AgroBase.Models.Modules }, new SensorValoresLeituraModel() { - funcao = FuncoesPinout.Massa, + funcao = FuncoesPinout.LeituraBruta, posicao = CanMessagePosicaoDados.Dados1, indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.Massa, + posicao = CanMessagePosicaoDados.Dados1, + indice = 1, analise_health = true, maximo = 35, minimo = 0, @@ -410,9 +443,15 @@ namespace AgroBase.Models.Modules }, new SensorValoresLeituraModel() { - funcao = FuncoesPinout.Pressao, + funcao = FuncoesPinout.LeituraBruta, posicao = CanMessagePosicaoDados.Dados1, indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.Pressao, + posicao = CanMessagePosicaoDados.Dados1, + indice = 1, analise_health = true, maximo = 120, minimo = 0, @@ -587,6 +626,103 @@ namespace AgroBase.Models.Modules } }, }, + // 91 ~ 93 + Servos = new List() + { + new SensorServoModel() + { + ID = "SRVB1", + ID_Num = 91, + Descricao = "Articulaccao Bico 01", + Componente = S_Code.sSRV, + Controlar = true, + Mandatorio = false, + Funcoes = new List() + { + FuncoesPinout.Servo, + }, + _AnguloControle = 90, + Incremental = true, + ValoresLeituras = new List() + { + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.Iniciado, + posicao = CanMessagePosicaoDados.Status, + indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.ServoAnguloLeitura, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + analise_health = true + }, + } + }, + new SensorServoModel() + { + ID = "SRVB2", + ID_Num = 92, + Descricao = "Articulaccao Bico 02", + Componente = S_Code.sSRV, + Controlar = true, + Mandatorio = false, + Funcoes = new List() + { + FuncoesPinout.Servo, + }, + _AnguloControle = 90, + Incremental = true, + ValoresLeituras = new List() + { + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.Iniciado, + posicao = CanMessagePosicaoDados.Status, + indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.ServoAnguloLeitura, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + analise_health = true + }, + } + }, + new SensorServoModel() + { + ID = "SRVB3", + ID_Num = 93, + Descricao = "Articulaccao Bico 03", + Componente = S_Code.sSRV, + Controlar = true, + Mandatorio = false, + Funcoes = new List() + { + FuncoesPinout.Servo, + }, + _AnguloControle = 90, + Incremental = true, + ValoresLeituras = new List() + { + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.Iniciado, + posicao = CanMessagePosicaoDados.Status, + indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.ServoAnguloLeitura, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + analise_health = true + }, + } + }, + }, }; for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdBicos; i++) { @@ -595,6 +731,7 @@ namespace AgroBase.Models.Modules { ID = "B" + posicao.ToString("00"), ID_Num = 70 + posicao, + Servo_ID_Num = 90 + posicao, Componente = S_Code.sBIC, Posicao = posicao, Atuacoes = 0, @@ -624,6 +761,12 @@ namespace AgroBase.Models.Modules funcao = FuncoesPinout.EstadoLeitura, posicao = CanMessagePosicaoDados.Dados1, indice = 0, + }, + new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.ServoAnguloLeitura, + posicao = CanMessagePosicaoDados.Dados1, + indice = 1, } } }); @@ -746,6 +889,10 @@ namespace AgroBase.Models.Modules var sensoresConfig = SensoresConfig(Conectar, configurarTodos); config.AddRange(sensoresConfig); + // Adicionar configurações dos Servos + var servosConfig = ServosConfig(Conectar, configurarTodos); + config.AddRange(servosConfig); + // Adicionar configurações dos Bicos var bicosConfig = BicosConfig(Conectar, configurarTodos); config.AddRange(bicosConfig); @@ -834,6 +981,27 @@ namespace AgroBase.Models.Modules return config; } + private List<(int, CanMessagePosicaoDados, byte[])> ServosConfig(bool Conectar, bool ConfigurarTodos) + { + var config = new List<(int, CanMessagePosicaoDados, byte[])>(); + + foreach (var servo in Servos.Where(x => (x.Controlar && (ConfigurarTodos ? true : x.Inicializado != Conectar)) || (!x.Controlar && x.Inicializado))) + { + if (!servo.Controlar && servo.Inicializado) + { + Conectar = false; + } + (CanMessagePosicaoDados posicao, var payload) = servo.ProtocoloConfiguracao(Pinout, Conectar); + if (payload != null) + { + config.Add((servo.ID_Num, posicao, payload)); + } + } + + return config; + } + + public void IniciarRegistrador() { if (!(tmrRegistrador?.IsRunning ?? false)) @@ -885,53 +1053,13 @@ namespace AgroBase.Models.Modules AtualizaComponentesIniciados(); } - public (bool, List) StatusModulosATU() - { - var Bicos = BicosPulverizadores.Where(x => x.Comandar).ToList(); - var BicosComFalha = Bicos.Where(x => !x.Liberado).ToList(); - bool _bicosOperantes = !BicosComFalha.Any(); - - var _bomba = BombasPressurizadoras.FirstOrDefault(); - var _sensorFluxo = Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX); - bool _sensorFluxoOperante = !_sensorFluxo?.Liberado ?? false; - var _sensorMassa = Sensores.FirstOrDefault(x => x.Componente == S_Code.sMAS); - bool _sensorMassaOperante = !_sensorMassa?.Liberado ?? false; - var _sensorPressao = Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS); - bool _sensorPressaoOperante = !_sensorPressao?.Liberado ?? false; - - List ModsComFalha = BicosComFalha.Select(x => x.ID).ToList(); - - bool _bombaOperante = _bomba?.Liberado ?? false; - - if (!_bombaOperante) - { - ModsComFalha.Add(_bomba?.ID); - } - if (!_sensorFluxoOperante) - { - ModsComFalha.Add(_sensorFluxo.ID); - } - if (!_sensorMassaOperante) - { - ModsComFalha.Add(_sensorMassa.ID); - } - if (!_sensorPressaoOperante) - { - ModsComFalha.Add(_sensorPressao.ID); - } - - bool _atuadorOperante = _bombaOperante && _bicosOperantes && _sensorPressaoOperante && _sensorMassaOperante && _sensorFluxoOperante; - - return (_atuadorOperante, ModsComFalha); - } - private void VerificaControleLeitura() { if (true) // !frmDiagnosticos.Diagnosticando { foreach (var bico in BicosPulverizadores.Where(x => x.Comandar && x.Inicializado)) { - Estado leituraEstado = (Estado?)(bico.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor) ?? Estado.Desligado; + Estado leituraEstado = bico._EstadoLeitura; Estado comandoEstado = bico.ComandoAtuar ? Estado.Ligado : Estado.Desligado; if (leituraEstado != comandoEstado) { @@ -942,7 +1070,7 @@ namespace AgroBase.Models.Modules var bomba = BombasPressurizadoras.FirstOrDefault(x => x.Comandar && x.Inicializado); if (bomba != null) { - bool leituraEstado = (bomba.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0) > 0; + bool leituraEstado = bomba._Potencia > 0; // Desliga a bomba caso esteja ligada e o nivel de herbicida caiu if (ContadorCarga.PercentualAtual < VariaveisEquipamento.PercentualReservatorioMin && leituraEstado == true) @@ -960,6 +1088,14 @@ namespace AgroBase.Models.Modules GeneralJoystick.EnviarComandoAtuador(bomba.Componente, bomba.ID, Status: bomba.ComandoAtuar); } } + + foreach (var servo in Servos.Where(x => x.Controlar && x.Inicializado)) + { + if (servo._AnguloLeiutra != servo._AnguloControle) + { + GeneralJoystick.EnviarComandoSensoriamento(S_Code.sFRO, servo.ID, servo._AnguloControle); + } + } } } @@ -983,6 +1119,10 @@ namespace AgroBase.Models.Modules { sensor.Inicializado = false; } + foreach (var servo in Servos.Where(x => x.Inicializado && x.UltimaLeitura.AddMilliseconds(TempoLimiteConexao) < Agora)) + { + servo.Inicializado = false; + } } @@ -1126,6 +1266,7 @@ namespace AgroBase.Models.Modules public int Posicao { get; set; } public S_Code Componente { get; set; } = S_Code.sBIC; public bool AtuacaoNivelAlto { get; set; } + public int Servo_ID_Num { get; set; } public double AnguloControle { get; set; } public double AnguloAbertura { get; set; } private bool _atuado; @@ -1162,7 +1303,7 @@ namespace AgroBase.Models.Modules } } public List ValoresLeituras { get; set; } - + public Estado _EstadoLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar) @@ -1174,6 +1315,7 @@ namespace AgroBase.Models.Modules (byte)Componente, (byte)(conectar ? 1 : 0), (byte)(AtuacaoNivelAlto ? 1 : 0), + (byte)Servo_ID_Num, (byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR), (byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO) }; @@ -1188,7 +1330,8 @@ namespace AgroBase.Models.Modules CanMessagePosicaoDados.Command1, new byte[] { - (byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado) + (byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado), + (byte)AnguloControle } ); } @@ -1259,6 +1402,7 @@ namespace AgroBase.Models.Modules public int ID_Num { get; set; } public bool ComandoAtuar { get; set; } public S_Code Componente { get; set; } = S_Code.sBMB; + public int Sensor_ID_Num { get; set; } public bool Comandar { get; set; } public bool Mandatorio { get; set; } public bool Liberado @@ -1278,6 +1422,9 @@ namespace AgroBase.Models.Modules } } public List ValoresLeituras { get; set; } + public Estado _EstadoLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; + public double _Potencia => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0; + @@ -1289,6 +1436,7 @@ namespace AgroBase.Models.Modules (byte)Componente, (byte)(conectar ? 1 : 0), (byte)Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha, + (byte)Sensor_ID_Num, (byte)(pinout.Pinos.FirstOrDefault(x => x.ComponenteID == ID && x.Funcao == FuncoesPinout.ENA)?.Pino ?? PinoutUtils.PINO_INVALIDO), (byte)(pinout.Pinos.FirstOrDefault(x => x.Funcao == FuncoesPinout.CS)?.Pino ?? PinoutUtils.PINO_INVALIDO), }; @@ -1503,21 +1651,6 @@ namespace AgroBase.Models.Modules } - - - - public class FirmwareBombaPressurizadora : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Estado { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Potencia { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel PressaoSP { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Pressao { get; set; } = new CanCommandFreqModel(); - } - public class AtuadorMensagemJsonModel { public DateTime Momento { get; set; } @@ -1527,9 +1660,10 @@ namespace AgroBase.Models.Modules public string Mod_ID { get; set; } public int QualidadeWifi { get; set; } public int LatenciaLoop { get; set; } - public List BicosPulverizadores { get; set; } = new List(); - public List BombasPressurizadoras { get; set; } = new List(); - public List Sensores { get; set; } = new List(); + public List BicosPulverizadores { get; set; } + public List BombasPressurizadoras { get; set; } + public List Sensores { get; set; } + public List Servos { get; set; } public DateTime UltimoComandoRespondido { get; set; } } @@ -1566,8 +1700,9 @@ namespace AgroBase.Models.Modules var sensor = Disp.Sensores.FirstOrDefault(x => x.ID_Num == ID_Num); var bico = Disp.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == ID_Num); var bomba = Disp.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == ID_Num); + var servo = Disp.Servos.FirstOrDefault(x => x.ID_Num == ID_Num); - return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? S_Code.sVZO; + return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? servo?.Componente ?? S_Code.sVZO; } private void AtualizarDados(int CompID_Num, CanMessagePosicaoDados Posicao, S_Code componente, List Parametros) @@ -1577,12 +1712,14 @@ namespace AgroBase.Models.Modules var sensor = Dados.Sensores.FirstOrDefault(x => x.ID_Num == CompID_Num); var bomba = Dados.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == CompID_Num); var bico = Dados.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == CompID_Num); + var servo = Dados.Servos.FirstOrDefault(x => x.ID_Num == CompID_Num); List valoresLeituras = new List(); if (sensor != null) valoresLeituras = sensor.ValoresLeituras; else if (bomba != null) valoresLeituras = bomba.ValoresLeituras; else if (bico != null) valoresLeituras = bico.ValoresLeituras; + else if (servo != null) valoresLeituras = servo.ValoresLeituras; for (int i = 0; i < valoresLeituras.Where(x => x.posicao == Posicao).Count(); i++) { @@ -1610,6 +1747,8 @@ namespace AgroBase.Models.Modules bomba.Inicializado = v; if (bico != null) bico.Inicializado = v; + if (servo != null) + servo.Inicializado = v; } } } @@ -1681,7 +1820,8 @@ namespace AgroBase.Models.Modules case CanMessagePosicaoDados.Dados1: { Estado estado = (Estado)data[2]; - AtualizarDados(ID_Num, posicao, componente, new List() { estado }); + int angulo = data[3]; + AtualizarDados(ID_Num, posicao, componente, new List() { estado, angulo }); break; } } @@ -1699,8 +1839,10 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double vazao = ConverterByteParaDouble(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { vazao }); + int qtdPulsos = data[2]; + ushort periodo = Converter2BytesU16(data, 3); + double vazao = ConverterByteParaDouble(data, 5); + AtualizarDados(ID_Num, posicao, componente, new List() { qtdPulsos, periodo, vazao }); break; } } @@ -1718,8 +1860,9 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double massa = ConverterByteParaDouble(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { massa }); + double raw = ConverterByteParaDouble(data, 2); + double massa = ConverterByteParaDouble(data, 4); + AtualizarDados(ID_Num, posicao, componente, new List() { raw, massa }); break; } } @@ -1737,8 +1880,9 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double pressao = ConverterByteParaDouble(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { pressao }); + ushort raw = Converter2BytesU16(data, 2); + double pressao = ConverterByteParaDouble(data, 4); + AtualizarDados(ID_Num, posicao, componente, new List() { raw, pressao }); break; } } @@ -1787,9 +1931,28 @@ namespace AgroBase.Models.Modules } break; } - + case S_Code.sSRV: + { + switch (posicao) + { + case CanMessagePosicaoDados.Status: + { + bool Iniciado = data[2] == 1; + AtualizarDados(ID_Num, posicao, componente, new List() { Iniciado }); + break; + } + case CanMessagePosicaoDados.Dados1: + { + int angulo = data[2]; + AtualizarDados(ID_Num, posicao, componente, new List() { angulo }); + break; + } + } + break; + } + } - + Dados.DadosLeitura.UltimoComandoRespondido = DateTime.Now; Variaveis.OperacaoEmAndamento.DispAtu.Dados.AtualizarDadosSensoresExternos(componente, ID_Num); diff --git a/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs b/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs index 6f2b5a533..69a0a1691 100644 --- a/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs @@ -37,6 +37,7 @@ namespace AgroBase.Models.Modules 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; public AsyncTaskTimerModel tmrRegistrador; @@ -138,6 +139,7 @@ namespace AgroBase.Models.Modules Dados.DistanciaPercorridaOperacao = 0; Dados.VelocidadeMedia = 0; Dados.TempoEmAtividade = 0; + Dados.UltimoTickRegistrador = DateTime.MinValue; Dados.Modulos.ForEach(x => { x.MovMotor.AlarmeSensores = false; @@ -220,7 +222,11 @@ namespace AgroBase.Models.Modules var UltimaDirecao = Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Mov)?.UltimaDirecao ?? Direcao.Parado; if (UltimaDirecao != Direcao.Parado) { - double tempo = _TaxaAmostragem / 1000.0; + //double tempo = _TaxaAmostragem / 1000.0; + DateTime agora = DateTime.Now; + double tempo = UltimoTickRegistrador == DateTime.MinValue ? 0 : (agora - UltimoTickRegistrador).TotalSeconds; + UltimoTickRegistrador = agora; + double distancia = tempo * VelocidadeMedia; DistanciaPercorridaTotal += distancia; DistanciaPercorridaParcial += ((UltimaDirecao == Direcao.Frente ? 1 : UltimaDirecao == Direcao.Tras ? -1 : 0) * distancia); diff --git a/AgroBase/AgroBase/Models/Modules/PinoutModel.cs b/AgroBase/AgroBase/Models/Modules/PinoutModel.cs index 84dc3fb54..4355ffd72 100644 --- a/AgroBase/AgroBase/Models/Modules/PinoutModel.cs +++ b/AgroBase/AgroBase/Models/Modules/PinoutModel.cs @@ -405,7 +405,7 @@ namespace AgroBase.Models.Modules ModbusDI, ModbusRO, ModbusDE_RE, - ServoFreio, + Servo, Potenciometro, M0, M1, @@ -432,7 +432,9 @@ namespace AgroBase.Models.Modules CodAlarme, LeituraBruta, LeituraAngulo, - Cooler + Cooler, + QtdPulsos, + Periodo } public static class PinoutUtils diff --git a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs index 0d7db9e5e..92d44549e 100644 --- a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs @@ -1211,10 +1211,16 @@ namespace AgroBase.Models.Modules indice = 0, }, new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.LeituraBruta, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + }, + new SensorValoresLeituraModel() { funcao = FuncoesPinout.LuzUV, posicao = CanMessagePosicaoDados.Dados1, - indice = 0, + indice = 1, analise_health = true, maximo = 11.0, minimo = 0.0, @@ -1263,10 +1269,16 @@ namespace AgroBase.Models.Modules indice = 0, }, new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.LeituraBruta, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + }, + new SensorValoresLeituraModel() { funcao = FuncoesPinout.Gas, posicao = CanMessagePosicaoDados.Dados1, - indice = 0, + indice = 1, analise_health = true, maximo = 600.0, minimo = 0.0, @@ -1315,10 +1327,16 @@ namespace AgroBase.Models.Modules indice = 0, }, new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.LeituraBruta, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + }, + new SensorValoresLeituraModel() { funcao = FuncoesPinout.Gas, posicao = CanMessagePosicaoDados.Dados1, - indice = 0, + indice = 1, analise_health = true, maximo = 400.0, minimo = 0.0, @@ -1510,10 +1528,16 @@ namespace AgroBase.Models.Modules indice = 0, }, new SensorValoresLeituraModel() + { + funcao = FuncoesPinout.LeituraBruta, + posicao = CanMessagePosicaoDados.Dados1, + indice = 0, + }, + new SensorValoresLeituraModel() { funcao = FuncoesPinout.Chuva, posicao = CanMessagePosicaoDados.Dados1, - indice = 0, + indice = 1, analise_health = true, maximo = 100.0, minimo = 0.0, @@ -1753,12 +1777,12 @@ namespace AgroBase.Models.Modules ID = "FROET", ID_Num = 41, Descricao = "Freio Motor ET", - Componente = S_Code.sFRO, + Componente = S_Code.sSRV, Controlar = true, Mandatorio = false, Funcoes = new List() { - FuncoesPinout.ServoFreio, + FuncoesPinout.Servo, }, _AnguloControle = 0, Incremental = true, @@ -1784,12 +1808,12 @@ namespace AgroBase.Models.Modules ID = "FROEF", ID_Num = 42, Descricao = "Freio Motor EF", - Componente = S_Code.sFRO, + Componente = S_Code.sSRV, Controlar = false, Mandatorio = false, Funcoes = new List() { - FuncoesPinout.ServoFreio, + FuncoesPinout.Servo, }, _AnguloControle = 0, Incremental = true, @@ -1815,12 +1839,12 @@ namespace AgroBase.Models.Modules ID = "FRODT", ID_Num = 43, Descricao = "Freio Motor DT", - Componente = S_Code.sFRO, + Componente = S_Code.sSRV, Controlar = true, Mandatorio = false, Funcoes = new List() { - FuncoesPinout.ServoFreio, + FuncoesPinout.Servo, }, _AnguloControle = 180, Incremental = false, @@ -1846,12 +1870,12 @@ namespace AgroBase.Models.Modules ID = "FRODF", ID_Num = 44, Descricao = "Freio Motor DF", - Componente = S_Code.sFRO, + Componente = S_Code.sSRV, Controlar = false, Mandatorio = false, Funcoes = new List() { - FuncoesPinout.ServoFreio, + FuncoesPinout.Servo, }, _AnguloControle = 180, Incremental = false, @@ -2263,35 +2287,6 @@ namespace AgroBase.Models.Modules AtualizaComponentesIniciados(); } - public (bool, List) StatusModulosSEN() - { - var _Sensores = Sensores?.Where(x => x.Aferir).ToList(); - var _SensoresComFalha = _Sensores?.Where(x => !x.Liberado).ToList(); - bool _sensoresOperantes = (_SensoresComFalha?.Count() ?? 0) < (_Sensores?.Count() ?? 0); - - var _Sinaleiros = Sinaleiros?.ToList(); - var _SinaleirosComFalha = _Sinaleiros?.Where(x => !x.Inicializado).ToList(); - bool _sinaleirosOperantes = !(_SinaleirosComFalha?.Any() ?? false); - - var _Reles = Reles?.Where(x => x.Controlar).ToList(); - var _RelesComFalha = _Reles?.Where(x => !x.Liberado).ToList(); - bool _relesOperantes = !(_RelesComFalha?.Any() ?? false); - - var _Servos = Servos?.Where(x => x.Controlar).ToList(); - var _ServosComFalha = _Servos?.Where(x => !x.Liberado).ToList(); - bool _servosOperantes = !(_ServosComFalha?.Any() ?? false); - - bool _sensoriamentoOperante = _sinaleirosOperantes && _sensoresOperantes && _relesOperantes && _servosOperantes; - List ModsComFalha = - (_SensoresComFalha?.Select(x => x.ID) ?? new List()) - .Union(_SinaleirosComFalha?.Select(x => x.ID) ?? new List()) - .Union(_RelesComFalha?.Select(x => x.ID) ?? new List()) - .Union(_ServosComFalha?.Select(x => x.ID) ?? new List()) - .ToList(); - - return (_sensoriamentoOperante, ModsComFalha); - } - private void VerificaControleLeitura() { if (true) // !frmDiagnosticos.Diagnosticando @@ -2334,8 +2329,7 @@ namespace AgroBase.Models.Modules foreach (var servo in Servos.Where(x => x.Controlar && x.Inicializado)) { - int leituraAngulo = (int?)(servo.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.ServoAnguloLeitura)?.atual?.valor) ?? 0; - if (leituraAngulo != servo._AnguloControle) + if (servo._AnguloLeiutra != servo._AnguloControle) { GeneralJoystick.EnviarComandoSensoriamento(S_Code.sFRO, servo.ID, servo._AnguloControle); } @@ -2369,73 +2363,6 @@ namespace AgroBase.Models.Modules } } - public void AtualizarStatusComponentes() - { - var StatusSaudaveis = new List() { StatusModulo.Desconectado, StatusModulo.Falha }; - - var saudeSen = RedisService.GetField(RedisService.ModKey(T_Code.Sen), "saude"); - DadosLeitura.Conectado = !StatusSaudaveis.Contains(saudeSen?.status ?? StatusModulo.Desconectado); - - if (DadosLeitura.Conectado) - { - var objetos = - Sensores - .Select(x => new - { - Chave = "sensores", - Componente = x.Componente, - ID_Num = x.ID_Num - }) - .Union(Servos - .Select(x => new - { - Chave = "servos", - Componente = x.Componente, - ID_Num = x.ID_Num - })) - .ToList(); - - foreach (var sensor in objetos) - { - string chave = sensor.Chave; - int tipo = (int)sensor.Componente; - int id = sensor.ID_Num; - string basePath = $"{chave}.{tipo}.{id}"; - - var saude = RedisService.GetField(RedisService.ModKey(T_Code.Sen), $"{basePath}.saude"); - bool inicializado = !StatusSaudaveis.Contains(saude?.status ?? StatusModulo.Desconectado); - switch (chave) - { - case "sensores": - Sensores.FirstOrDefault(x => x.ID_Num == sensor.ID_Num).Inicializado = inicializado; - break; - case "servos": - Servos.FirstOrDefault(x => x.ID_Num == sensor.ID_Num).Inicializado = inicializado; - break; - } - } - } - else - { - foreach (var led in Sinaleiros.Where(x => x.Inicializado)) - { - led.Inicializado = false; - } - foreach (var rele in Reles.Where(x => x.Inicializado)) - { - rele.Inicializado = false; - } - foreach (var servo in Servos.Where(x => x.Inicializado)) - { - servo.Inicializado = false; - } - foreach (var sensor in Sensores.Where(x => x.Inicializado)) - { - sensor.Inicializado = false; - } - } - } - } public class SensorModel @@ -2562,7 +2489,6 @@ namespace AgroBase.Models.Modules } public bool AtuacaoNivelAlto { get; set; } public Estado StatusControle { get; set; } - public Estado StatusLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; public bool Inicializado { get; set; } public DateTime UltimaLeitura { @@ -2572,6 +2498,8 @@ namespace AgroBase.Models.Modules } } public List ValoresLeituras { get; set; } + public Estado _EstadoLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; + public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar) { @@ -2718,19 +2646,6 @@ namespace AgroBase.Models.Modules } } - public class SenSensorimanetoGrafico - { - public DateTime Momento { get; set; } - public string ComponenteID { get; set; } - public S_Code Componente { get; set; } - public double Leitura1 { get; set; } - public double Leitura2 { get; set; } - public double Leitura3 { get; set; } - public double Leitura4 { get; set; } - public bool AlarmeMaxima { get; set; } - public bool AlarmeMinima { get; set; } - } - public class SensorParametroModel { public string Descricao { get; set; } @@ -2779,247 +2694,6 @@ namespace AgroBase.Models.Modules public string unidade_medida { get; set; } } - - public class FirmwareSensorTemperaturaNTC : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Temperatura { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorCorrente : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel BusVoltage { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel ShuntVoltage { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Current { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Power { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Energy { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Temperature { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSinaleiro : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Leitura { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Comando { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareRele : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Leitura { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareServoFreio : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Angulo { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorFluxo : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Vazao { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorMassa : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Massa { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorPressao : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Pressao { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorIMU : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public double AccX { get; set; } - public double AccY { get; set; } - public double AccZ { get; set; } - public double GyrX { get; set; } - public double GyrY { get; set; } - public double GyrZ { get; set; } - public double MagX { get; set; } - public double MagY { get; set; } - public double MagZ { get; set; } - public double Temperatura { get; set; } - public double Pressao { get; set; } - public double Altitude { get; set; } - public double Roll { get; set; } - public double Pitch { get; set; } - public double Yaw { get; set; } - public double YawFixed - { - get - { - double angulo = Yaw; - - // ✅ Aplica o offset armazenado - return GPSUtils.NormalizarAngulo(GPSUtils.NormalizarAngulo(angulo) + Offset); - } - } - - public double Offset { get; set; } = 0.0; - private DateTime ultimaAtualizacaoOffset = DateTime.MinValue; - public void AtualizarOffset(GPSModel UltimaLeitura) - { - // Verifica se a qualidade do GPS é boa - if (UltimaLeitura.QualidadeFix == TiposCorrecaoGPS.RTKFixo || UltimaLeitura.QualidadeFix == TiposCorrecaoGPS.RTKFlutuante) - { - // Só atualiza o offset se a última atualização foi há pelo menos 2 segundos (evita variações rápidas) - if ((DateTime.Now - ultimaAtualizacaoOffset).TotalSeconds > 2) - { - // Suaviza a mudança do offset para evitar grandes variações - double novoOffset = UltimaLeitura.OrientacaoReal - YawFixed; - Offset = (Offset * 0.8) + (novoOffset * 0.2); // Filtro exponencial - - // Atualiza o tempo da última atualização - ultimaAtualizacaoOffset = DateTime.Now; - } - } - } - - public FirmwareSensorIMU Clone() - { - return new FirmwareSensorIMU() - { - ID_Num = ID_Num, - Iniciado = Iniciado, - Pitch = Pitch, - Roll = Roll, - Yaw = Yaw, - Temperatura = Temperatura, - Altitude = Altitude, - Pressao = Pressao, - AccX = AccX, - AccY = AccY, - AccZ = AccZ, - MagX = MagX, - MagY = MagY, - MagZ = MagZ, - GyrX = GyrX, - GyrY = GyrY, - GyrZ = GyrZ, - Offset = Offset, - }; - } - - public string DadosToString() - { - return - $"[IMU] " + - $"Iniciado: {Iniciado}, " + - $"AccX: {AccX}, " + - $"AccY: {AccY}, " + - $"AccZ: {AccZ}, " + - $"GyrX: {GyrX}, " + - $"GyrY: {GyrY}, " + - $"GyrZ: {GyrZ}, " + - $"MagX: {MagX}, " + - $"MagY: {MagY}, " + - $"MagZ: {MagZ}, " + - $"Temperatura: {Temperatura}, " + - $"Pressao: {Pressao}, " + - $"Altitude: {Altitude}, " + - $"Roll: {Roll}, " + - $"Pitch: {Pitch}, " + - $"Yaw: {Yaw}, " + - $"Yaw Corrigido: {YawFixed}"; - } - - } - - public class FirmwareSensorGas : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel PPM { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorTemperaturaSHT : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Temperatura { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Umidade { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorLuminosidade : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Lux { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorLuzUV : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel IndiceUV { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorQualidadeAr : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel TVOC { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel ECO2 { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel AQI { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Temperatura { get; set; } = new CanCommandFreqModel(); - public CanCommandFreqModel Umidade { get; set; } = new CanCommandFreqModel(); - } - - public class FirmwareSensorChuva : IFirmwareSensorBase - { - public DateTime Momento { get; set; } - public string ID { get; set; } - public int ID_Num { get; set; } - public bool Iniciado { get; set; } - public CanCommandFreqModel Percentual { get; set; } = new CanCommandFreqModel(); - } - - public class SensoriamentoMensagemJsonModel { public DateTime Momento { get; set; } @@ -3334,8 +3008,9 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double temperatura = ConverterByteParaDouble(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { temperatura }); + ushort raw = Converter2BytesU16(data, 2); + double temperatura = ConverterByteParaDouble(data, 4); + AtualizarDados(ID_Num, posicao, componente, new List() { raw, temperatura }); break; } } @@ -3410,7 +3085,7 @@ namespace AgroBase.Models.Modules } break; } - case S_Code.sFRO: + case S_Code.sSRV: { switch (posicao) { @@ -3494,8 +3169,9 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double ppm = ConverterBytesParaDouble32(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { ppm }); + ushort raw = Converter2BytesU16(data, 2); + double ppm = ConverterBytesParaDouble32(data, 4); + AtualizarDados(ID_Num, posicao, componente, new List() { raw, ppm }); break; } } @@ -3552,8 +3228,9 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double iuv = ConverterByteParaDouble(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { iuv }); + ushort raw = Converter2BytesU16(data, 2); + double iuv = ConverterByteParaDouble(data, 4); + AtualizarDados(ID_Num, posicao, componente, new List() { raw, iuv }); break; } } @@ -3599,8 +3276,9 @@ namespace AgroBase.Models.Modules } case CanMessagePosicaoDados.Dados1: { - double percentual = ConverterByteParaDouble(data, 2); - AtualizarDados(ID_Num, posicao, componente, new List() { percentual }); + ushort raw = Converter2BytesU16(data, 2); + double percentual = ConverterByteParaDouble(data, 4); + AtualizarDados(ID_Num, posicao, componente, new List() { raw, percentual }); break; } } diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index f0efa22fe..385e1f479 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -1461,7 +1461,7 @@ namespace AgroBase.Models { foreach (var Bomba in Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras) { - bool Ligado = Bomba.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor > 0; + bool Ligado = Bomba._Potencia > 0; if (!Ligado) { Variaveis.OperacaoEmAndamento.Controle.BombaAtuada = true; @@ -1694,6 +1694,7 @@ namespace AgroBase.Models if (controleBase.Controle.PercentualVelocidadeSP != null) _Controle.PercentualVelocidadeSP = (double)controleBase.Controle.PercentualVelocidadeSP; if (controleBase.Controle.AnguloSP != null) _Controle.Angulo = (double)controleBase.Controle.AnguloSP; if (controleBase.Controle.TipoMovimentoDirecional != null) _Controle.TipoMovimento = (TipoMovimentoDirecional)controleBase.Controle.TipoMovimentoDirecional; + if (controleBase.Controle.EmFreio != null) _Controle.EmFreio = (bool)controleBase.Controle.EmFreio; Keys tecla = GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.botaoJoy == controleBase.Tecla)?.key ?? Keys.Escape; GeneralJoystick.EnviaComandoMotor(tecla, controleBase.Dispositivo, ForcarComando: true, ID: controleBase._comp_id); @@ -1821,7 +1822,7 @@ namespace AgroBase.Models VolumeReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.VolumeAtual_L, PressaoLinha_SP = Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha, PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha, - PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0, + PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?._Potencia ?? 0, BombaLigada = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ComandoAtuar, VazaoFluxoMLpSInstantanea = Variaveis.OperacaoEmAndamento.DispAtu.Dados.VazaoFluxoMLpSInstantanea, VazaoFluxoMLpSMedia = Variaveis.OperacaoEmAndamento.DispAtu.Dados.VazaoFluxoMLpSMedia, @@ -1836,7 +1837,7 @@ namespace AgroBase.Models Atuado = Bico.ComandoAtuar, MediaNivelFluxo = Bico.MediaNivelFluxo, Posicao = Bico.Posicao, - StatusBico = Bico.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor == Estado.Ligado, + StatusBico = Bico._EstadoLeitura == Estado.Ligado, Atuacoes = Bico.Atuacoes, TempoAtuado = Bico.TempoAtuado, }).ToList(), @@ -2245,6 +2246,7 @@ namespace AgroBase.Models public double? PercentualVelocidadeSP { get; set; } public double? AnguloSP { get; set; } public TipoMovimentoDirecional? TipoMovimentoDirecional { get; set; } + public bool? EmFreio { get; set; } public bool? Estado { get; set; } public double? Altura { get; set; } } @@ -2376,13 +2378,14 @@ namespace AgroBase.Models PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0, PercentualReservatorio = _Reservatorio.PercentualAtual, VolumeReservatorio = _Reservatorio.VolumeAtual_L, + MassaReservatorio = _Reservatorio.MassaAtual_Kg, PressaoLinha = _DispAtu.Dados.PressaoLinha, VazaoInstantanea = _DispAtu.Dados.VazaoFluxoMLpSInstantanea, VazaoMedia = _DispAtu.Dados.VazaoFluxoMLpSMedia, TempoBombaAtuada = _DispAtu.Dados.TempoAtuado, - ComandoBomba = _DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?.ComandoAtuar ?? false, - LeituraComandoBomba = (_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado) == Estado.Ligado, - LeituraPotenciaBomba = FuncoesMatematicas.Clamp(_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0, 0, 100), + ComandoBomba = _DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ComandoAtuar, + LeituraComandoBomba = _DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()._EstadoLeitura == Estado.Ligado, + LeituraPotenciaBomba = FuncoesMatematicas.Clamp(_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()._Potencia, 0, 100), VolumeVazaoMl = _DispAtu.Dados.VolumeVazaoML, Iniciados = _DispAtu.Dados.Sensores.Select(s => new { s.ID, s.Inicializado }).Union(_DispAtu.Dados.BicosPulverizadores.Select(b => new { b.ID, b.Inicializado })).Union(_DispAtu.Dados.BombasPressurizadoras.Select(b => new { b.ID, b.Inicializado })).ToDictionary(x => x.ID, x => x.Inicializado), AnguloBarraEsquerda = _DispAtu.Dados.AnguloBarraEsquerda, @@ -2401,7 +2404,7 @@ namespace AgroBase.Models Atuado = Bico.ComandoAtuar, MediaNivelFluxo = Bico.MediaNivelFluxo, Posicao = Bico.Posicao, - StatusBico = Bico.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor == Estado.Ligado, + StatusBico = Bico._EstadoLeitura == Estado.Ligado, Atuacoes = Bico.Atuacoes, TempoAtuado = Bico.TempoAtuado, AnguloAbertura = Bico.AnguloAbertura, @@ -2577,7 +2580,7 @@ namespace AgroBase.Models DispositivosMapeados = new List(SerialService.DispositivosMapeados), ModsCalibragem = new Dictionary>(Variaveis.OperacaoEmAndamento.ModsCalibragem), Temperaturas = _DispSen?.Dados?.Sensores?.Where(x => x.Componente == S_Code.sNTC)?.ToDictionary(x => x.ID, y => (double?)(y.ValoresLeituras?.FirstOrDefault(v => v.funcao == FuncoesPinout.Temperatura)?.atual?.valor) ?? -1), - Reles = _DispSen?.Dados?.Reles?.ToDictionary(x => x.ID, y => (y.StatusControle == Estado.Ligado, y.StatusLeitura == Estado.Ligado)), + Reles = _DispSen?.Dados?.Reles?.ToDictionary(x => x.ID, y => (y.StatusControle == Estado.Ligado, y._EstadoLeitura == Estado.Ligado)), Servos = _DispSen?.Dados?.Servos?.ToDictionary(x => x.ID, y => (y._AnguloControle, y._AnguloLeiutra, y.Incremental)), Iniciados = _DispSen?.Dados?.Servos?.Select(s => new { s.ID, s.Inicializado }).Union(_DispSen?.Dados?.Reles?.Select(r => new { r.ID, r.Inicializado })).Union(_DispSen?.Dados?.Sinaleiros?.Select(s => new { s.ID, s.Inicializado })).Union(_DispSen?.Dados?.Sensores?.Select(s => new { s.ID, s.Inicializado })).ToDictionary(s => s.ID, s => s.Inicializado), Logs = new List(Logs ?? new List()), @@ -2680,6 +2683,7 @@ namespace AgroBase.Models public bool ErvasNoRadar { get; set; } public double PercentualErvasNoRadar { get; set; } public double PercentualReservatorio { get; set; } + public double MassaReservatorio { get; set; } public double VolumeReservatorio { get; set; } public double PressaoLinha { get; set; } public double VazaoInstantanea { get; set; } @@ -2713,6 +2717,7 @@ namespace AgroBase.Models PercentualErvasTerreno = PercentualErvasTerreno, PercentualReservatorio = PercentualReservatorio, VolumeReservatorio = VolumeReservatorio, + MassaReservatorio = MassaReservatorio, PressaoLinha = PressaoLinha, VazaoInstantanea = VazaoInstantanea, VazaoMedia = VazaoMedia, diff --git a/AgroBase/AgroBase/Models/Variaveis.cs b/AgroBase/AgroBase/Models/Variaveis.cs index bf74c8919..5a5204f11 100644 --- a/AgroBase/AgroBase/Models/Variaveis.cs +++ b/AgroBase/AgroBase/Models/Variaveis.cs @@ -228,7 +228,7 @@ namespace AgroBase.Models public static double PercentualReservatorioMin { get; set; } = 8.0; public static double PercentualToleranciaPressaoLinha { get; set; } = 0.15; public static int QuantidadeCamerasSolo { get; set; } = 1; - public static int QuantidadeBicosPulverizadores { get; set; } = 4; + public static int QuantidadeBicosPulverizadores { get; set; } = 3; public static double AlturaBarraPulverizadoraCm { get; set; } = 80; public static double ComprimentoBarraPulverizadoraCm { get; set; } = 103.7; public static double DistanciaEntreBicosCm { get; set; } = 50; diff --git a/AgroBase/AgroBase/Services/CoolerControlService.cs b/AgroBase/AgroBase/Services/CoolerControlService.cs index f8e0a00dd..8f1757b06 100644 --- a/AgroBase/AgroBase/Services/CoolerControlService.cs +++ b/AgroBase/AgroBase/Services/CoolerControlService.cs @@ -157,9 +157,9 @@ namespace AgroBase.Services private void EnviarComando() { - if (ReleCoolerEntrada != null && (ReleCoolerEntrada?.StatusLeitura ?? Estado.Desligado) != CoolerEntradaEstado) + if (ReleCoolerEntrada != null && ReleCoolerEntrada._EstadoLeitura != CoolerEntradaEstado) GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerEntrada.Componente, ReleCoolerEntrada.ID, CoolerEntradaEstado); - if (ReleCoolerSaida != null && (ReleCoolerSaida?.StatusLeitura ?? Estado.Desligado) != CoolerSaidaEstado) + if (ReleCoolerSaida != null && ReleCoolerSaida._EstadoLeitura != CoolerSaidaEstado) GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerSaida.Componente, ReleCoolerSaida.ID, CoolerSaidaEstado); } diff --git a/AgroBase/AgroBase/Services/HerbicideCounterService.cs b/AgroBase/AgroBase/Services/HerbicideCounterService.cs index e396a83bb..c502113a6 100644 --- a/AgroBase/AgroBase/Services/HerbicideCounterService.cs +++ b/AgroBase/AgroBase/Services/HerbicideCounterService.cs @@ -37,6 +37,7 @@ namespace AgroBase.Services /// Massa atual lida no reservatório (Kg). /// public double MassaAtual_Kg { get; private set; } + public double MassaAtual_Kg_Calc { get; private set; } /// /// Volume atual estimado no reservatório (L). @@ -163,8 +164,9 @@ namespace AgroBase.Services if (!Iniciado) return; - bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && (x.ValoresLeituras?.Any(y => y.funcao == FuncoesPinout.EstadoLeitura && y.atual?.valor == Estado.Ligado) ?? false)) ?? false; + bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado) ?? false; double massaLida_Kg = Sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Massa)?.atual?.valor ?? 0; + double massaLida_Kg_bruto = Sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0; double volumeMedido_L = massaLida_Kg / DensidadeProduto; int qtd_atuacoes = Variaveis.OperacaoEmAndamento.Controle?.BicosAtuados?.Sum(x => x.Atuacoes) ?? 0; @@ -181,11 +183,13 @@ namespace AgroBase.Services _tempoTotalAnterior_s = tempoTotalSegundosAtual; MassaAtual_Kg = massaLida_Kg; + MassaAtual_Kg_Calc = massaLida_Kg_bruto; VolumeAtual_L = volumeMedido_L; return; } MassaAtual_Kg = massaLida_Kg; + MassaAtual_Kg_Calc = massaLida_Kg_bruto; VolumeAtual_L = volumeMedido_L; // --- Cálculo de deltas básicos --- diff --git a/AgroBase/OperationControl/Windows/MainWindow.xaml.cs b/AgroBase/OperationControl/Windows/MainWindow.xaml.cs index 518c7d1c5..a8eed3b43 100644 --- a/AgroBase/OperationControl/Windows/MainWindow.xaml.cs +++ b/AgroBase/OperationControl/Windows/MainWindow.xaml.cs @@ -1075,7 +1075,7 @@ namespace OperationControl.Windows var bico = rover?.Controle?.BicosAtuados?.FirstOrDefault(x => x.ID == label); bool comando = bico?.ComandoAtuar ?? false; - var leitura = bico?.ValoresLeituras?.FirstOrDefault(x => x.funcao == AgroBase.Models.Modules.FuncoesPinout.EstadoLeitura)?.atual?.valor; + var leitura = bico?._EstadoLeitura; txtBico_Titulo.Text = $"Bico {label} - Testes"; txtBico_Comando.Text = comando ? "Ligado" : "Desligado"; txtBico_StatusReal.Text = leitura != null && (AgroBase.Models.Enums.Estado)Enum.Parse(typeof(AgroBase.Models.Enums.Estado), leitura.ToString(), true) == AgroBase.Models.Enums.Estado.Ligado ? "Ligado" : "Desligado"; diff --git a/Firmware/Atuador/Atuador_v12/.theia/launch.json b/Firmware/Atuador/Atuador_v12/.theia/launch.json new file mode 100644 index 000000000..7e4253b33 --- /dev/null +++ b/Firmware/Atuador/Atuador_v12/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Firmware/Atuador/Atuador_v12/Atuador_v12.ino b/Firmware/Atuador/Atuador_v12/Atuador_v12.ino new file mode 100644 index 000000000..5ca4886c7 --- /dev/null +++ b/Firmware/Atuador/Atuador_v12/Atuador_v12.ino @@ -0,0 +1,355 @@ +// Dispositivo: Atuador +// Versão Firmware: 12 +// Ultima atualização: 16/12/2025 +// Atualização: Adicionado controle dos bicos pulverizadores + +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\CanService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\I2CService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BicoPulverizadorModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BombaPressurizadoraModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorFluxoModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMassaModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorPressaoModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMagneticoModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ServoAgroModel.h" + + +// Configurações do CAN +uint8_t CanID = 0x12; +CanService canService = CanService(CanID); + +#define D_Code Atu +int VERSION = 12; +const String Mod_ID = "Atu"; + +#define _pinoLED RGB_BUILTIN + +bool Conectado = false; +bool Conectar = false; + +int _TaxaAmostragem = 1000; +volatile bool RequisitarDados = false; +int latenciaLoop = 0; +int qtdEnviosStatus = 0; +int maxEnviosStatus = 5; + +std::vector listaBicos; +std::vector listaBombas; +std::vector listaSensoresFluxo; +std::vector listaSensoresMassa; +std::vector listaSensoresPressao; +std::vector listaSensoresMagneticos; +std::vector listaServos; + +void MostrarLog(String mensagem) { + bool _debugMode = false; + if (_debugMode) { + PrintTela(String("[ATU] ") + mensagem); + } +} + +void inicializarDependenciasI2C() { + I2CService::IniciarI2C(); + I2CService::IniciarMUX(); +} + +void setup() { + delay(5000); + + inicializarDependenciasI2C(); + + // Registrar callback para processar mensagens CAN recebidas + canService.setReceiveCallback([](int packetSize, int senderId, CanMessagePosicaoDados posicao, byte* data, int dataLength) { + std::vector fullData; + fullData.push_back(static_cast(posicao)); // Primeiro byte é sempre a posicao + for (int i = 0; i < dataLength; i++) { + fullData.push_back(data[i]); + } + + ProcessarFrameCAN(posicao, fullData); + }); + + canService.begin(); +} + +void loop() { + if (!RequisitarDados) { + enviarLogsPeriodicamente(); + } + + for (auto* bomba : listaBombas) { + bomba->Loop(); + } + for (auto* sensor : listaSensoresFluxo) { + sensor->Loop(); + } + + delay(1); +} + +// Função para enviar logs do sensor periodicamente +unsigned long ultimoEnvioLogs = 0; +const unsigned long intervaloEnvioLogs = 1000; // 1 segundo +void enviarLogsPeriodicamente() { + unsigned long tempoAtual = millis(); + // Verifica se o intervalo de 5 segundos já passou + if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) { + ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio + + enviarDadosSensores(canService.ID_Num_sTOD, CanMessagePosicaoDados::DadosAll); + } +} + +void enviarDadosSensores(uint8_t id_num, CanMessagePosicaoDados posicao) { + if (Conectado || posicao == CanMessagePosicaoDados::Status) { + unsigned long startLoop = millis(); + + bool enviarStatus = qtdEnviosStatus >= maxEnviosStatus && posicao != CanMessagePosicaoDados::Status; + bool todosDados = posicao == CanMessagePosicaoDados::DadosAll; + bool todosIDs = id_num == canService.ID_Num_sTOD; + + if (id_num == canService.ID_Num_sMOD) { + EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION)); + return; + } + + MostrarLog("Atualizando dados dos sensores..."); + + if (todosIDs && enviarStatus) { + EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION)); + } + + ComponenteCAN::ProcessarComponentesCAN(listaBombas, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaBicos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresFluxo, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresMassa, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresPressao, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresMagneticos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaServos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + if (enviarStatus) { + qtdEnviosStatus = 0; + } + else { + qtdEnviosStatus++; + } + + latenciaLoop = millis() - startLoop; + + if (posicao == CanMessagePosicaoDados::DadosAll) { + EnviarDadosCAN(canService.MontarFrameReqDadosFim(latenciaLoop)); + } + + MostrarLog("Ciclo concluido, latencia de loop: " + String(latenciaLoop)); + } +} + +void EnviarDadosCAN(std::vector data) { + if (data.size() > 2) { + canService.adicionarMensagemFila(data); + } +} + +void ProcessarFrameCAN(CanMessagePosicaoDados posicao, std::vector data) { + if (data.size() < 1) return; + + F_Code funcao = canService.FuncaoPorPosicao(posicao); + + switch (funcao) { + case F_Code::ReqTx: ProcessarReq(data); break; + case F_Code::CmdTx: ProcessarCmd(data); break; + case F_Code::CfgTx: ProcessarCfg(data); break; + } +} + +void ProcessarReq(std::vector data) { + if (data.size() < 2) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + enviarDadosSensores(id, posicao); +} + +void ProcessarCfg(std::vector data) { + if (data.size() < 4) return; + std::vector _chkRx; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + S_Code componente = DetectarComponente(id); + if (componente == S_Code::sMOD) { + switch (posicao) { + case CanMessagePosicaoDados::Config1: { + if (data.size() < 7) return; + bool conectar = data[2] == 1; + int taxa = data[3] * 10; + bool requisitar = data[4] == 1; + int pinoSDA = data[5]; + int pinoSCL = data[6]; + + _TaxaAmostragem = taxa; + RequisitarDados = requisitar; + + LimparListasComponentes(); + + if (pinoSDA != PINO_INVALIDO && pinoSCL != PINO_INVALIDO) { + if (I2CService::DefinirPinos(pinoSDA, pinoSCL) || !I2CService::I2CIniciado) { + //inicializarDependenciasI2C(); + } + } + + vTaskDelay(pdMS_TO_TICKS(100)); + + Conectado = conectar; + _chkRx = canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION); + + MostrarLog("Configuracao do modulo concluida"); + break; + } + } + } + else { + componente = (S_Code)data[2]; + switch (componente) { + case sBIC: { + _chkRx = Bico::ConfigurarBico(listaBicos, data, Mod_ID, listaServos); + break; + } + case sFLX: { + _chkRx = SensorFluxo::ConfigurarSensor(listaSensoresFluxo, data, Mod_ID); + break; + } + case sPRS: { + _chkRx = SensorPressao::ConfigurarSensor(listaSensoresPressao, data, Mod_ID); + break; + } + case sMAS: { + _chkRx = SensorMassa::ConfigurarSensor(listaSensoresMassa, data, Mod_ID); + break; + } + case sBMB: { + _chkRx = BombaPressurizadora::ConfigurarBomba(listaBombas, data, Mod_ID, listaSensoresPressao); + break; + } + case sMAG: { + _chkRx = SensorMagnetico::ConfigurarSensor(listaSensoresMagneticos, data, Mod_ID); + break; + } + case sSRV: { + _chkRx = ServoAgro::ConfigurarServo(listaServos, data, Mod_ID); + break; + } + } + } + + EnviarDadosCAN(_chkRx); +} + +void ProcessarCmd(std::vector data) { + if (data.size() < 2) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + S_Code componente = DetectarComponente(id); + switch (componente) { + case sBIC: { + Bico::ComandarBico(listaBicos, data); + ComponenteCAN::ProcessarComponentesCAN(listaBicos, {}, false, id, false, false, CanMessagePosicaoDados::Dados1, EnviarDadosCAN); + break; + } + case sBMB: { + BombaPressurizadora::ComandarBomba(listaBombas, data); + break; + } + default: + break; + } +} + +void LimparListasComponentes() { + for (auto* bico : listaBicos) { + if (bico) { + bico->Desligar(); + MostrarLog("Bico " + bico->_ID + " desligado."); + delete bico; + } + } + listaBicos.clear(); + + for (auto* bomba : listaBombas) { + if (bomba) { + bomba->Desligar(); + MostrarLog("Bomba Pressurizadora " + bomba->_ID + " desligada."); + delete bomba; + } + } + listaBombas.clear(); + + for (auto* sensor : listaSensoresFluxo) { + if (sensor) { + sensor->Desligar(); + MostrarLog("Sensor de Fluxo " + sensor->_ID + " desligado."); + delete sensor; + } + } + listaSensoresFluxo.clear(); + + for (auto* sensor : listaSensoresMassa) { + if (sensor) { + sensor->Desligar(); + MostrarLog("Sensor de Massa " + sensor->_ID + " desligado."); + delete sensor; + } + } + listaSensoresMassa.clear(); + + for (auto* sensor : listaSensoresPressao) { + if (sensor) { + sensor->Desligar(); + MostrarLog("Sensor de Pressao " + sensor->_ID + " desligado."); + delete sensor; + } + } + listaSensoresPressao.clear(); + + for (auto* sensor : listaSensoresMagneticos) { + sensor->Desligar(); + MostrarLog("Sensor magnetico " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresMagneticos.clear(); + + for (auto* servo : listaServos) { + servo->Desligar(); + MostrarLog("Servo " + servo->_ID + " desligado."); + delete servo; + } + listaServos.clear(); +} + +S_Code DetectarComponente(uint8_t idNum) { + if (idNum == canService.ID_Num_sMOD) return S_Code::sMOD; + for (auto* s : listaBicos) { + if (s->ID_Num == idNum) return S_Code::sBIC; + } + for (auto* s : listaBombas) { + if (s->ID_Num == idNum) return S_Code::sBMB; + } + for (auto* s : listaSensoresFluxo) { + if (s->ID_Num == idNum) return S_Code::sFLX; + } + for (auto* s : listaSensoresMassa) { + if (s->ID_Num == idNum) return S_Code::sMAS; + } + for (auto* s : listaSensoresPressao) { + if (s->ID_Num == idNum) return S_Code::sPRS; + } + for (auto* s : listaSensoresMagneticos) { + if (s->ID_Num == idNum) return S_Code::sMAG; + } + for (auto* s : listaServos) { + if (s->ID_Num == idNum) return S_Code::sSRV; + } + return S_Code::sVZO; +} diff --git a/Firmware/Modulos/BicoPulverizadorModel.h b/Firmware/Modulos/BicoPulverizadorModel.h new file mode 100644 index 000000000..b169ed7b8 --- /dev/null +++ b/Firmware/Modulos/BicoPulverizadorModel.h @@ -0,0 +1,216 @@ +#include "SerialService.h" +#include "Pinout.h" +#include "Utils.h" +#include "IComponenteCAN.h" +#include "ServoAgroModel.h" + +#ifndef BicoModel +#define BicoModel + +class Bico : public ComponenteCAN { + public: + + Bico(String _modID, String _id) { + Mod_ID = _modID; + _ID = _id; + } + + String Mod_ID; + String _ID; + int ID_Num; + PinoModel _pino; + bool Iniciado = false; + + bool AtuacaoNivelAlto = true; + + Estado _Status = Desligado; + + ServoAgro* servoMov = nullptr; + + void Inicializar() { + if (Iniciado) { + MostrarLog("Bico ja inicializado"); + return; + } + + if (servoMov == nullptr) { + PrintTela("Servo nao definido, bico nao tera controle de movimento"); + //Iniciado = false; + //return; + } + + _pino.Conectar(!AtuacaoNivelAlto); + + Iniciado = _pino.Definido(); + + if (Iniciado) { + MostrarLog("Bico iniciado"); + } + else + { + MostrarLog("Bico nao iniciado"); + } + + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Bico nao esta inicializado"); + return; + } + + servoMov = nullptr; + + // Redefinir as configurações para os valores iniciais + _pino.Desconectar(); + + MostrarLog("Bico Desligado"); + + Iniciado = false; + } + + void AtualizarStatus(Estado novoEstado, int novoAngulo) { + if (Iniciado) { + bool status = novoEstado == Ligado; + if (!AtuacaoNivelAlto) { + status = !status; + } + + MostrarLog("Atualizando status do bico de " + String(_Status) + " para " + String(novoEstado)); + + _pino.set(status); + _Status = (Estado)_pino.get(); + + if (servoMov != nullptr) { + servoMov->AtualizarAngulo(novoAngulo); + } + } + } + + void AtualizarLeitura() { + if (Iniciado) { + _Status = (Estado)_pino.get(); + } + } + + void RequisitarDados() { + AtualizarLeitura(); + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + case CanMessagePosicaoDados::Dados1: { + data.push_back(static_cast(_Status)); + data.push_back(servoMov->_Angulo); + break; + } + } + return data; + } + + static std::vector ConfigurarBico(std::vector& lista, std::vector& data, const String& Mod_ID, std::vector& servos) { + std::vector status; + if (data.size() < 2) return status; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + auto it = std::find_if(lista.begin(), lista.end(), [idNum](Bico* s) { return s->ID_Num == idNum; }); + bool jaExiste = it != lista.end(); + Bico* bico; + switch (posicao) { + case CanMessagePosicaoDados::Config1: { + if (data.size() < 8) return status; + bool conectar = data[3] == 1; + bool atuacaoNivelAlto = data[4] == 1; + int servo_id = (data[5] == 0xFF) ? -1 : (int)data[5]; + TiposBarramentos tipoBarramento = (TiposBarramentos)data[6]; + int pino = data[7]; + if (conectar) { + if (!jaExiste) { + bico = new Bico(Mod_ID, "sBIC_" + String(idNum)); + } + else { + bico = *it; + } + if (!bico->Iniciado) { + bool com_movimento = servo_id >= 0; + if (com_movimento) { + if (servos.size() > 0) { + auto srv = std::find_if(servos.begin(), servos.end(), [servo_id](ServoAgro* s) { return s->ID_Num == servo_id; }); + bool servo_encontrado = srv != servos.end(); + if (servo_encontrado && (*srv)->Iniciado) { + bico->servoMov = *srv; + } + } + if (bico->servoMov == nullptr) { + PrintTela("O servo " + String(servo_id) + " nao foi encontrado para ser associado ao bico."); + delete bico; + return status; + } + } + bico->ID_Num = idNum; + bico->_pino = PinoModel(pino, tipoBarramento, _OUTPUT); + bico->AtuacaoNivelAlto = atuacaoNivelAlto; + bico->Inicializar(); + if (!jaExiste) { + lista.push_back(bico); + bico->MostrarLog("Bico adicionado via CAN: sBIC_" + String(idNum)); + } + } + status = bico->MontarMensagemCAN(CanMessagePosicaoDados::Status); + } else { + if (jaExiste) { + bico = *it; + bico->Desligar(); + status = bico->MontarMensagemCAN(CanMessagePosicaoDados::Status); + bico->MostrarLog("Bico removido via CAN: sBIC_" + String(idNum)); + delete bico; + lista.erase(it); + } + } + break; + } + } + return status; + } + + static void ComandarBico(std::vector& lista, std::vector& data) { + if (data.size() < 4) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + for (auto* _bico : lista) { + if (_bico->ID_Num == idNum) { + switch (posicao) { + case CanMessagePosicaoDados::Command1: { + Estado novoEstado = (Estado)data[2]; + int novoAngulo = data[3]; + _bico->AtualizarStatus(novoEstado, novoAngulo); + break; + } + } + return; + } + } + } + + + private: + bool DebugMode = false; + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[BIC " + _ID + "] " + mensagem); + } + } + +}; + + + +#endif \ No newline at end of file diff --git a/Firmware/Modulos/BombaPressurizadoraModel.h b/Firmware/Modulos/BombaPressurizadoraModel.h index 892bdf8ca..63573fc8e 100644 --- a/Firmware/Modulos/BombaPressurizadoraModel.h +++ b/Firmware/Modulos/BombaPressurizadoraModel.h @@ -33,7 +33,7 @@ class BombaPressurizadora : public ComponenteCAN { bool bombaDesligadaPorPressao = false; //PID* _PID = nullptr; - SensorPressao* sensorPressao; + SensorPressao* sensorPressao = nullptr; int ZeroRampa = 0; int RampaMax = 1023; @@ -184,11 +184,12 @@ class BombaPressurizadora : public ComponenteCAN { BombaPressurizadora* bomba; switch (posicao) { case CanMessagePosicaoDados::Config1: { - if (data.size() < 7) return status; + if (data.size() < 8) return status; bool conectar = data[3] == 1; int pressaoSp = (int)data[4]; - int pinoEn = data[5]; - int pinoCs = data[6]; + int sensor_id = (data[5] == 0xFF) ? -1 : (int)data[5]; + int pinoEn = data[6]; + int pinoCs = data[7]; if (conectar) { if (!jaExiste) { bomba = new BombaPressurizadora(Mod_ID, "sBMB_" + String(idNum)); @@ -197,15 +198,20 @@ class BombaPressurizadora : public ComponenteCAN { bomba = *it; } if (!bomba->Iniciado) { - if (sensoresPressao.size() > 0) { - if (sensoresPressao[0]->Iniciado) { - bomba->sensorPressao = sensoresPressao[0]; + bool malha_fechada = sensor_id >= 0; + if (malha_fechada) { + auto prs = std::find_if(sensoresPressao.begin(), sensoresPressao.end(), [sensor_id](SensorPressao* s) { return s->ID_Num == sensor_id; }); + bool sensor_encontrado = prs != sensoresPressao.end(); + if (sensoresPressao.size() > 0) { + if (sensor_encontrado && (*prs)->Iniciado) { + bomba->sensorPressao = *prs; + } + } + if (bomba->sensorPressao == nullptr) { + PrintTela("Sensor de pressao " + String(sensor_id) + " nao encontrado para associar à bomba."); + delete bomba; + return status; } - } - if (bomba->sensorPressao == nullptr) { - PrintTela("Nenhum sensor de pressão disponível para associar à bomba."); - delete bomba; - return status; } bomba->ID_Num = idNum; bomba->_pinoEN = PinoModel(pinoEn, CONTROLADOR, _OUTPUT); diff --git a/Firmware/Modulos/Enuns.h b/Firmware/Modulos/Enuns.h index 4d0325af5..59f578124 100644 --- a/Firmware/Modulos/Enuns.h +++ b/Firmware/Modulos/Enuns.h @@ -81,6 +81,7 @@ enum S_Code { sIUV = 31, sQAR = 32, sCHV = 33, + sSRV = 34, }; enum Estado { diff --git a/Firmware/Modulos/SensorChuvaModel.h b/Firmware/Modulos/SensorChuvaModel.h index 250015aec..90dc677c3 100644 --- a/Firmware/Modulos/SensorChuvaModel.h +++ b/Firmware/Modulos/SensorChuvaModel.h @@ -19,6 +19,7 @@ class SensorChuva : public ComponenteCAN { int ID_Num; PinoModel _pino; + int leitura = 0; double tensao = 0; double percentual = -1; @@ -65,8 +66,8 @@ class SensorChuva : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { int16_t pInt = static_cast(round(percentual * 100.0f)); - data.push_back((uint8_t)(pInt >> 8)); - data.push_back((uint8_t)(pInt & 0xFF)); + data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF)); + data.push_back((uint8_t)(pInt >> 8)); data.push_back((uint8_t)(pInt & 0xFF)); break; } } @@ -141,7 +142,7 @@ class SensorChuva : public ComponenteCAN { void AferirChuva() { if (!Iniciado) return; - int leitura = _pino.get(); + leitura = _pino.get(); tensao = (float)leitura / 4095.0f * Vs; tensao = tensao * divisor * vOffset; diff --git a/Firmware/Modulos/SensorFluxoModel.h b/Firmware/Modulos/SensorFluxoModel.h index 3164dff78..21473ed0f 100644 --- a/Firmware/Modulos/SensorFluxoModel.h +++ b/Firmware/Modulos/SensorFluxoModel.h @@ -101,8 +101,9 @@ class SensorFluxo : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { uint16_t vazaoEscalada = (uint16_t)(_Vazao * 100); - data.push_back(vazaoEscalada >> 8); - data.push_back(vazaoEscalada & 0xFF); + data.push_back(_PulsosLeitura); + data.push_back((uint8_t)(_PeriodoTotalLeitura >> 8)); data.push_back((uint8_t)(_PeriodoTotalLeitura & 0xFF)); + data.push_back(vazaoEscalada >> 8); data.push_back(vazaoEscalada & 0xFF); break; } } @@ -183,16 +184,25 @@ class SensorFluxo : public ComponenteCAN { } float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) { - if (periodoMs == 0) return 0; + if (periodoMs == 0) return 0.0f; // evita divisão por zero - float frequencia = (float)pulsos / (float)periodoMs * 1000.0; // Hz - const float Rh = 0.0047; // raio interno do tubo - const float Rt = 0.0037; // raio interno do rotor + // F = pulsos / (periodoMs/1000) => Hz + float F = ((float)pulsos) * 1000.0f / (float)periodoMs; - float vazao_m3s = frequencia * 2.0 * PI * Rh * PI * (Rt * Rt); // m³/s - float vazao_ml_s = vazao_m3s * 1e6; // ml/s + // Equação do anúncio: F = 8.1*q - 3 (q em L/min) + float q_L_min = (F + 3.0f) / 8.1f; - return vazao_ml_s; + // evita valores negativos perto do zero (offset -3) + if (q_L_min < 0.0f) q_L_min = 0.0f; + + // limites do sensor informados: 0.3–10 L/min (opcional "clamp") + // se você quiser respeitar mínimo físico, pode usar 0.3f ao invés de 0.0f + if (q_L_min > 10.0f) q_L_min = 10.0f; + + // L/min -> mL/s (1 L = 1000 mL; 1 min = 60 s) + float q_mL_s = q_L_min * (1000.0f / 60.0f); + + return q_mL_s; } diff --git a/Firmware/Modulos/SensorGasModel.h b/Firmware/Modulos/SensorGasModel.h index 66e50a1ed..7f8039171 100644 --- a/Firmware/Modulos/SensorGasModel.h +++ b/Firmware/Modulos/SensorGasModel.h @@ -28,6 +28,7 @@ class SensorGas : public ComponenteCAN { float ppm = -1; float tensao = -1; + int leitura = 0; bool Iniciado = false; bool Checando = false; @@ -71,11 +72,9 @@ class SensorGas : public ComponenteCAN { break; } case CanMessagePosicaoDados::Dados1: { - int32_t leituraInt = static_cast(round(ppm * 100.0f)); - data.push_back((uint8_t)(leituraInt >> 24)); - data.push_back((uint8_t)(leituraInt >> 16)); - data.push_back((uint8_t)(leituraInt >> 8)); - data.push_back((uint8_t)(leituraInt & 0xFF)); + int32_t ppmInt = static_cast(round(ppm * 100.0f)); + data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF)); + data.push_back((uint8_t)(ppmInt >> 24)); data.push_back((uint8_t)(ppmInt >> 16)); data.push_back((uint8_t)(ppmInt >> 8)); data.push_back((uint8_t)(ppmInt & 0xFF)); break; } } @@ -143,7 +142,7 @@ class SensorGas : public ComponenteCAN { void AferirGas() { if (!Iniciado) return; - float leitura = _pino.get(); + leitura = _pino.get(); ppm = CalcularPPM(leitura); MostrarLog("Leitura Gas: " + String(leitura) + ", Tensao: " + String(tensao) + ", PPM estimado: " + String(ppm)); } diff --git a/Firmware/Modulos/SensorLuzUVModel.h b/Firmware/Modulos/SensorLuzUVModel.h index 461b2ef4e..59869cfbe 100644 --- a/Firmware/Modulos/SensorLuzUVModel.h +++ b/Firmware/Modulos/SensorLuzUVModel.h @@ -21,6 +21,7 @@ class SensorLuzUV : public ComponenteCAN { double tensao = 0; double uv_index = -1; + int leitura = 0; bool Iniciado = false; bool Checando = false; @@ -65,8 +66,8 @@ class SensorLuzUV : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { int16_t uvInt = static_cast(round(uv_index * 100.0f)); - data.push_back((uint8_t)(uvInt >> 8)); - data.push_back((uint8_t)(uvInt & 0xFF)); + data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF)); + data.push_back((uint8_t)(uvInt >> 8)); data.push_back((uint8_t)(uvInt & 0xFF)); break; } } @@ -137,7 +138,7 @@ class SensorLuzUV : public ComponenteCAN { void AferirUV() { if (!Iniciado) return; - int leitura = _pino.get(); + leitura = _pino.get(); float Vadc = (float)leitura / 4095.0f * Vs; Vadc = Vadc * divisor * vOffset; diff --git a/Firmware/Modulos/SensorMassaModel.h b/Firmware/Modulos/SensorMassaModel.h index ca281e319..9cdeac33b 100644 --- a/Firmware/Modulos/SensorMassaModel.h +++ b/Firmware/Modulos/SensorMassaModel.h @@ -30,6 +30,7 @@ class SensorMassa : public ComponenteCAN { SimpleKalmanFilter filtro = SimpleKalmanFilter(0.05, 0.05, 0.25); float Massa = 0; + float leitura = 0; bool Iniciado = false; @@ -85,8 +86,8 @@ class SensorMassa : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { uint16_t massaEscalada = (uint16_t)(Massa * 100); - data.push_back(massaEscalada >> 8); - data.push_back(massaEscalada & 0xFF); + data.push_back(leitura >> 8); data.push_back(leitura & 0xFF); + data.push_back(massaEscalada >> 8); data.push_back(massaEscalada & 0xFF); break; } } @@ -147,9 +148,10 @@ class SensorMassa : public ComponenteCAN { private: void AferirMassa() { if (Iniciado) { - float leitura = -balanca.get_units(5); - leitura += _OffsetMassa; - Massa = filtro.updateEstimate(leitura); + leitura = balanca.get_units(5); + float _leitura = -leitura; + _leitura += _OffsetMassa; + Massa = filtro.updateEstimate(_leitura); } } diff --git a/Firmware/Modulos/SensorPressaoModel.h b/Firmware/Modulos/SensorPressaoModel.h index 166d678a3..5d17cfa84 100644 --- a/Firmware/Modulos/SensorPressaoModel.h +++ b/Firmware/Modulos/SensorPressaoModel.h @@ -25,7 +25,7 @@ class SensorPressao : public ComponenteCAN { double _Vmax = 4.5; double _Pmax = 174.045; - double leitura = 0; + int leitura = 0; double Pressao = 0; SimpleKalmanFilter filtro = SimpleKalmanFilter(2, 2, 0.01); @@ -80,8 +80,8 @@ class SensorPressao : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { uint16_t pressaoEscalada = (uint16_t)(Pressao * 100); - data.push_back(pressaoEscalada >> 8); - data.push_back(pressaoEscalada & 0xFF); + data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF)); + data.push_back(pressaoEscalada >> 8); data.push_back(pressaoEscalada & 0xFF); break; } } diff --git a/Firmware/Modulos/SensorTemperaturaModel.h b/Firmware/Modulos/SensorTemperaturaModel.h index 0dd84a62a..1ce00b44b 100644 --- a/Firmware/Modulos/SensorTemperaturaModel.h +++ b/Firmware/Modulos/SensorTemperaturaModel.h @@ -21,7 +21,7 @@ class SensorTemperatura : public ComponenteCAN { int ID_Num; PinoModel _pino; - double leitura = 0; + int leitura = 0; double temperatura = -1; double tensao = 0; @@ -73,8 +73,8 @@ class SensorTemperatura : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { int16_t leituraInt = static_cast(round(temperatura * 100.0f)); - data.push_back((uint8_t)(leituraInt >> 8)); - data.push_back((uint8_t)(leituraInt & 0xFF)); + data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF)); + data.push_back((uint8_t)(leituraInt >> 8)); data.push_back((uint8_t)(leituraInt & 0xFF)); break; } } diff --git a/Firmware/Modulos/ServoAgroModel.h b/Firmware/Modulos/ServoAgroModel.h new file mode 100644 index 000000000..43bdd41ea --- /dev/null +++ b/Firmware/Modulos/ServoAgroModel.h @@ -0,0 +1,181 @@ +#include "SerialService.h" +#include "Pinout.h" +#include "Utils.h" +#include "IComponenteCAN.h" +#include + +#ifndef ServoAgroModel +#define ServoAgroModel + +class ServoAgro : public ComponenteCAN { + public: + + ServoAgro(String _modID, String _id) { + Mod_ID = _modID; + _ID = _id; + } + + String Mod_ID; + String _ID; + int ID_Num; + PinoModel _pino; + + bool Incremental = true; + + bool Iniciado = false; + + int _Angulo = 0; + + Servo _Servo; + + void Inicializar() { + if (Iniciado) { + MostrarLog("Servo ja inicializado"); + return; + } + + if (_pino.Definido()) { + _Servo.attach(_pino.num); + AtualizarAngulo(Incremental ? 0 : 180); + + Iniciado = true; + + MostrarLog("Servo iniciado"); + } + else { + MostrarLog("Servo nao iniciado"); + } + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Servo nao esta inicializado"); + return; + } + + // Redefinir as configurações para os valores iniciais + if (_pino.Definido()) { + _Servo.detach(); + } + + MostrarLog("Servo Desligado"); + + Iniciado = false; + } + + void AtualizarAngulo(int novoAngulo) { + if (Iniciado) { + MostrarLog("Angulo atualizado de " + String(_Angulo) + " para " + String(novoAngulo)); + + _Angulo = novoAngulo; + + _Servo.write(_Angulo); + } + } + + void RequisitarDados() { + + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + case CanMessagePosicaoDados::Dados1: { + data.push_back(_Angulo); // 0 a 180 + break; + } + } + return data; + } + + static std::vector ConfigurarServo(std::vector& lista, std::vector& data, const String& Mod_ID) { + std::vector status; + if (data.size() < 2) return status; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + auto it = std::find_if(lista.begin(), lista.end(), [idNum](ServoAgro* s) { return s->ID_Num == idNum; }); + bool jaExiste = it != lista.end(); + ServoAgro* sensor; + switch (posicao) { + case CanMessagePosicaoDados::Config1: { + if (data.size() < 7) return status; + bool conectar = data[3] == 1; + bool incremental = data[4] == 1; + TiposBarramentos tipoBarramento = (TiposBarramentos)data[5]; + int pino = data[6]; + if (conectar) { + if (!jaExiste) { + sensor = new ServoAgro(Mod_ID, "sSRV_" + String(idNum)); + } + else { + sensor = *it; + } + if (!sensor->Iniciado) { + sensor->ID_Num = idNum; + sensor->Incremental = incremental; + sensor->_pino = PinoModel(pino, tipoBarramento, _OUTPUT); + sensor->Inicializar(); + if (!jaExiste) { + lista.push_back(sensor); + sensor->MostrarLog("Servo adicionado via CAN: sSRV_" + String(idNum)); + } + } + status = sensor->MontarMensagemCAN(CanMessagePosicaoDados::Status); + } else { + if (jaExiste) { + sensor = *it; + sensor->Desligar(); + status = sensor->MontarMensagemCAN(CanMessagePosicaoDados::Status); + sensor->MostrarLog("Servo removido via CAN: sSRV_" + String(idNum)); + delete sensor; + lista.erase(it); + } + } + break; + } + } + return status; + } + + static void ComandarServo(std::vector& lista, std::vector& data) { + if (data.size() < 3) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + for (auto* _servo : lista) { + if (_servo->ID_Num == idNum) { + switch (posicao) { + case CanMessagePosicaoDados::Command1: { + int novoAngulo = (int)data[2]; + _servo->AtualizarAngulo(novoAngulo); + break; + } + } + return; + } + } + } + + + private: + bool DebugMode = false; + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[SRV " + _ID + "] " + mensagem); + } + } + +}; + + + + + + +#endif \ No newline at end of file diff --git a/Firmware/Sensoriamento/Sensoriamento_v21/.theia/launch.json b/Firmware/Sensoriamento/Sensoriamento_v21/.theia/launch.json new file mode 100644 index 000000000..9a49ac9ff --- /dev/null +++ b/Firmware/Sensoriamento/Sensoriamento_v21/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Firmware/Sensoriamento/Sensoriamento_v21/Sensoriamento_v21.ino b/Firmware/Sensoriamento/Sensoriamento_v21/Sensoriamento_v21.ino new file mode 100644 index 000000000..ef89f540a --- /dev/null +++ b/Firmware/Sensoriamento/Sensoriamento_v21/Sensoriamento_v21.ino @@ -0,0 +1,464 @@ +// Dispositivo: Sensoriamento +// Versão Firmware: 21 +// Ultima atualização: 16/12/2025 +// Atualização: Padronizado uso do componente ServoAgro + +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\CanService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\LoRaService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\I2CService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorTemperaturaModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorCorrenteModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorIMUModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SinaleiroModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ReleModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ServoAgroModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorGasModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorTemperaturaSHTModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorLuminosidadeModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorLuzUVModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorQualidadeArModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorChuvaModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMagneticoModel.h" + + +// Configurações do CAN +uint8_t CanID = 0x11; +CanService canService(CanID); + +LoRaService loraService(&canService); + +#define D_Code Sen +int VERSION = 21; +String Mod_ID = "Sen"; + +#define _pinoLED RGB_BUILTIN + +bool Conectado = false; +bool Conectar = false; + +int _TaxaAmostragem = 1000; +volatile bool RequisitarDados = false; +int latenciaLoop = 0; +int qtdEnviosStatus = 0; +int maxEnviosStatus = 5; + +std::vector listaSensoresTemperaturaNTC; +std::vector listaSensoresCorrente; +std::vector listaSinaleiros; +std::vector listaReles; +std::vector listaServos; +std::vector listaSensoresIMU; +std::vector listaSensoresGas; +std::vector listaSensoresTemperaturaSHT; +std::vector listaSensoresLuminosidade; +std::vector listaSensoresLuzUV; +std::vector listaSensoresQualidadeAr; +std::vector listaSensoresChuva; +std::vector listaSensoresMagneticos; + +void MostrarLog(String mensagem) { + bool _debugMode = false; + if (_debugMode) { + PrintTela(String("[SEN] ") + mensagem); + } +} + +void inicializarDependenciasI2C() { + I2CService::IniciarI2C(); + I2CService::IniciarMUX(); + I2CService::IniciarMCP(); +} + +void setup() { + delay(2000); + + inicializarDependenciasI2C(); + + // Registrar callback para processar mensagens CAN recebidas + canService.setReceiveCallback([](int packetSize, int senderId, CanMessagePosicaoDados posicao, byte* data, int dataLength) { + std::vector fullData; + fullData.push_back(static_cast(posicao)); // Primeiro byte é sempre a posicao + for (int i = 0; i < dataLength; i++) { + fullData.push_back(data[i]); + } + + ProcessarFrameCAN(posicao, fullData); + }); + + canService.begin(); +} + +void loop() { + if (!RequisitarDados) { + enviarLogsPeriodicamente(); + } + + delay(1); +} + +// Função para enviar logs do sensor periodicamente +unsigned long ultimoEnvioLogs = 0; +const unsigned long intervaloEnvioLogs = 1000; // 1 segundo +void enviarLogsPeriodicamente() { + unsigned long tempoAtual = millis(); + // Verifica se o intervalo de 5 segundos já passou + if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) { + ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio + + enviarDadosSensores(canService.ID_Num_sTOD, CanMessagePosicaoDados::DadosAll); + } +} + +void enviarDadosSensores(uint8_t id_num, CanMessagePosicaoDados posicao) { + if (Conectado || posicao == CanMessagePosicaoDados::Status) { + unsigned long startLoop = millis(); + + bool enviarStatus = qtdEnviosStatus >= maxEnviosStatus && posicao != CanMessagePosicaoDados::Status; + bool todosDados = posicao == CanMessagePosicaoDados::DadosAll; + bool todosIDs = id_num == canService.ID_Num_sTOD; + + if (id_num == canService.ID_Num_sMOD) { + EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION)); + return; + } + + if (id_num == canService.ID_Num_sLRA) { + EnviarDadosCAN(loraService.MontarMensagemCAN(posicao)); + return; + } + + MostrarLog("Atualizando dados dos sensores..."); + + if (todosIDs && enviarStatus) { + EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION)); + EnviarDadosCAN(loraService.MontarMensagemCAN(CanMessagePosicaoDados::Status)); + } + + ComponenteCAN::ProcessarComponentesCAN(listaSensoresTemperaturaNTC, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresCorrente, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSinaleiros, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaReles, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaServos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresGas, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresTemperaturaSHT, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresLuminosidade, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresLuzUV, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresQualidadeAr, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresChuva, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresIMU, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponentesCAN(listaSensoresMagneticos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + if (enviarStatus) { + qtdEnviosStatus = 0; + } + else { + qtdEnviosStatus++; + } + + latenciaLoop = millis() - startLoop; + + if (posicao == CanMessagePosicaoDados::DadosAll) { + EnviarDadosCAN(canService.MontarFrameReqDadosFim(latenciaLoop)); + } + + MostrarLog("Ciclo concluido, latencia de loop: " + String(latenciaLoop)); + } +} + +void EnviarDadosCAN(std::vector data) { + if (data.size() > 2) { + canService.adicionarMensagemFila(data); + } +} + +void ProcessarFrameCAN(CanMessagePosicaoDados posicao, std::vector data) { + if (data.size() < 1) return; + + F_Code funcao = canService.FuncaoPorPosicao(posicao); + + switch (funcao) { + case F_Code::ReqTx: ProcessarReq(data); break; + case F_Code::CmdTx: ProcessarCmd(data); break; + case F_Code::CfgTx: ProcessarCfg(data); break; + } +} + +void ProcessarReq(std::vector data) { + if (data.size() < 2) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + enviarDadosSensores(id, posicao); +} + +void ProcessarCfg(std::vector data) { + if (data.size() < 4) return; + std::vector _chkRx; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + S_Code componente = DetectarComponente(id); + if (componente == S_Code::sMOD) { + switch (posicao) { + case CanMessagePosicaoDados::Config1: { + if (data.size() < 8) return; + bool conectar = data[2] == 1; + int taxa = data[3] * 10; + bool requisitar = data[4] == 1; + loraService.AddressBase = data[5]; + int pinoSDA = data[6]; + int pinoSCL = data[7]; + + _TaxaAmostragem = taxa; + RequisitarDados = requisitar; + + LimparListasComponentes(); + + if (pinoSDA != PINO_INVALIDO && pinoSCL != PINO_INVALIDO) { + if (I2CService::DefinirPinos(pinoSDA, pinoSCL) || !I2CService::I2CIniciado) { + inicializarDependenciasI2C(); + } + } + + vTaskDelay(pdMS_TO_TICKS(100)); + + Conectado = conectar; + _chkRx = canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION); + + MostrarLog("Configuracao do modulo concluida"); + break; + } + } + } + if (componente == S_Code::sLRA) { + _chkRx = loraService.ConfigurarModulo(data); + } + else { + componente = (S_Code)data[2]; + switch (componente) { + case sNTC: { + _chkRx = SensorTemperatura::ConfigurarSensor(listaSensoresTemperaturaNTC, data, Mod_ID); + break; + } + case sCOR: { + _chkRx = SensorCorrente::ConfigurarSensor(listaSensoresCorrente, data, Mod_ID); + break; + } + case sLED: { + _chkRx = Sinaleiro::ConfigurarSinaleiro(listaSinaleiros, data, Mod_ID); + break; + } + case sRLE: { + _chkRx = Rele::ConfigurarRele(listaReles, data, Mod_ID); + break; + } + case sSRV: { + _chkRx = ServoAgro::ConfigurarServo(listaServos, data, Mod_ID); + break; + } + case sIMU: { + _chkRx = SensorIMU::ConfigurarSensor(listaSensoresIMU, data, Mod_ID); + break; + } + case sGAS: { + _chkRx = SensorGas::ConfigurarSensor(listaSensoresGas, data, Mod_ID); + break; + } + case sSHT: { + _chkRx = SensorTemperaturaSHT::ConfigurarSensor(listaSensoresTemperaturaSHT, data, Mod_ID); + break; + } + case sLUZ: { + _chkRx = SensorLuminosidade::ConfigurarSensor(listaSensoresLuminosidade, data, Mod_ID); + break; + } + case sIUV: { + _chkRx = SensorLuzUV::ConfigurarSensor(listaSensoresLuzUV, data, Mod_ID); + break; + } + case sQAR: { + _chkRx = SensorQualidadeAr::ConfigurarSensor(listaSensoresQualidadeAr, data, Mod_ID); + break; + } + case sCHV: { + _chkRx = SensorChuva::ConfigurarSensor(listaSensoresChuva, data, Mod_ID); + break; + } + case sMAG: { + _chkRx = SensorMagnetico::ConfigurarSensor(listaSensoresMagneticos, data, Mod_ID); + break; + } + } + } + + EnviarDadosCAN(_chkRx); +} + +void ProcessarCmd(std::vector data) { + if (data.size() < 2) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + S_Code componente = DetectarComponente(id); + switch (componente) { + case sLED: { + Sinaleiro::ComandarSinaleiro(listaSinaleiros, data); + break; + } + case sRLE: { + Rele::ComandarRele(listaReles, data); + break; + } + case sSRV: { + ServoAgro::ComandarServo(listaServos, data); + break; + } + case sLRA: { + loraService.EnviarComando(data); + break; + } + default: + break; + } +} + +void LimparListasComponentes() { + for (auto* rele : listaReles) { + rele->Desligar(); + MostrarLog("Rele " + rele->_ID + " desligado."); + delete rele; + } + listaReles.clear(); + + for (auto* sinaleiro : listaSinaleiros) { + sinaleiro->Desligar(); + MostrarLog("Sinaleiro " + sinaleiro->_ID + " desligado."); + delete sinaleiro; + } + listaSinaleiros.clear(); + + for (auto* servo : listaServos) { + servo->Desligar(); + MostrarLog("Servo " + servo->_ID + " desligado."); + delete servo; + } + listaServos.clear(); + + for (auto* sensor : listaSensoresCorrente) { + sensor->Desligar(); + MostrarLog("Sensor de Corrente " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresCorrente.clear(); + + for (auto* sensor : listaSensoresTemperaturaNTC) { + sensor->Desligar(); + MostrarLog("Sensor de Temperatura " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresTemperaturaNTC.clear(); + + for (auto* sensor : listaSensoresIMU) { + sensor->Desligar(); + MostrarLog("Sensor IMU " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresIMU.clear(); + + for (auto* sensor : listaSensoresGas) { + sensor->Desligar(); + MostrarLog("Sensor de gas " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresGas.clear(); + + for (auto* sensor : listaSensoresTemperaturaSHT) { + sensor->Desligar(); + MostrarLog("Sensor de temperatura e umidade " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresTemperaturaSHT.clear(); + + for (auto* sensor : listaSensoresLuminosidade) { + sensor->Desligar(); + MostrarLog("Sensor de luminosidade " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresLuminosidade.clear(); + + for (auto* sensor : listaSensoresLuzUV) { + sensor->Desligar(); + MostrarLog("Sensor de luz UV " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresLuzUV.clear(); + + for (auto* sensor : listaSensoresQualidadeAr) { + sensor->Desligar(); + MostrarLog("Sensor de qualidade do ar " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresQualidadeAr.clear(); + + for (auto* sensor : listaSensoresChuva) { + sensor->Desligar(); + MostrarLog("Sensor de chuva " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresChuva.clear(); + + for (auto* sensor : listaSensoresMagneticos) { + sensor->Desligar(); + MostrarLog("Sensor magnetico " + sensor->_ID + " desligado."); + delete sensor; + } + listaSensoresMagneticos.clear(); + +} + +S_Code DetectarComponente(uint8_t idNum) { + if (idNum == canService.ID_Num_sMOD) return S_Code::sMOD; + if (idNum == canService.ID_Num_sTOD) return S_Code::sTOD; + if (idNum == canService.ID_Num_sLRA) return S_Code::sLRA; + for (auto* s : listaSensoresTemperaturaNTC) { + if (s->ID_Num == idNum) return S_Code::sNTC; + } + for (auto* s : listaSensoresCorrente) { + if (s->ID_Num == idNum) return S_Code::sCOR; + } + for (auto* s : listaSinaleiros) { + if (s->ID_Num == idNum) return S_Code::sLED; + } + for (auto* s : listaReles) { + if (s->ID_Num == idNum) return S_Code::sRLE; + } + for (auto* s : listaServos) { + if (s->ID_Num == idNum) return S_Code::sSRV; + } + for (auto* s : listaSensoresIMU) { + if (s->ID_Num == idNum) return S_Code::sIMU; + } + for (auto* s : listaSensoresGas) { + if (s->ID_Num == idNum) return S_Code::sGAS; + } + for (auto* s : listaSensoresTemperaturaSHT) { + if (s->ID_Num == idNum) return S_Code::sSHT; + } + for (auto* s : listaSensoresLuminosidade) { + if (s->ID_Num == idNum) return S_Code::sLUZ; + } + for (auto* s : listaSensoresLuzUV) { + if (s->ID_Num == idNum) return S_Code::sIUV; + } + for (auto* s : listaSensoresQualidadeAr) { + if (s->ID_Num == idNum) return S_Code::sQAR; + } + for (auto* s : listaSensoresChuva) { + if (s->ID_Num == idNum) return S_Code::sCHV; + } + for (auto* s : listaSensoresMagneticos) { + if (s->ID_Num == idNum) return S_Code::sMAG; + } + return S_Code::sVZO; +}