ajustes no canservice

This commit is contained in:
Diego Freitas 2025-05-02 08:24:23 -03:00
parent cae8b20601
commit a33f02787c
28 changed files with 202 additions and 216 deletions

Binary file not shown.

View File

@ -3,20 +3,16 @@
"WorkspaceRootPath": "C:\\ZendionINC\\agrobot_base\\AgroBase\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|c:\\zendioninc\\agrobot_base\\agrobase\\agrobase\\models\\mpccontrolleraprimorado.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\models\\mpccontrolleraprimorado.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|c:\\zendioninc\\agrobot_base\\agrobase\\agrobase\\services\\oidcanservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\services\\oidcanservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|c:\\zendioninc\\agrobot_base\\agrobase\\agrobase\\models\\modules\\sensoriamentomodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\models\\modules\\sensoriamentomodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|c:\\zendioninc\\agrobot_base\\agrobase\\agrobase\\models\\modules\\movimentacaomodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\models\\modules\\movimentacaomodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|c:\\zendioninc\\agrobot_base\\agrobase\\agrobase\\models\\modules\\dispositivobasemodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\models\\modules\\dispositivobasemodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|C:\\ZendionINC\\agrobot_base\\AgroBase\\agrobase\\models\\modules\\atuadormodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\models\\modules\\atuadormodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|c:\\zendioninc\\agrobot_base\\agrobase\\agrobase\\models\\modules\\movimentacaounificadomodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{C54B41C0-1D21-4E3E-949E-0F86BBC86A33}|AgroBase\\AgroBase.csproj|solutionrelative:agrobase\\models\\modules\\movimentacaounificadomodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@ -26,58 +22,45 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"SelectedChildIndex": 2,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "MPCControllerAprimorado.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\MPCControllerAprimorado.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\MPCControllerAprimorado.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\MPCControllerAprimorado.cs",
"RelativeToolTip": "AgroBase\\Models\\MPCControllerAprimorado.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAABoAAABcAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-16T16:33:32.578Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "DispositivoBaseModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\DispositivoBaseModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\DispositivoBaseModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\DispositivoBaseModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\DispositivoBaseModel.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAgAAAAnAAAA",
"Title": "MovimentacaoUnificadoModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAPEAAAAzAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-16T13:20:21.786Z",
"WhenOpened": "2025-05-02T10:28:02.411Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "SensoriamentoModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\SensoriamentoModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\SensoriamentoModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\SensoriamentoModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\SensoriamentoModel.cs",
"ViewState": "AQIAABsHAAAAAAAAAAAuwEUIAAAOAAAA",
"Title": "MovimentacaoModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"ViewState": "AQIAAPYAAAAAAAAAAAAwwF8BAAA/AAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-15T10:44:14.963Z",
"WhenOpened": "2025-05-02T09:59:28.094Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "AtuadorModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\AtuadorModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\AtuadorModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\AtuadorModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\AtuadorModel.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAEAAAAYAAAA",
"DocumentIndex": 0,
"Title": "OIDCanService.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Services\\OIDCanService.cs",
"RelativeDocumentMoniker": "AgroBase\\Services\\OIDCanService.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Services\\OIDCanService.cs",
"RelativeToolTip": "AgroBase\\Services\\OIDCanService.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAMAAAABGAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-15T10:40:50.024Z",
"WhenOpened": "2025-05-01T23:29:12.777Z",
"EditorCaption": ""
}
]

View File

