revisado fluxo completo do direcional
This commit is contained in:
parent
e8cdb27687
commit
a5586d3ed1
|
|
@ -428,28 +428,22 @@ namespace AgroBase.Models.Modules
|
|||
|
||||
DateTime agora = DateTime.Now;
|
||||
|
||||
if (!MKS057DCanService.Iniciado && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Dir))
|
||||
{
|
||||
foreach (var leitura in MKS057DCanService.DadosLeitura.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < agora))
|
||||
{
|
||||
/*
|
||||
* Poke leve para tentar recuperar leitura.
|
||||
* O MKS057DCanService agora já segura throttle interno.
|
||||
* Toda a manutenção da comunicação com os MKS fica concentrada
|
||||
* no MKS057DCanService:
|
||||
*
|
||||
* - polling dos drivers online;
|
||||
* - throttle por driver/parâmetro;
|
||||
* - prioridade durante referenciamento;
|
||||
* - identificação de drivers sem resposta;
|
||||
* - marcação individual como offline;
|
||||
* - tentativa periódica de reconexão dos drivers offline.
|
||||
*
|
||||
* O timer não precisa mais fazer poke ou polling individual.
|
||||
*/
|
||||
MKS057DCanService.RequisitarDado(
|
||||
leitura.EnderecoTx,
|
||||
leitura.EnderecoRx,
|
||||
MKS057DCanService.MksHandler.MksFuncCode.PulsosRecebidos
|
||||
);
|
||||
}
|
||||
|
||||
tmrRegistradorDIR.SetInterval(1000);
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
MKS057DCanService.AtualizarDados();
|
||||
|
||||
bool deveEnviarControle = _ultimoEnvioControleDir == DateTime.MinValue || agora - _ultimoEnvioControleDir >= IntervaloControleDir;
|
||||
|
||||
bool deveRequisitarSensoresExternos = _ultimoSensoresExternosDir == DateTime.MinValue || agora - _ultimoSensoresExternosDir >= IntervaloSensoresExternosDir;
|
||||
|
||||
bool enviouControle = false;
|
||||
|
|
@ -459,43 +453,43 @@ namespace AgroBase.Models.Modules
|
|||
|
||||
foreach (var modulo in Modulos)
|
||||
{
|
||||
if (modulo?.DirMotor == null || !modulo.DirMotor.Inicializado)
|
||||
var driver = modulo?.DirMotor;
|
||||
|
||||
if (driver == null || !driver.Inicializado)
|
||||
continue;
|
||||
|
||||
byte addrTx = modulo.DirMotor._EnderecoCAN_Tx;
|
||||
byte addrRx = modulo.DirMotor._EnderecoCAN_Rx;
|
||||
|
||||
/*
|
||||
* Agora é igual ao MOV/OID:
|
||||
* o service escolhe PulsosRecebidos, IO, RPM, ErroAcumulado etc.
|
||||
* com throttle, cursor e prioridade de referenciamento.
|
||||
*/
|
||||
MKS057DCanService.RequisitarProximoDado(addrTx, addrRx);
|
||||
|
||||
/*
|
||||
* Se isso também gera CAN, melhor não chamar em todo tick.
|
||||
* Se for leitura local/barata, pode voltar para todo tick.
|
||||
* Sensores externos do direcional.
|
||||
*
|
||||
* Mantemos o throttle de 500 ms para não gerar tráfego
|
||||
* desnecessário no sensoriamento.
|
||||
*/
|
||||
if (deveRequisitarSensoresExternos)
|
||||
{
|
||||
modulo.DirMotor.RequisitarDadosSensoresExternos();
|
||||
driver.RequisitarDadosSensoresExternos();
|
||||
requisitouSensoresExternos = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenvio de controle direcional.
|
||||
* Reenvio periódico do comando enquanto o ângulo solicitado
|
||||
* ainda não foi atingido.
|
||||
*
|
||||
* Não precisa mais reenviar no ritmo da TaxaAmostragem.
|
||||
* O MKS057DCanService já tem dedupe curto, mas ainda assim
|
||||
* é melhor não transformar posição em metralhadora CAN.
|
||||
* Durante referenciamento não interferimos no comando,
|
||||
* pois o próprio fluxo de referência assume o controle do MKS.
|
||||
*/
|
||||
if (!MKS057DCanService.Referenciando && deveEnviarControle && controleDir != null && !modulo.DirMotor.AtingiuAnguloSP)
|
||||
if (!MKS057DCanService.Referenciando && deveEnviarControle && controleDir != null && !driver.AtingiuAnguloSP)
|
||||
{
|
||||
modulo.DirMotor.EnviarComandoControle(controleDir.UltimaDirecao);
|
||||
driver.EnviarComandoControle(controleDir.UltimaDirecao);
|
||||
enviouControle = true;
|
||||
}
|
||||
|
||||
modulo.DirMotor.AtualizarSaudeSeguimentoAngular(agora);
|
||||
/*
|
||||
* Atualização do acompanhamento angular.
|
||||
*
|
||||
* Saúde global será validada em outro tópico, mas mantemos
|
||||
* aqui o comportamento já existente.
|
||||
*/
|
||||
driver.AtualizarSaudeSeguimentoAngular(agora);
|
||||
}
|
||||
|
||||
if (enviouControle)
|
||||
|
|
@ -504,6 +498,10 @@ namespace AgroBase.Models.Modules
|
|||
if (requisitouSensoresExternos)
|
||||
_ultimoSensoresExternosDir = agora;
|
||||
|
||||
/*
|
||||
* Normalmente 80 ms.
|
||||
* Durante referenciamento, 40 ms.
|
||||
*/
|
||||
tmrRegistradorDIR.SetInterval(MKS057DCanService.TaxaAmostragem);
|
||||
|
||||
await Task.CompletedTask;
|
||||
|
|
|
|||
|
|
@ -48,10 +48,13 @@ namespace AgroBase.Services
|
|||
*/
|
||||
|
||||
private static readonly TimeSpan TempoRespostaRecente = TimeSpan.FromSeconds(3);
|
||||
private static readonly TimeSpan TempoRemoverDriver = TimeSpan.FromSeconds(15);
|
||||
private static readonly TimeSpan TempoRemoverDriver = TimeSpan.FromSeconds(5);
|
||||
private static readonly TimeSpan TempoRespostaDescoberta = TimeSpan.FromMilliseconds(700);
|
||||
private static readonly TimeSpan JanelaDedupeComandoControle = TimeSpan.FromMilliseconds(20);
|
||||
|
||||
private static readonly Dictionary<byte, DateTime> _ultimaTentativaReconexaoPorDriver = new Dictionary<byte, DateTime>();
|
||||
private static readonly TimeSpan IntervaloTentativaReconexao = TimeSpan.FromSeconds(1);
|
||||
|
||||
/*
|
||||
* Pooling de produção:
|
||||
* operação normal = ângulo rápido + IO lento.
|
||||
|
|
@ -693,37 +696,73 @@ namespace AgroBase.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var modulos =
|
||||
Variaveis
|
||||
.OperacaoEmAndamento
|
||||
.DispMvd?
|
||||
.Dados?
|
||||
.Modulos;
|
||||
|
||||
var modulos = Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos;
|
||||
if (modulos == null)
|
||||
return;
|
||||
|
||||
MarcarDriversInativosPorTimeout();
|
||||
|
||||
foreach (var mod in modulos)
|
||||
{
|
||||
var driver = mod?.DirMotor;
|
||||
|
||||
if (driver == null || !driver.Inicializado)
|
||||
if (driver == null)
|
||||
continue;
|
||||
|
||||
RequisitarProximoDado(
|
||||
driver._EnderecoCAN_Tx,
|
||||
driver._EnderecoCAN_Rx
|
||||
);
|
||||
if (driver.Inicializado)
|
||||
{
|
||||
RequisitarProximoDado(driver._EnderecoCAN_Tx, driver._EnderecoCAN_Rx);
|
||||
continue;
|
||||
}
|
||||
|
||||
RemoverDriversMuitoAntigos();
|
||||
TentarReconectarDriver(driver._EnderecoCAN_Tx, driver._EnderecoCAN_Rx);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("[MKS] Erro em AtualizarDados: " + ex.Message);
|
||||
Variaveis.MostrarLog("[MKS057DCanService] Erro em AtualizarDados: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TentarReconectarDriver(byte idTx, byte idRx)
|
||||
{
|
||||
/*
|
||||
* Só tentamos recuperar um driver que já existiu anteriormente.
|
||||
*
|
||||
* Descoberta inicial continua sendo responsabilidade de
|
||||
* VerificaDispositivoConectado().
|
||||
*/
|
||||
bool driverConhecido;
|
||||
|
||||
lock (DadosLeitura)
|
||||
{
|
||||
driverConhecido = DadosLeitura.Any(x => x.EnderecoTx == idTx);
|
||||
}
|
||||
|
||||
if (!driverConhecido)
|
||||
return;
|
||||
|
||||
DateTime agora = DateTime.Now;
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (_ultimaTentativaReconexaoPorDriver.TryGetValue(idTx, out DateTime ultima) && agora - ultima < IntervaloTentativaReconexao)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ultimaTentativaReconexaoPorDriver[idTx] = agora;
|
||||
}
|
||||
|
||||
/*
|
||||
* Versão é uma consulta pequena e já é utilizada
|
||||
* pela descoberta.
|
||||
*
|
||||
* Não contamina timeout do health.
|
||||
*/
|
||||
EnviarComandoDescoberta(idTx, idRx);
|
||||
}
|
||||
|
||||
private static MksFuncCode? EscolherProximoParametro(byte idTx)
|
||||
{
|
||||
DateTime agora = DateTime.Now;
|
||||
|
|
@ -756,7 +795,7 @@ namespace AgroBase.Services
|
|||
return null;
|
||||
}
|
||||
|
||||
private static void RemoverDriversMuitoAntigos()
|
||||
private static void MarcarDriversInativosPorTimeout()
|
||||
{
|
||||
DateTime agora = DateTime.Now;
|
||||
|
||||
|
|
@ -774,7 +813,17 @@ namespace AgroBase.Services
|
|||
}
|
||||
|
||||
foreach (var antigo in antigos)
|
||||
{
|
||||
antigo.Iniciado = false;
|
||||
|
||||
double tempoSemResposta = (agora - antigo.UltimoComandoRecebido).TotalSeconds;
|
||||
|
||||
Variaveis.MostrarLog(
|
||||
$"[MKS057DCanService] [CONEXAO] " +
|
||||
$"Driver CAN 0x{antigo.EnderecoTx:X2} OFFLINE | " +
|
||||
$"sem resposta há {tempoSemResposta:F1}s"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetZero(byte idTx, byte idRx)
|
||||
|
|
@ -1130,9 +1179,7 @@ namespace AgroBase.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
if (mensagem == null ||
|
||||
mensagem.DataRx == null ||
|
||||
mensagem.DataRx.Length < 1)
|
||||
if (mensagem == null || mensagem.DataRx == null || mensagem.DataRx.Length < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -1142,6 +1189,8 @@ namespace AgroBase.Services
|
|||
|
||||
var item = ObterOuCriar(mensagem);
|
||||
|
||||
bool estavaOffline = !item.Iniciado && item.UltimoComandoRecebido != DateTime.MinValue;
|
||||
|
||||
switch (func)
|
||||
{
|
||||
case MksFuncCode.EncoderCarregado:
|
||||
|
|
@ -1188,10 +1237,15 @@ namespace AgroBase.Services
|
|||
|
||||
item.UltimoComandoRecebido = DateTime.Now;
|
||||
item.Iniciado = true;
|
||||
|
||||
if (estavaOffline)
|
||||
{
|
||||
Variaveis.MostrarLog($"[MKS057DCanService] [CONEXAO] Driver CAN 0x{item.EnderecoTx:X2} ONLINE novamente");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("[MKS] Erro ao interpretar resposta CAN: " + ex.Message);
|
||||
Variaveis.MostrarLog("[MKS057DCanService] Erro ao interpretar resposta CAN: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue