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\\", "WorkspaceRootPath": "C:\\ZendionINC\\agrobot_base\\AgroBase\\",
"Documents": [ "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}", "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\\models\\mpccontrolleraprimorado.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}", "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\\sensoriamentomodel.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}", "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\\dispositivobasemodel.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}"
},
{
"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}"
} }
], ],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
@ -26,58 +22,45 @@
"DocumentGroups": [ "DocumentGroups": [
{ {
"DockedWidth": 200, "DockedWidth": 200,
"SelectedChildIndex": 0, "SelectedChildIndex": 2,
"Children": [ "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", "$type": "Document",
"DocumentIndex": 2, "DocumentIndex": 2,
"Title": "DispositivoBaseModel.cs", "Title": "MovimentacaoUnificadoModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\DispositivoBaseModel.cs", "DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\DispositivoBaseModel.cs", "RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\DispositivoBaseModel.cs", "ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\DispositivoBaseModel.cs", "RelativeToolTip": "AgroBase\\Models\\Modules\\MovimentacaoUnificadoModel.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAgAAAAnAAAA", "ViewState": "AQIAAAAAAAAAAAAAAAAAAPEAAAAzAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-16T13:20:21.786Z", "WhenOpened": "2025-05-02T10:28:02.411Z",
"EditorCaption": "" "EditorCaption": ""
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 1, "DocumentIndex": 1,
"Title": "SensoriamentoModel.cs", "Title": "MovimentacaoModel.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\SensoriamentoModel.cs", "DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\SensoriamentoModel.cs", "RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\SensoriamentoModel.cs", "ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\SensoriamentoModel.cs", "RelativeToolTip": "AgroBase\\Models\\Modules\\MovimentacaoModel.cs",
"ViewState": "AQIAABsHAAAAAAAAAAAuwEUIAAAOAAAA", "ViewState": "AQIAAPYAAAAAAAAAAAAwwF8BAAA/AAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-15T10:44:14.963Z", "WhenOpened": "2025-05-02T09:59:28.094Z",
"EditorCaption": "" "EditorCaption": ""
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 3, "DocumentIndex": 0,
"Title": "AtuadorModel.cs", "Title": "OIDCanService.cs",
"DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\AtuadorModel.cs", "DocumentMoniker": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Services\\OIDCanService.cs",
"RelativeDocumentMoniker": "AgroBase\\Models\\Modules\\AtuadorModel.cs", "RelativeDocumentMoniker": "AgroBase\\Services\\OIDCanService.cs",
"ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Models\\Modules\\AtuadorModel.cs", "ToolTip": "C:\\ZendionINC\\agrobot_base\\AgroBase\\AgroBase\\Services\\OIDCanService.cs",
"RelativeToolTip": "AgroBase\\Models\\Modules\\AtuadorModel.cs", "RelativeToolTip": "AgroBase\\Services\\OIDCanService.cs",
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAEAAAAYAAAA", "ViewState": "AQIAAAAAAAAAAAAAAAAAAMAAAABGAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-04-15T10:40:50.024Z", "WhenOpened": "2025-05-01T23:29:12.777Z",
"EditorCaption": "" "EditorCaption": ""
} }
] ]

View File

@ -2377,7 +2377,7 @@ namespace AgroBase.Forms
{ {
if (!CanService.IsConnected) 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) if (CanService.IsConnected)

View File

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

View File

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

View File

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

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.IO.Ports; using System.IO.Ports;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using static AgroBase.Models.Enums; using static AgroBase.Models.Enums;
@ -60,7 +59,6 @@ namespace AgroBase.Services
public static SerialPort _PortaCAN; public static SerialPort _PortaCAN;
public static string _portName; public static string _portName;
private static int _baudRate; private static int _baudRate;
private static object _lock = new object();
public static bool IsConnected { get; private set; } public static bool IsConnected { get; private set; }
public static bool Iniciado public static bool Iniciado
{ {
@ -73,12 +71,11 @@ namespace AgroBase.Services
private static AsyncTaskTimerModel tmrOuvirCAN; private static AsyncTaskTimerModel tmrOuvirCAN;
private static AsyncTaskTimerModel tmrProcessarCAN; private static AsyncTaskTimerModel tmrProcessarCAN;
private static StringBuilder SerialCANBuffer = new StringBuilder(); private static StringBuilder SerialCANBuffer = new StringBuilder();
private static object _framesLock = new object(); private static ConcurrentQueue<string> FramesRecebidos = new ConcurrentQueue<string>();
private static readonly Queue<string> FramesRecebidos = new Queue<string>();
private static readonly ConcurrentDictionary<byte, ICanMessageHandler> _roteadores = new ConcurrentDictionary<byte, ICanMessageHandler>(); private static readonly ConcurrentDictionary<byte, ICanMessageHandler> _roteadores = new ConcurrentDictionary<byte, ICanMessageHandler>();
private static byte? _ultimoIdEnviado = null; 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) public static void RegistrarHandler(byte endereco_rx, ICanMessageHandler handler)
@ -86,48 +83,51 @@ namespace AgroBase.Services
_roteadores[endereco_rx] = handler; _roteadores[endereco_rx] = handler;
} }
public static void DefinirPortaCOM(SerialPort Porta) public static async Task<bool> DefinirPortaCOM(SerialPort Porta)
{ {
if (!IsConnected) if (!IsConnected)
{ {
Porta.Close(); Porta.Close();
} }
bool sucesso = false;
if (_PortaCAN == null || !IsConnected) 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 = new SerialPort(_portName, _baudRate, Parity.None, 8, StopBits.One);
_PortaCAN.Open(); _PortaCAN.Open();
EnviarComando("S6\r"); // 500Kbps sucesso = EnviarComando("S6\r"); // 500Kbps
Thread.Sleep(100); if (!sucesso) return sucesso;
EnviarComando("O\r"); // Open CAN await Task.Delay(100);
Thread.Sleep(100); sucesso = EnviarComando("O\r"); // Open CAN
await Task.Delay(100);
if (!sucesso) return sucesso;
tmrOuvirCAN?.Dispose(); tmrOuvirCAN?.Dispose();
tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 5); tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 5);
tmrOuvirCAN.Start(); tmrOuvirCAN.Start();
tmrEnviarCAN?.Dispose(); tmrEnviarCAN?.Dispose();
tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 100); tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 5);
tmrEnviarCAN.Start(); tmrEnviarCAN.Start();
tmrProcessarCAN?.Dispose(); tmrProcessarCAN?.Dispose();
tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 5); tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 10);
tmrProcessarCAN.Start(); tmrProcessarCAN.Start();
IsConnected = true; IsConnected = true;
}
} }
if (_PortaCAN != null && !_PortaCAN.IsOpen) if (_PortaCAN != null && !_PortaCAN.IsOpen)
{ {
_PortaCAN.Open(); _PortaCAN.Open();
} }
return sucesso;
} }
private static async Task OuvirCAN() private static async Task OuvirCAN()
@ -147,10 +147,7 @@ namespace AgroBase.Services
if (!string.IsNullOrWhiteSpace(frame)) if (!string.IsNullOrWhiteSpace(frame))
{ {
lock (_framesLock) FramesRecebidos.Enqueue(frame);
{
FramesRecebidos.Enqueue(frame);
}
} }
} }
else else
@ -163,17 +160,7 @@ namespace AgroBase.Services
private static async Task ProcessarCAN() private static async Task ProcessarCAN()
{ {
string frame = null; if (FramesRecebidos.TryDequeue(out string frame))
lock (_framesLock)
{
if (FramesRecebidos.Count > 0)
{
frame = FramesRecebidos.Dequeue();
}
}
if (frame != null)
{ {
ProcessarFrameCAN(frame); ProcessarFrameCAN(frame);
} }
@ -198,20 +185,12 @@ namespace AgroBase.Services
} }
byte fCodeRx = data[0]; byte fCodeRx = data[0];
var mensagem = new CanMessage();
lock (Mensagens) var mensagem = new CanMessage() { IdTx = (byte)id, IdRx = (byte)id, funcCodeRx = fCodeRx, DataRx = data };
{
mensagem = Mensagens
.Where(x => x.IdRx == id)
.OrderBy(x => x.EnviadoEm)
.FirstOrDefault(x => x.Enviado && !x.Respondido && x.funcCodeRx == fCodeRx);
}
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; 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}"); Console.WriteLine($"[CAN] ID_Num não tratado: 0x{id:X2}, fCodeRx: 0x{fCodeRx:X2}");
} }
LimparMensagensAntigas();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -260,70 +241,51 @@ namespace AgroBase.Services
ComResposta = get ComResposta = get
}; };
lock (Mensagens) string chave = GerarChaveDicionarioFila(novaMensagem);
if (MensagensPendentes.ContainsKey(chave))
{ {
// Limpa mensagens antigas antes de avaliar return;
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);
} }
MensagensPendentes.TryAdd(chave, novaMensagem);
} }
private static CanMessage ObterProximaMensagem() 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 proximoId = idsDisponiveis.First();
.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;
} }
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() private static async Task EnviarCAN()
@ -338,16 +300,18 @@ namespace AgroBase.Services
if (_ultimoIdEnviado.HasValue && msg.IdTx == _ultimoIdEnviado.Value) 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.Enviado = true;
msg.EnviadoEm = DateTime.Now; msg.EnviadoEm = DateTime.Now;
_ultimoIdEnviado = msg.IdTx; _ultimoIdEnviado = msg.IdTx;
if (!msg.ComResposta)
{
MensagensPendentes.TryRemove(GerarChaveDicionarioFila(msg), out _);
} }
} }
} }
@ -363,26 +327,40 @@ namespace AgroBase.Services
return frame; return frame;
} }
private static void EnviarComando(string comando) private static bool EnviarComando(string comando)
{ {
if (_PortaCAN?.IsOpen == true) if (_PortaCAN?.IsOpen == true)
{ {
_PortaCAN.Write(comando); bool sucesso = SerialService.EnviarDadosPortaSerial(_PortaCAN, comando, false, 20);
if (sucesso)
//Console.WriteLine($"[CAN] Frame enviado: {comando}"); {
//Console.WriteLine($"[CAN] Frame enviado: {comando}");
}
else
{
Console.WriteLine($"[CAN] Erro ao enviar frame: {comando}");
}
return sucesso;
} }
return false;
} }
private static void LimparMensagensAntigas() 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 var msg = item.Value;
Mensagens.RemoveAll(x =>
(!x.ComResposta && x.Enviado) || // Mensagem que não precisa resposta e já foi enviada if (!msg.ComResposta && msg.Enviado) // mensagem sem resposta e já enviada
(x.ComResposta && x.Respondido && x.RespondidoEm < limite) || // Resposta antiga MensagensPendentes.TryRemove(item.Key, out _);
(x.ComResposta && x.Enviado && !x.Respondido && x.EnviadoEm < limite) // Enviada mas nunca respondida e já passou do prazo
); 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(); tmrOuvirCAN?.Dispose();
tmrEnviarCAN?.Dispose(); tmrEnviarCAN?.Dispose();
lock (Mensagens) MensagensPendentes.Clear();
{
Mensagens.Clear();
}
SerialCANBuffer.Clear(); SerialCANBuffer.Clear();
FramesRecebidos = new ConcurrentQueue<string>();
_roteadores.Clear(); _roteadores.Clear();
_ultimoIdEnviado = null; _ultimoIdEnviado = null;
@ -422,6 +398,11 @@ namespace AgroBase.Services
return (byte)(soma & 0xFF); 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) if (!CanService.IsConnected)
{ {
CanService.DefinirPortaCOM(porta); bool sucesso = await CanService.DefinirPortaCOM(porta);
if (!sucesso)
{
return false;
}
} }
if (CanService.IsConnected) if (CanService.IsConnected)