@ -2377,7 +2377,7 @@ namespace AgroBase.Forms
{
if (!CanService.IsConnected)
{
CanService.DefinirPortaCOM(new SerialPort(cmbPorta.Text, Convert.ToInt32(cmbBaud.Text)));
Task.Run(async () => await CanService.DefinirPortaCOM(new SerialPort(cmbPorta.Text, Convert.ToInt32(cmbBaud.Text))));
}
if (CanService.IsConnected)

View File

@ -392,7 +392,11 @@ namespace AgroBase.Models.Modules
{
if (!CanService.IsConnected)
{
CanService.DefinirPortaCOM(porta);
bool sucesso = await CanService.DefinirPortaCOM(porta);
if (!sucesso)
{
return false;
}
}
CanService.RegistrarHandler(_EnderecoCAN_Rx, _AtuHandler);

View File

@ -30,6 +30,7 @@ namespace AgroBase.Models.Modules
return Leitura?.CorrenteMotor != 0;
}
}
public double LeituraRPM { get; set; } = 0;
public bool ComandoLigado { get; set; } = false;
//public bool Freio { get; set; } = false;
public OidCodigoErro CodigoAlarme
@ -395,14 +396,12 @@ namespace AgroBase.Models.Modules
return;
}
byte Addr = _EnderecoCAN_Tx;
DateTime Agora = DateTime.Now;
bool SentidoAlterado = Sentido_SP != Sentido.Parado && (Leitura == null || Leitura.Direcao != Sentido_SP);
bool RPMAlterado = ComandoLigado && (Leitura == null || _Controle.PercentualVelocidadeSP != Variaveis.OperacaoEmAndamento.ControleAnterior.PercentualVelocidadeSP);
bool LigadoAlterado = Leitura == null || ComandoLigado != LeituraLigado;
bool FreioAlterado = Leitura == null || Leitura.Freado != Freado;
bool EnviaComando = SentidoAlterado || RPMAlterado || LigadoAlterado;
bool PrimeiraLeitura = Leitura == null;
bool SentidoAlterado = (Leitura?.Direcao ?? Sentido.Parado) != Sentido_SP;
bool RPMAlterado = LeituraRPM != RPM_SP;
bool LigadoAlterado = LeituraLigado != ComandoLigado;
bool FreioAlterado = (Leitura?.Freado ?? false) != Freado;
bool EnviaComando = PrimeiraLeitura || SentidoAlterado || RPMAlterado || LigadoAlterado;
OidFuncCode modoControle =
Freado ? OidFuncCode.ComandoCorrenteFreio :
@ -418,6 +417,8 @@ namespace AgroBase.Models.Modules
float velocidade = RPM_SP * mx;
OIDCanService.ComandoControle(_EnderecoCAN_Tx, _EnderecoCAN_Rx, modoControle, velocidade);
LeituraRPM = RPM_SP;
}
}

View File

@ -775,7 +775,11 @@ namespace AgroBase.Models.Modules
{
if (!CanService.IsConnected)
{
CanService.DefinirPortaCOM(porta);
bool sucesso = await CanService.DefinirPortaCOM(porta);
if (!sucesso)
{
return false;
}
}
CanService.RegistrarHandler(_EnderecoCAN_Rx, _SenHandler);

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
@ -60,7 +59,6 @@ namespace AgroBase.Services
public static SerialPort _PortaCAN;
public static string _portName;
private static int _baudRate;
private static object _lock = new object();
public static bool IsConnected { get; private set; }
public static bool Iniciado
{
@ -73,12 +71,11 @@ namespace AgroBase.Services
private static AsyncTaskTimerModel tmrOuvirCAN;
private static AsyncTaskTimerModel tmrProcessarCAN;
private static StringBuilder SerialCANBuffer = new StringBuilder();
private static object _framesLock = new object();
private static readonly Queue<string> FramesRecebidos = new Queue<string>();
private static ConcurrentQueue<string> FramesRecebidos = new ConcurrentQueue<string>();
private static readonly ConcurrentDictionary<byte, ICanMessageHandler> _roteadores = new ConcurrentDictionary<byte, ICanMessageHandler>();
private static byte? _ultimoIdEnviado = null;
private static List<CanMessage> Mensagens = new List<CanMessage>();
private static ConcurrentDictionary<string, CanMessage> MensagensPendentes = new ConcurrentDictionary<string, CanMessage>();
public static void RegistrarHandler(byte endereco_rx, ICanMessageHandler handler)
@ -86,48 +83,51 @@ namespace AgroBase.Services
_roteadores[endereco_rx] = handler;
}
public static void DefinirPortaCOM(SerialPort Porta)
public static async Task<bool> DefinirPortaCOM(SerialPort Porta)
{
if (!IsConnected)
{
Porta.Close();
}
bool sucesso = false;
if (_PortaCAN == null || !IsConnected)
{
lock (_lock)
{
_portName = Porta.PortName;
_baudRate = 115200;
_portName = Porta.PortName;
_baudRate = 115200;
_PortaCAN = new SerialPort(_portName, _baudRate, Parity.None, 8, StopBits.One);
_PortaCAN.Open();
_PortaCAN = new SerialPort(_portName, _baudRate, Parity.None, 8, StopBits.One);
_PortaCAN.Open();
EnviarComando("S6\r"); // 500Kbps
Thread.Sleep(100);
EnviarComando("O\r"); // Open CAN
Thread.Sleep(100);
sucesso = EnviarComando("S6\r"); // 500Kbps
if (!sucesso) return sucesso;
await Task.Delay(100);
sucesso = EnviarComando("O\r"); // Open CAN
await Task.Delay(100);
if (!sucesso) return sucesso;
tmrOuvirCAN?.Dispose();
tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 5);
tmrOuvirCAN.Start();
tmrOuvirCAN?.Dispose();
tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 5);
tmrOuvirCAN.Start();
tmrEnviarCAN?.Dispose();
tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 100);
tmrEnviarCAN.Start();
tmrEnviarCAN?.Dispose();
tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 5);
tmrEnviarCAN.Start();
tmrProcessarCAN?.Dispose();
tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 5);
tmrProcessarCAN.Start();
tmrProcessarCAN?.Dispose();
tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 10);
tmrProcessarCAN.Start();
IsConnected = true;
}
IsConnected = true;
}
if (_PortaCAN != null && !_PortaCAN.IsOpen)
{
_PortaCAN.Open();
}
return sucesso;
}
private static async Task OuvirCAN()
@ -147,10 +147,7 @@ namespace AgroBase.Services
if (!string.IsNullOrWhiteSpace(frame))
{
lock (_framesLock)
{
FramesRecebidos.Enqueue(frame);
}
FramesRecebidos.Enqueue(frame);
}
}
else
@ -163,17 +160,7 @@ namespace AgroBase.Services
private static async Task ProcessarCAN()
{
string frame = null;
lock (_framesLock)
{
if (FramesRecebidos.Count > 0)
{
frame = FramesRecebidos.Dequeue();
}
}
if (frame != null)
if (FramesRecebidos.TryDequeue(out string frame))
{
ProcessarFrameCAN(frame);
}
@ -198,20 +185,12 @@ namespace AgroBase.Services
}
byte fCodeRx = data[0];
var mensagem = new CanMessage();
lock (Mensagens)
{
mensagem = Mensagens
.Where(x => x.IdRx == id)
.OrderBy(x => x.EnviadoEm)
.FirstOrDefault(x => x.Enviado && !x.Respondido && x.funcCodeRx == fCodeRx);
}
var mensagem = new CanMessage() { IdTx = (byte)id, IdRx = (byte)id, funcCodeRx = fCodeRx, DataRx = data };
if (mensagem == null)
if (!MensagensPendentes.TryRemove(GerarChaveDicionarioFila(mensagem), out mensagem))
{
mensagem = new CanMessage { IdTx = (byte)id, IdRx = (byte)id, DataRx = data };
mensagem = new CanMessage { IdTx = (byte)id, IdRx = (byte)id, funcCodeRx = fCodeRx, DataRx = data };
}
mensagem.DataRx = data;
@ -226,6 +205,8 @@ namespace AgroBase.Services
{
Console.WriteLine($"[CAN] ID_Num não tratado: 0x{id:X2}, fCodeRx: 0x{fCodeRx:X2}");
}
LimparMensagensAntigas();
}
catch (Exception ex)
{
@ -260,70 +241,51 @@ namespace AgroBase.Services
ComResposta = get
};
lock (Mensagens)
string chave = GerarChaveDicionarioFila(novaMensagem);
if (MensagensPendentes.ContainsKey(chave))
{
// Limpa mensagens antigas antes de avaliar
LimparMensagensAntigas();
var existente = Mensagens.FirstOrDefault(x =>
x.IdTx == novaMensagem.IdTx &&
x.funcCodeTx == novaMensagem.funcCodeTx &&
x.funcCodeRx == novaMensagem.funcCodeRx &&
x.ComResposta == novaMensagem.ComResposta &&
x.DataTx.SequenceEqual(novaMensagem.DataTx) &&
(!x.Enviado || (x.ComResposta && !x.Respondido)) // Está pendente
);
if (existente != null)
{
// Já existe mensagem igual aguardando ou pendente
return;
}
// Log e adiciona
//Console.WriteLine($"[MSG] - MENSAGEM ADICIONADA NA FILA para o módulo {Dispositivo} - {FuncoesGlobais.ConverterComandoBytesParaTexto(novaMensagem.DataTx)}");
Mensagens.Add(novaMensagem);
return;
}
MensagensPendentes.TryAdd(chave, novaMensagem);
}
private static CanMessage ObterProximaMensagem()
{
lock (Mensagens)
var mensagensPendentes = MensagensPendentes.Values
.Where(x => !x.Enviado)
.ToList();
if (!mensagensPendentes.Any())
return null;
// Agrupa por IdTx e ordena os grupos
var idsDisponiveis = mensagensPendentes
.Select(x => x.IdTx)
.Distinct()
.OrderBy(x => x)
.ToList();
byte proximoId;
if (!_ultimoIdEnviado.HasValue || !idsDisponiveis.Contains(_ultimoIdEnviado.Value))
{
var idsDisponiveis = Mensagens
.Where(x => !x.Enviado)
.Select(x => x.IdTx)
.Distinct()
.OrderBy(id => id)
.ToList();
if (!idsDisponiveis.Any())
return null;
byte proximoId;
if (!_ultimoIdEnviado.HasValue || !idsDisponiveis.Contains(_ultimoIdEnviado.Value))
{
// Começa pelo menor ID disponível
proximoId = idsDisponiveis.First();
}
else
{
// Busca o próximo ID após o último usado
var index = idsDisponiveis.IndexOf(_ultimoIdEnviado.Value);
if (index + 1 < idsDisponiveis.Count)
proximoId = idsDisponiveis[index + 1];
else
proximoId = idsDisponiveis.First(); // ciclo completo
}
var msg = Mensagens
.Where(x => !x.Enviado && x.IdTx == proximoId)
.OrderBy(x => x.Momento)
.FirstOrDefault();
return msg;
proximoId = idsDisponiveis.First();
}
else
{
var index = idsDisponiveis.IndexOf(_ultimoIdEnviado.Value);
proximoId = (index + 1 < idsDisponiveis.Count) ? idsDisponiveis[index + 1] : idsDisponiveis.First();
}
// Seleciona a mensagem mais antiga com esse IdTx
var proximaMsg = mensagensPendentes
.Where(x => x.IdTx == proximoId)
.OrderBy(x => x.Momento)
.FirstOrDefault();
return proximaMsg;
}
private static async Task EnviarCAN()
@ -338,16 +300,18 @@ namespace AgroBase.Services
if (_ultimoIdEnviado.HasValue && msg.IdTx == _ultimoIdEnviado.Value)
{
await Task.Delay(5);
//await Task.Delay(5);
}
lock (_lock)
{
EnviarComando(frame);
EnviarComando(frame);
msg.Enviado = true;
msg.EnviadoEm = DateTime.Now;
_ultimoIdEnviado = msg.IdTx;
msg.Enviado = true;
msg.EnviadoEm = DateTime.Now;
_ultimoIdEnviado = msg.IdTx;
if (!msg.ComResposta)
{
MensagensPendentes.TryRemove(GerarChaveDicionarioFila(msg), out _);
}
}
}
@ -363,26 +327,40 @@ namespace AgroBase.Services
return frame;
}
private static void EnviarComando(string comando)
private static bool EnviarComando(string comando)
{
if (_PortaCAN?.IsOpen == true)
{
_PortaCAN.Write(comando);
//Console.WriteLine($"[CAN] Frame enviado: {comando}");
bool sucesso = SerialService.EnviarDadosPortaSerial(_PortaCAN, comando, false, 20);
if (sucesso)
{
//Console.WriteLine($"[CAN] Frame enviado: {comando}");
}
else
{
Console.WriteLine($"[CAN] Erro ao enviar frame: {comando}");
}
return sucesso;
}
return false;
}
private static void LimparMensagensAntigas()
{
lock (Mensagens)
var agora = DateTime.Now;
foreach (var item in MensagensPendentes)
{
var limite = DateTime.Now.AddSeconds(-5); // ⏱ 5 segundos de validade
Mensagens.RemoveAll(x =>
(!x.ComResposta && x.Enviado) || // Mensagem que não precisa resposta e já foi enviada
(x.ComResposta && x.Respondido && x.RespondidoEm < limite) || // Resposta antiga
(x.ComResposta && x.Enviado && !x.Respondido && x.EnviadoEm < limite) // Enviada mas nunca respondida e já passou do prazo
);
var msg = item.Value;
if (!msg.ComResposta && msg.Enviado) // mensagem sem resposta e já enviada
MensagensPendentes.TryRemove(item.Key, out _);
else if (msg.ComResposta && msg.Respondido)
MensagensPendentes.TryRemove(item.Key, out _);
else if (msg.ComResposta && msg.Enviado && !msg.Respondido && msg.EnviadoEm < agora.AddSeconds(-5))
MensagensPendentes.TryRemove(item.Key, out _);
}
}
@ -391,12 +369,10 @@ namespace AgroBase.Services
tmrOuvirCAN?.Dispose();
tmrEnviarCAN?.Dispose();
lock (Mensagens)
{
Mensagens.Clear();
}
MensagensPendentes.Clear();
SerialCANBuffer.Clear();
FramesRecebidos = new ConcurrentQueue<string>();
_roteadores.Clear();
_ultimoIdEnviado = null;
@ -422,6 +398,11 @@ namespace AgroBase.Services
return (byte)(soma & 0xFF);
}
private static string GerarChaveDicionarioFila(CanMessage msg)
{
byte parametro = (msg?.DataTx?.Length ?? 0) > 1 ? msg.DataTx[1] : (byte)0x00;
return $"{msg.IdRx}_{msg.funcCodeRx}_{parametro}";
}
}
}

