diff --git a/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs b/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs index 767d8dc9f..cb218a820 100644 --- a/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs @@ -257,14 +257,7 @@ namespace AgroBase.Models.Modules { byte addrTx = Modulo.MovMotor._EnderecoCAN_Tx; byte addrRx = Modulo.MovMotor._EnderecoCAN_Rx; - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.VelocidadeAtual); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.Potencia); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.Temperatura); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.CicloTrabalho); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.CodErro); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.CorrenteBarramento); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.CorrenteMotor); - OIDCanService.RequisitarDado(addrTx, addrRx, OIDCanService.OidHandler.OidParametros.Tensao); + OIDCanService.RequisitarProximoDado(addrTx, addrRx); Modulo.MovMotor.RequisitarDadosSensoresExternos(); var Controle = Variaveis.OperacaoEmAndamento.Controle.TiposControle?.FirstOrDefault(x => x.Tipo == T_Code.Mov); diff --git a/AgroBase/AgroBase/Services/CanServiceEthernet.cs b/AgroBase/AgroBase/Services/CanServiceEthernet.cs index 49a7d66ed..9f78f0c52 100644 --- a/AgroBase/AgroBase/Services/CanServiceEthernet.cs +++ b/AgroBase/AgroBase/Services/CanServiceEthernet.cs @@ -797,7 +797,68 @@ namespace AgroBase.Services { _roteadores.TryGetValue(id, out ICanMessageHandler handler); - T_Code dispositivo = handler?.Dispositivo ?? T_Code.Vzo; + if (handler == null) + { + /* + * Fallback para OID/par Tx-Rx: + * Se o frame chegou pelo ID de TX do pendente, talvez não exista + * roteador registrado exatamente nesse ID. Tenta achar o handler + * pelo dispositivo pendente. + */ + T_Code? dispositivoPendente = null; + + lock (_LockMensagens) + { + dispositivoPendente = + MensagensPendentes + .Where(x => + x.ComResposta && + x.Enviado && + !x.Respondido && + ( + x.IdRx == id || + x.IdTx == id + )) + .OrderBy(x => x.EnviadoEm) + .Select(x => (T_Code?)x.Dispositivo) + .FirstOrDefault(); + } + + if (dispositivoPendente.HasValue) + { + handler = + _roteadores + .Values + .FirstOrDefault( + h => h.Dispositivo == dispositivoPendente.Value + ); + } + } + + T_Code dispositivo = + handler?.Dispositivo ?? T_Code.Vzo; + + if (dispositivo == T_Code.Vzo) + { + lock (_LockMensagens) + { + var pendente = + MensagensPendentes + .Where(x => + x.ComResposta && + x.Enviado && + !x.Respondido && + ( + x.IdRx == id || + x.IdTx == id + )) + .OrderBy(x => x.EnviadoEm) + .FirstOrDefault(); + + if (pendente != null) + dispositivo = pendente.Dispositivo; + } + } bool db = dispositivo == T_Code.Bat; byte fCodeRx = db ? (byte)DalyBMSService.GetDataId(id) : data.Length > 0 ? data[0] : (byte)0x00; @@ -854,7 +915,11 @@ namespace AgroBase.Services } } - private bool MensagemCorrespondeResposta(CanMessage pendente, T_Code dispositivoResposta, uint idResposta, byte[] dataResposta) + private bool MensagemCorrespondeResposta( + CanMessage pendente, + T_Code dispositivoResposta, + uint idResposta, + byte[] dataResposta) { if (pendente == null) return false; @@ -871,9 +936,6 @@ namespace AgroBase.Services if (pendente.Dispositivo != dispositivoResposta) return false; - if (pendente.IdRx != idResposta) - return false; - byte[] dataTx = pendente.DataTx ?? new byte[0]; @@ -884,32 +946,45 @@ namespace AgroBase.Services { case T_Code.Bat: /* - * Daly: DataID vem no CAN ID, então idRx já fechou. + * Daly usa DataID no CAN ID estendido. */ - return true; + return pendente.IdRx == idResposta; case T_Code.Mks: return + pendente.IdRx == idResposta && dataRx.Length > 0 && pendente.funcCodeRx == dataRx[0]; case T_Code.Oid: - /* - * OID: - * consulta retorna DATA[0]=0x0F e DATA[1]=param. - */ - return - dataRx.Length >= 2 && - dataTx.Length >= 2 && - dataRx[0] == pendente.funcCodeRx && - dataRx[1] == dataTx[1]; + { + /* + * OID pode responder no mesmo ID do comando ou no par lógico RX. + */ + bool idOk = + pendente.IdRx == idResposta || + pendente.IdTx == idResposta; + + if (!idOk) + return false; + + /* + * Consulta OID: + * TX: DATA[0]=0x0F, DATA[1]=param + * RX: DATA[0]=0x0F, DATA[1]=param, DATA[2..]=valor + */ + return + dataRx.Length >= 2 && + dataTx.Length >= 2 && + dataRx[0] == pendente.funcCodeRx && + dataRx[1] == dataTx[1]; + } case T_Code.Atu: case T_Code.Sen: - /* - * ATU/SEN: - * casa pelo func/posição e, quando existir, pelo ID_Num. - */ + if (pendente.IdRx != idResposta) + return false; + if (dataRx.Length <= 0) return false; @@ -922,6 +997,9 @@ namespace AgroBase.Services return true; default: + if (pendente.IdRx != idResposta) + return false; + if (dataRx.Length <= 0) return false; diff --git a/AgroBase/AgroBase/Services/OIDCanService.cs b/AgroBase/AgroBase/Services/OIDCanService.cs index c87b1cc5c..c2eec9eeb 100644 --- a/AgroBase/AgroBase/Services/OIDCanService.cs +++ b/AgroBase/AgroBase/Services/OIDCanService.cs @@ -139,7 +139,7 @@ namespace AgroBase.Services public static int TaxaAmostragem { - get { return 1000; } + get { return 60; } } public static async Task VerificaDispositivoConectado() @@ -170,7 +170,7 @@ namespace AgroBase.Services byte idRx = modulo.MovMotor._EnderecoCAN_Rx; - RegistrarHandler(idRx); + RegistrarHandlersMotor(idTx, idRx); EnviarComandoDescoberta(idTx, idRx); @@ -217,7 +217,10 @@ namespace AgroBase.Services if (modulo == null) continue; - RegistrarHandler(modulo._EnderecoCAN_Rx); + RegistrarHandlersMotor( + modulo._EnderecoCAN_Tx, + modulo._EnderecoCAN_Rx + ); var leitura = DadosLeitura.FirstOrDefault( @@ -305,11 +308,19 @@ namespace AgroBase.Services } } + private static void RegistrarHandlersMotor(byte idTx, byte idRx) + { + RegistrarHandler(idTx); + + if (idRx != idTx) + RegistrarHandler(idRx); + } + #region COMANDOS private static void EnviarComandoDescoberta(byte idTx, byte idRx) { - RegistrarHandler(idRx); + RegistrarHandlersMotor(idTx, idRx); CanManager.CanService.AdicionarMensagemNaFila( Dispositivo, @@ -333,7 +344,7 @@ namespace AgroBase.Services bool get = true, bool contabilizarTimeoutHealth = true) { - RegistrarHandler(idRx); + RegistrarHandlersMotor(idTx, idRx); CanManager.CanService.AdicionarMensagemNaFila( dispositivo, @@ -420,6 +431,17 @@ namespace AgroBase.Services _ultimaConsultaPendente[idTx] = dado; } + Console.WriteLine( + "[OID/TX] idTx=" + + idTx.ToString("X2") + + " idRx=" + + idRx.ToString("X2") + + " param=" + + dado + + " data=0F-" + + ((byte)dado).ToString("X2") + ); + EnviarComando( Dispositivo, idTx, @@ -447,6 +469,22 @@ namespace AgroBase.Services dado == OidParametros.CorrenteBarramento; } + public static void RequisitarProximoDado(byte idTx, byte idRx) + { + OidParametros parametro = + EscolherProximoParametro(idTx) ?? + OidParametros.VelocidadeAtual; + + RequisitarDadoInterno( + idTx, + idRx, + parametro, + forcar: false, + contabilizarTimeoutHealth: + DeveContabilizarTimeoutHealth(parametro) + ); + } + public static void AtualizarDados() { try @@ -996,30 +1034,98 @@ namespace AgroBase.Services SinalZNaoEncontrado = 19 } - private OIDModel ObterOuCriar(uint _idTx, uint _idRx) + private OIDModel ObterOuCriar(CanMessage mensagem) { lock (DadosLeitura) { - byte idTx = - CanManager.ConverterIdCan(_idTx)[0]; + byte idTxMsg = + CanManager.ConverterIdCan( + mensagem.IdTx + )[0]; - byte idRx = - CanManager.ConverterIdCan(_idRx)[0]; + byte idRxMsg = + CanManager.ConverterIdCan( + mensagem.IdRx + )[0]; + /* + * Primeiro, tenta achar pelo par exato. + */ var item = DadosLeitura.FirstOrDefault( - x => x.EnderecoTx == idTx && - x.EnderecoRx == idRx + x => x.EnderecoTx == idTxMsg && + x.EnderecoRx == idRxMsg + ); + + if (item != null) + return item; + + /* + * Depois, tenta achar pelo motor configurado. + * Isso evita criar leitura órfã quando o OID responde no mesmo ID + * usado como Tx ou em outro ID lógico. + */ + var motor = + Variaveis + .OperacaoEmAndamento + .DispMvd? + .Dados? + .Modulos? + .Select(x => x?.MovMotor) + .FirstOrDefault(m => + m != null && + ( + m._EnderecoCAN_Tx == idTxMsg || + m._EnderecoCAN_Rx == idTxMsg || + m._EnderecoCAN_Tx == idRxMsg || + m._EnderecoCAN_Rx == idRxMsg + ) + ); + + if (motor != null) + { + item = + DadosLeitura.FirstOrDefault( + x => x.EnderecoTx == motor._EnderecoCAN_Tx + ); + + if (item == null) + { + item = new OIDModel + { + EnderecoTx = motor._EnderecoCAN_Tx, + EnderecoRx = motor._EnderecoCAN_Rx + }; + + DadosLeitura.Add(item); + } + else + { + item.EnderecoRx = motor._EnderecoCAN_Rx; + } + + return item; + } + + /* + * Fallback final. + */ + item = + DadosLeitura.FirstOrDefault( + x => + x.EnderecoTx == idTxMsg || + x.EnderecoRx == idTxMsg || + x.EnderecoTx == idRxMsg || + x.EnderecoRx == idRxMsg ); if (item == null) { - item = - new OIDModel - { - EnderecoTx = idTx, - EnderecoRx = idRx - }; + item = new OIDModel + { + EnderecoTx = idTxMsg, + EnderecoRx = idRxMsg + }; DadosLeitura.Add(item); } @@ -1052,11 +1158,7 @@ namespace AgroBase.Services return; } - var item = - ObterOuCriar( - mensagem.IdTx, - mensagem.IdRx - ); + var item = ObterOuCriar(mensagem); if (func == OidFuncCode.ConsultaStatusRetornoZero) { @@ -1070,6 +1172,15 @@ namespace AgroBase.Services return; } + Console.WriteLine( + "[OID/RX] idTx=" + + mensagem.IdTx.ToString("X") + + " idRx=" + + mensagem.IdRx.ToString("X") + + " data=" + + BitConverter.ToString(mensagem.DataRx ?? new byte[0]) + ); + OidParametros parametro = (OidParametros)mensagem.DataRx[1]; @@ -1084,9 +1195,8 @@ namespace AgroBase.Services lock (_sync) { - _ultimaConsultaPendente.Remove( - item.EnderecoTx - ); + _ultimaConsultaPendente.Remove(item.EnderecoTx); + _ultimaConsultaPendente.Remove(item.EnderecoRx); } } catch (Exception ex) @@ -1223,4 +1333,4 @@ namespace AgroBase.Services model.ModoControle = modo; } } -} +} \ No newline at end of file diff --git a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs index 4995d3e4f..cc7c24f7a 100644 --- a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs +++ b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs @@ -428,7 +428,7 @@ namespace AgroBase.Services.Operadores RedisService.ModKey(Enums.T_Code.Mov), ($"{endereco_mov}.timestamp", agora), ($"{endereco_mov}.conectado", mod.MovMotor.Inicializado), - ($"{endereco_mov}.freq_base", Variaveis.OperacaoEmAndamento.DispMvd.Dados.tmrRegistradorMOV.IntervalHz), + ($"{endereco_mov}.freq_base", 1), ($"{endereco_mov}.endereco", mod.MovMotor._EnderecoCAN_Tx), ($"{endereco_mov}.mod_id", mod.Modulo_ID), ($"{endereco_mov}.cod_erro", mod.MovMotor.CodigoAlarme),