View File

@ -13,7 +13,6 @@ namespace AgroBase.Services
public class OIDCanService public class OIDCanService
{ {
public static List<OIDModel> DadosLeitura = new List<OIDModel>(); 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 T_Code Dispositivo { get; set; } = T_Code.Oid;
private static OidHandler _OidHandler { get; set; } = new OidHandler(); private static OidHandler _OidHandler { get; set; } = new OidHandler();
private static AsyncTaskTimerModel tmrHeartbeat; private static AsyncTaskTimerModel tmrHeartbeat;
@ -37,7 +36,11 @@ namespace AgroBase.Services
{ {
if (!CanService.IsConnected) if (!CanService.IsConnected)
{ {
CanService.DefinirPortaCOM(porta); bool sucesso = await CanService.DefinirPortaCOM(porta);
if (!sucesso)
{
return false;
}
} }
if (CanService.IsConnected) if (CanService.IsConnected)
@ -84,7 +87,7 @@ namespace AgroBase.Services
if (tmrHeartbeat == null || !(tmrHeartbeat?.IsRunning ?? false)) if (tmrHeartbeat == null || !(tmrHeartbeat?.IsRunning ?? false))
{ {
tmrHeartbeat?.Dispose(); tmrHeartbeat?.Dispose();
tmrHeartbeat = new AsyncTaskTimerModel("tmrOidHeartbeat", tmrHeartbeat_Tick, 1000); tmrHeartbeat = new AsyncTaskTimerModel("tmrOidHeartbeat", tmrHeartbeat_Tick, 500);
tmrHeartbeat.Start(); tmrHeartbeat.Start();
} }
@ -125,42 +128,43 @@ namespace AgroBase.Services
public static void RequisitarDado(byte idTx, byte idRx, OidParametros dado) 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; byte[] setPointBytes = null;
switch (tipoControle) switch (funcCode)
{ {
case OidFuncCode.ComandoCorrente: case OidFuncCode.ComandoCorrente:
case OidFuncCode.ComandoCorrenteFreio: case OidFuncCode.ComandoCorrenteFreio:
case OidFuncCode.AjusteCorrenteMaxima: case OidFuncCode.AjusteCorrenteMaxima:
{ {
short corrente_10mA = (short)(setPoint * 100); short corrente_10mA = (short)(setPoint * 100);
setPointBytes = BitConverter.GetBytes(corrente_10mA); setPointBytes = BitConverter.GetBytes(corrente_10mA).Reverse().ToArray();
break; break;
} }
case OidFuncCode.ComandoVelocidade: case OidFuncCode.ComandoVelocidade:
{ {
int erpm = (int)(setPoint * VariaveisEquipamento.NumeroPolosMotor); int erpm = (int)(setPoint * VariaveisEquipamento.NumeroPolosMotor);
setPointBytes = BitConverter.GetBytes(erpm); setPointBytes = BitConverter.GetBytes(erpm).Reverse().ToArray();
break; break;
} }
case OidFuncCode.ComandoCicloTrabalho: case OidFuncCode.ComandoCicloTrabalho:
{ {
short duty = (short)(Math.Max(-100, Math.Min(setPoint, 100)) * 10); short duty = (short)(Math.Max(-100, Math.Min(setPoint, 100)) * 10);
setPointBytes = BitConverter.GetBytes(duty); setPointBytes = BitConverter.GetBytes(duty).Reverse().ToArray();
break; break;
} }
case OidFuncCode.AjusteAceleracaoVelocidade: case OidFuncCode.AjusteAceleracaoVelocidade:
case OidFuncCode.AjusteDesaceleracaoVelocidade: case OidFuncCode.AjusteDesaceleracaoVelocidade:
{ {
if (setPoint <= 0) setPoint = 1;
double erpmMax = VariaveisEquipamento.RPM_Max_Roda * VariaveisEquipamento.RelacaoRPM * VariaveisEquipamento.NumeroPolosMotor; double erpmMax = VariaveisEquipamento.RPM_Max_Roda * VariaveisEquipamento.RelacaoRPM * VariaveisEquipamento.NumeroPolosMotor;
int aceleracao = (int)(erpmMax / setPoint); // setPoint = tempo (s) int aceleracao = (int)(erpmMax / setPoint); // setPoint = tempo (s)
setPointBytes = BitConverter.GetBytes(aceleracao); setPointBytes = BitConverter.GetBytes(aceleracao).Reverse().ToArray();
break; break;
} }
case OidFuncCode.Heartbeat: case OidFuncCode.Heartbeat:
@ -170,7 +174,7 @@ namespace AgroBase.Services
} }
default: default:
{ {
Console.WriteLine($"[OID] Comando nao mapeado: {tipoControle.ToString()}"); Console.WriteLine($"[OID] Comando nao mapeado: {funcCode.ToString()}");
break; break;
} }
} }
@ -178,10 +182,12 @@ namespace AgroBase.Services
if (setPointBytes == null) if (setPointBytes == null)
return; return;
if (BitConverter.IsLittleEndian) if (funcCode != OidFuncCode.Heartbeat)
Array.Reverse(setPointBytes); {
//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) 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); 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]; OidParametros parametro = (OidParametros)mensagem.DataRx[1];
byte[] valorBytes = mensagem.DataRx.Skip(2).ToArray(); 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) if (BitConverter.IsLittleEndian)
Array.Reverse(valorBytes); Array.Reverse(valorBytes);

View File

@ -36,7 +36,7 @@ namespace AgroBase.Services
private static bool VarreduraEmAndamento = false; 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; bool ForceDebug = false;
if (ForceDebug) if (ForceDebug)
@ -61,7 +61,7 @@ namespace AgroBase.Services
try try
{ {
// Define o tempo de espera máximo para a operação de escrita // 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 // Verifica se há dados para enviar
if (string.IsNullOrEmpty(Dados)) 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, <meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style> <style>
#map_0a65390b914a9d20a49b9ea06134c652 { #map_4450d383ac9fb1f3116e73305183afb1 {
position: relative; position: relative;
width: 100.0%; width: 100.0%;
height: 100.0%; height: 100.0%;
@ -39,14 +39,14 @@
<body> <body>
<div class="folium-map" id="map_0a65390b914a9d20a49b9ea06134c652" ></div> <div class="folium-map" id="map_4450d383ac9fb1f3116e73305183afb1" ></div>
</body> </body>
<script> <script>
var map_0a65390b914a9d20a49b9ea06134c652 = L.map( var map_4450d383ac9fb1f3116e73305183afb1 = L.map(
"map_0a65390b914a9d20a49b9ea06134c652", "map_4450d383ac9fb1f3116e73305183afb1",
{ {
center: [0.0, 0.0], center: [0.0, 0.0],
crs: L.CRS.EPSG3857, 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", "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} {"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> </script>
@ -87,7 +87,7 @@
} }
trajeto_json_add({"features": []}); trajeto_json_add({"features": []});
trajeto_json.addTo(map_0a65390b914a9d20a49b9ea06134c652); trajeto_json.addTo(map_4450d383ac9fb1f3116e73305183afb1);
function adicionarGeometria(novaGeometria) { function adicionarGeometria(novaGeometria) {
trajeto_json.addData(novaGeometria); trajeto_json.addData(novaGeometria);
@ -145,7 +145,7 @@
var marcadorDinamico = L.marker([0, 0], { var marcadorDinamico = L.marker([0, 0], {
icon: customIcon icon: customIcon
}).addTo(map_0a65390b914a9d20a49b9ea06134c652); }).addTo(map_4450d383ac9fb1f3116e73305183afb1);
// Conectar ao broker MQTT // Conectar ao broker MQTT
const client = mqtt.connect('ws://localhost:9001'); // Use wss para conexão segura const client = mqtt.connect('ws://localhost:9001'); // Use wss para conexão segura
@ -183,7 +183,7 @@
marcadorDinamico.setRotationAngle(angulo); marcadorDinamico.setRotationAngle(angulo);
adicionarCoordenada("Tj", [novaLongitude, novaLatitude]); adicionarCoordenada("Tj", [novaLongitude, novaLatitude]);
map_0a65390b914a9d20a49b9ea06134c652.setView(novaPosicao, map_0a65390b914a9d20a49b9ea06134c652.getZoom()); map_4450d383ac9fb1f3116e73305183afb1.setView(novaPosicao, map_4450d383ac9fb1f3116e73305183afb1.getZoom());
}); });
function calcularOrientacao(P1latitude, P1longitude, P2latitude, P2longitude) { 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.csproj.CoreCompileInputs.cache
C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.exe 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.pdb
C:\ZendionInc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.csproj.CopyComplete C:\ZendionINC\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.csproj.Up2Date