View File

@ -43,7 +43,11 @@ namespace AgroBase.Services
{
if (!CanService.IsConnected)
{
CanService.DefinirPortaCOM(porta);
bool sucesso = await CanService.DefinirPortaCOM(porta);
if (!sucesso)
{
return false;
}
}
if (CanService.IsConnected)

View File

@ -13,7 +13,6 @@ namespace AgroBase.Services
public class OIDCanService
{
public static List<OIDModel> DadosLeitura = new List<OIDModel>();
private static int _MStep { get; set; } = 16;
private static T_Code Dispositivo { get; set; } = T_Code.Oid;
private static OidHandler _OidHandler { get; set; } = new OidHandler();
private static AsyncTaskTimerModel tmrHeartbeat;
@ -37,7 +36,11 @@ namespace AgroBase.Services
{
if (!CanService.IsConnected)
{
CanService.DefinirPortaCOM(porta);
bool sucesso = await CanService.DefinirPortaCOM(porta);
if (!sucesso)
{
return false;
}
}
if (CanService.IsConnected)
@ -84,7 +87,7 @@ namespace AgroBase.Services
if (tmrHeartbeat == null || !(tmrHeartbeat?.IsRunning ?? false))
{
tmrHeartbeat?.Dispose();
tmrHeartbeat = new AsyncTaskTimerModel("tmrOidHeartbeat", tmrHeartbeat_Tick, 1000);
tmrHeartbeat = new AsyncTaskTimerModel("tmrOidHeartbeat", tmrHeartbeat_Tick, 500);
tmrHeartbeat.Start();
}
@ -125,42 +128,43 @@ namespace AgroBase.Services
public static void RequisitarDado(byte idTx, byte idRx, OidParametros dado)
{
EnviarComando(Dispositivo, idTx, idRx, (byte)OidFuncCode.Consulta, new byte[] { (byte)dado });
EnviarComando(Dispositivo, idTx, idRx, (byte)OidFuncCode.Consulta, new byte[] { (byte)dado }, true);
}
public static void ComandoControle(byte idTx, byte idRx, OidFuncCode tipoControle, double setPoint)
public static void ComandoControle(byte idTx, byte idRx, OidFuncCode funcCode, double setPoint)
{
byte[] setPointBytes = null;
switch (tipoControle)
switch (funcCode)
{
case OidFuncCode.ComandoCorrente:
case OidFuncCode.ComandoCorrenteFreio:
case OidFuncCode.AjusteCorrenteMaxima:
{
short corrente_10mA = (short)(setPoint * 100);
setPointBytes = BitConverter.GetBytes(corrente_10mA);
setPointBytes = BitConverter.GetBytes(corrente_10mA).Reverse().ToArray();
break;
}
case OidFuncCode.ComandoVelocidade:
{
int erpm = (int)(setPoint * VariaveisEquipamento.NumeroPolosMotor);
setPointBytes = BitConverter.GetBytes(erpm);
setPointBytes = BitConverter.GetBytes(erpm).Reverse().ToArray();
break;
}
case OidFuncCode.ComandoCicloTrabalho:
{
short duty = (short)(Math.Max(-100, Math.Min(setPoint, 100)) * 10);
setPointBytes = BitConverter.GetBytes(duty);
setPointBytes = BitConverter.GetBytes(duty).Reverse().ToArray();
break;
}
case OidFuncCode.AjusteAceleracaoVelocidade:
case OidFuncCode.AjusteDesaceleracaoVelocidade:
{
if (setPoint <= 0) setPoint = 1;
double erpmMax = VariaveisEquipamento.RPM_Max_Roda * VariaveisEquipamento.RelacaoRPM * VariaveisEquipamento.NumeroPolosMotor;
int aceleracao = (int)(erpmMax / setPoint); // setPoint = tempo (s)
setPointBytes = BitConverter.GetBytes(aceleracao);
setPointBytes = BitConverter.GetBytes(aceleracao).Reverse().ToArray();
break;
}
case OidFuncCode.Heartbeat:
@ -170,7 +174,7 @@ namespace AgroBase.Services
}
default:
{
Console.WriteLine($"[OID] Comando nao mapeado: {tipoControle.ToString()}");
Console.WriteLine($"[OID] Comando nao mapeado: {funcCode.ToString()}");
break;
}
}
@ -178,10 +182,12 @@ namespace AgroBase.Services
if (setPointBytes == null)
return;
if (BitConverter.IsLittleEndian)
Array.Reverse(setPointBytes);
if (funcCode != OidFuncCode.Heartbeat)
{
//Console.WriteLine($"[OID] Comando enviado para fila: {idTx.ToString("X")} {((byte)funcCode).ToString("X")} {string.Join(" ", setPointBytes.Select(x => x.ToString("X")))}");
}
EnviarComando(Dispositivo, idTx, idRx, (byte)tipoControle, setPointBytes);
EnviarComando(Dispositivo, idTx, idRx, (byte)funcCode, setPointBytes, false);
}
private static void ConfigurarDriver(MovimentacaoModel Modulo)
@ -210,6 +216,7 @@ namespace AgroBase.Services
ComandoControle(Mod.MovMotor._EnderecoCAN_Tx, Mod.MovMotor._EnderecoCAN_Rx, OidFuncCode.Heartbeat, novoValor);
Mod.MovMotor.heartBeatValue = novoValor;
}
}
}
@ -304,6 +311,8 @@ namespace AgroBase.Services
OidParametros parametro = (OidParametros)mensagem.DataRx[1];
byte[] valorBytes = mensagem.DataRx.Skip(2).ToArray();
//Console.WriteLine($"[OID] Dados brutos recebidos do driver {mensagem.IdTx} - {string.Join(" ", mensagem.DataRx.Select(x => x.ToString("X")))}");
if (BitConverter.IsLittleEndian)
Array.Reverse(valorBytes);

View File

@ -36,7 +36,7 @@ namespace AgroBase.Services
private static bool VarreduraEmAndamento = false;
public static bool EnviarDadosPortaSerial(SerialPort _porta, string Dados, bool DebugMode = false)
public static bool EnviarDadosPortaSerial(SerialPort _porta, string Dados, bool DebugMode = false, int timeout = 2000)
{
bool ForceDebug = false;
if (ForceDebug)
@ -61,7 +61,7 @@ namespace AgroBase.Services
try
{
// Define o tempo de espera máximo para a operação de escrita
_porta.WriteTimeout = 2000; // 2 segundos de timeout para escrita (ajuste conforme necessário)
_porta.WriteTimeout = timeout; // 2 segundos de timeout para escrita (ajuste conforme necessário)
// Verifica se há dados para enviar
if (string.IsNullOrEmpty(Dados))

File diff suppressed because one or more lines are too long

View File

@ -25,7 +25,7 @@
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_0a65390b914a9d20a49b9ea06134c652 {
#map_4450d383ac9fb1f3116e73305183afb1 {
position: relative;
width: 100.0%;
height: 100.0%;
@ -39,14 +39,14 @@
<body>
<div class="folium-map" id="map_0a65390b914a9d20a49b9ea06134c652" ></div>
<div class="folium-map" id="map_4450d383ac9fb1f3116e73305183afb1" ></div>
</body>
<script>
var map_0a65390b914a9d20a49b9ea06134c652 = L.map(
"map_0a65390b914a9d20a49b9ea06134c652",
var map_4450d383ac9fb1f3116e73305183afb1 = L.map(
"map_4450d383ac9fb1f3116e73305183afb1",
{
center: [0.0, 0.0],
crs: L.CRS.EPSG3857,
@ -60,13 +60,13 @@
var tile_layer_46f299708219af4df3a972d14ad0e238 = L.tileLayer(
var tile_layer_99e7db5371d91587ccc10829a4786ab2 = L.tileLayer(
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
{"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
);
tile_layer_46f299708219af4df3a972d14ad0e238.addTo(map_0a65390b914a9d20a49b9ea06134c652);
tile_layer_99e7db5371d91587ccc10829a4786ab2.addTo(map_4450d383ac9fb1f3116e73305183afb1);
</script>
@ -87,7 +87,7 @@
}
trajeto_json_add({"features": []});
trajeto_json.addTo(map_0a65390b914a9d20a49b9ea06134c652);
trajeto_json.addTo(map_4450d383ac9fb1f3116e73305183afb1);
function adicionarGeometria(novaGeometria) {
trajeto_json.addData(novaGeometria);
@ -145,7 +145,7 @@
var marcadorDinamico = L.marker([0, 0], {
icon: customIcon
}).addTo(map_0a65390b914a9d20a49b9ea06134c652);
}).addTo(map_4450d383ac9fb1f3116e73305183afb1);
// Conectar ao broker MQTT
const client = mqtt.connect('ws://localhost:9001'); // Use wss para conexão segura
@ -183,7 +183,7 @@
marcadorDinamico.setRotationAngle(angulo);
adicionarCoordenada("Tj", [novaLongitude, novaLatitude]);
map_0a65390b914a9d20a49b9ea06134c652.setView(novaPosicao, map_0a65390b914a9d20a49b9ea06134c652.getZoom());
map_4450d383ac9fb1f3116e73305183afb1.setView(novaPosicao, map_4450d383ac9fb1f3116e73305183afb1.getZoom());
});
function calcularOrientacao(P1latitude, P1longitude, P2latitude, P2longitude) {

View File

@ -482,4 +482,4 @@ C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.csproj.GenerateR
C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.csproj.CoreCompileInputs.cache
C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.exe
C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.pdb
C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.csproj.CopyComplete
C:\ZendionINC\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.csproj.Up2Date