diff --git a/AgroBase/AgroBase/AgroBase.csproj b/AgroBase/AgroBase/AgroBase.csproj
index 170a72d3c..06f4115da 100644
--- a/AgroBase/AgroBase/AgroBase.csproj
+++ b/AgroBase/AgroBase/AgroBase.csproj
@@ -589,6 +589,7 @@
+
diff --git a/AgroBase/AgroBase/Forms/frmMKS.cs b/AgroBase/AgroBase/Forms/frmMKS.cs
index 01fe84291..7fcf0d045 100644
--- a/AgroBase/AgroBase/Forms/frmMKS.cs
+++ b/AgroBase/AgroBase/Forms/frmMKS.cs
@@ -2375,14 +2375,14 @@ namespace AgroBase.Forms
private bool MKSIniciado()
{
- CanService.InicializarCanal();
+ CanManager.CanService.Inicializar();
byte addr = FuncoesGlobais.StringToHexByte(cmbEndereco.Text);
- if (CanService.IsConnected && MKS057DCanService.DadosLeitura.Any(x => x.EnderecoTx == addr && !x.Iniciado))
+ if (CanManager.CanService.IsConnected && MKS057DCanService.DadosLeitura.Any(x => x.EnderecoTx == addr && !x.Iniciado))
{
MKS057DCanService.RequisitarDado(addr, addr, MKS057DCanService.MksHandler.MksFuncCode.Versao);
}
- return CanService.IsConnected;
+ return CanManager.CanService.IsConnected;
}
private void btnMovimentoCAN_Click(object sender, EventArgs e)
@@ -2413,7 +2413,7 @@ namespace AgroBase.Forms
private async void btnRequisitarDados_Click(object sender, EventArgs e)
{
byte addr = FuncoesGlobais.StringToHexByte(cmbEndereco.Text);
- CanService.RegistrarHandler(addr, MKS057DCanService._MksHandler);
+ CanManager.CanService.RegistrarHandler(addr, MKS057DCanService._MksHandler);
await tmrReq_Tick();
}
diff --git a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs
index a7689cf24..cea10e9de 100644
--- a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs
+++ b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs
@@ -501,11 +501,11 @@ namespace AgroBase.Models.Modules
public async Task VerificaDispositivoConectado()
{
- if (!CanService.IsConnected) return false;
+ if (!CanManager.CanService.IsConnected) return false;
if (Variaveis.OperacaoEmAndamento.DispAtu == null) return false;
- CanService.RegistrarHandler(_EnderecoCAN_Rx, _AtuHandler);
+ CanManager.CanService.RegistrarHandler(_EnderecoCAN_Rx, _AtuHandler);
RequisitarDadosModulo(Variaveis.ID_Num_sMOD, CanMessagePosicaoDados.Status, CanMessagePosicaoDados.Status, true);
@@ -529,7 +529,7 @@ namespace AgroBase.Models.Modules
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Dispositivo = DadosLeitura.Dispositivo,
- Endereco = CanService._portName,
+ Endereco = CanManager.CanService._portName,
Versao = DadosLeitura.Versao.ToString(),
Mod_ID = Modulo_ID
});
diff --git a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs
index a97d27755..7e5043c88 100644
--- a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs
+++ b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs
@@ -1748,11 +1748,11 @@ namespace AgroBase.Models.Modules
public async Task VerificaDispositivoConectado()
{
- if (!CanService.IsConnected) return false;
+ if (!CanManager.CanService.IsConnected) return false;
if (Variaveis.OperacaoEmAndamento.DispSen == null) return false;
- CanService.RegistrarHandler(_EnderecoCAN_Rx, _SenHandler);
+ CanManager.CanService.RegistrarHandler(_EnderecoCAN_Rx, _SenHandler);
RequisitarDadosModulo(Variaveis.ID_Num_sMOD, CanMessagePosicaoDados.Status, CanMessagePosicaoDados.Status, true);
@@ -1775,7 +1775,7 @@ namespace AgroBase.Models.Modules
{
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
- Endereco = CanService._portName,
+ Endereco = CanManager.CanService._portName,
Dispositivo = DadosLeitura.Dispositivo,
Versao = DadosLeitura.Versao.ToString(),
Mod_ID = Modulo_ID,
@@ -2801,7 +2801,7 @@ namespace AgroBase.Models.Modules
var Dados = Variaveis.OperacaoEmAndamento.DispSen.Dados;
- Console.WriteLine($"[SEN] Componente={componente.ToString()}, ID_Num={ID_Num}, Posicao={posicao.ToString()}, Data={FuncoesGlobais.ConverterComandoBytesParaTexto(data)}");
+ //Console.WriteLine($"[SEN] Componente={componente.ToString()}, ID_Num={ID_Num}, Posicao={posicao.ToString()}, Data={FuncoesGlobais.ConverterComandoBytesParaTexto(data)}");
switch (componente)
{
@@ -2815,7 +2815,7 @@ namespace AgroBase.Models.Modules
bool conectado = data[3] == 1;
int versao = data[4];
- Console.WriteLine($"[SEN] Resposta {ID_Num} recebida. Tipo={tipoModulo}, Conectado={conectado}, Versão={versao}");
+ //Console.WriteLine($"[SEN] Resposta {ID_Num} recebida. Tipo={tipoModulo}, Conectado={conectado}, Versão={versao}");
Dados.DadosLeitura.Conectado = conectado;
Dados.DadosLeitura.Dispositivo = tipoModulo;
@@ -2951,7 +2951,7 @@ namespace AgroBase.Models.Modules
{
double latenciaLoop = ConverterByteParaDouble(data, 2) * 100;
Dados.DadosLeitura.LatenciaLoop = Convert.ToInt32(latenciaLoop);
- Console.WriteLine($"[SEN] Ciclo concluido. Latencia de loop: {latenciaLoop} ms");
+ //Console.WriteLine($"[SEN] Ciclo concluido. Latencia de loop: {latenciaLoop} ms");
break;
}
}
diff --git a/AgroBase/AgroBase/Services/CANService.cs b/AgroBase/AgroBase/Services/CANService.cs
index 15d99c356..967481494 100644
--- a/AgroBase/AgroBase/Services/CANService.cs
+++ b/AgroBase/AgroBase/Services/CANService.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -10,6 +11,30 @@ using static WaveshareCANFDService;
namespace AgroBase.Services
{
+ public class CanManager
+ {
+ public static bool UseCanSerial = true;
+
+ private static CanServiceWaveshare CanWaveshare = new CanServiceWaveshare();
+ private static CanServiceSerial CanSerial = new CanServiceSerial();
+
+ public static ICanService CanService
+ {
+ get
+ {
+ if (UseCanSerial)
+ {
+ return CanSerial;
+ }
+ else
+ {
+ return CanWaveshare;
+ }
+ }
+ }
+
+ }
+
public class CanMessage
{
public DateTime Momento { get; set; }
@@ -122,30 +147,41 @@ namespace AgroBase.Services
void ProcessarMensagem(CanMessage mensagem);
}
- public class CanService : IDisposable
+ public interface ICanService : IDisposable
{
- public static WaveshareCANFDService Connector = new WaveshareCANFDService(0);
- public static string _portName = "CAN-FD";
- public static bool IsConnected { get; private set; }
- public static bool Iniciado
+ void RegistrarHandler(byte endereco_rx, ICanMessageHandler handler);
+ bool Inicializar(SerialPort Porta = null);
+ void AdicionarMensagemNaFila(T_Code Dispositivo, byte idTx, byte idRx, byte funcCodeTx, byte funcCodeRx, byte[] payload = null, bool get = true);
+ void Fechar();
+ string _portName { get; set; }
+ bool Iniciado { get; }
+ bool IsConnected { get; }
+ }
+
+ public class CanServiceWaveshare : ICanService
+ {
+ public WaveshareCANFDService Connector = new WaveshareCANFDService(0);
+ public string _portName { get; set; } = "CAN-FD";
+ public bool IsConnected { get; private set; }
+ public bool Iniciado
{
get
{
return SerialService.DispositivosCan.Any(d => SerialService.DispositivosMapeados.Any(x => x.Status == StatusModulo.Operante && x.Dispositivo == d));
}
}
- private static AsyncTaskTimerModel tmrEnviarCAN;
- private static AsyncTaskTimerModel tmrOuvirCAN;
- private static AsyncTaskTimerModel tmrProcessarCAN;
- private static StringBuilder SerialCANBuffer = new StringBuilder();
- private static ConcurrentQueue<(byte, byte[])> FramesRecebidos = new ConcurrentQueue<(byte, byte[])>();
- private static readonly ConcurrentDictionary _roteadores = new ConcurrentDictionary();
- private static byte? _ultimoIdEnviado = null;
- private static List MensagensPendentes = new List();
- private static readonly object _LockMensagens = new object();
- private static bool DebugMode = false;
+ private AsyncTaskTimerModel tmrEnviarCAN;
+ private AsyncTaskTimerModel tmrOuvirCAN;
+ private AsyncTaskTimerModel tmrProcessarCAN;
+ private StringBuilder SerialCANBuffer = new StringBuilder();
+ private ConcurrentQueue<(byte, byte[])> FramesRecebidos = new ConcurrentQueue<(byte, byte[])>();
+ private readonly ConcurrentDictionary _roteadores = new ConcurrentDictionary();
+ private byte? _ultimoIdEnviado = null;
+ private List MensagensPendentes = new List();
+ private readonly object _LockMensagens = new object();
+ private bool DebugMode = false;
- private static void MostrarLog(string message, byte id)
+ private void MostrarLog(string message, byte id)
{
if (DebugMode && new List() { 0x01 }.Contains(id))
{
@@ -153,13 +189,13 @@ namespace AgroBase.Services
}
}
- public static void RegistrarHandler(byte endereco_rx, ICanMessageHandler handler)
+ public void RegistrarHandler(byte endereco_rx, ICanMessageHandler handler)
{
_roteadores[endereco_rx] = handler;
MostrarLog($"Roteador registrado: {endereco_rx.ToString("X")}", endereco_rx);
}
- public static bool InicializarCanal()
+ public bool Inicializar(SerialPort Porta = null)
{
bool canIniciado = Connector.IsOpen;
@@ -202,7 +238,7 @@ namespace AgroBase.Services
return canIniciado;
}
- private static async Task ProcessarCAN()
+ private async Task ProcessarCAN()
{
int mensagensParaProcessar = Math.Min(FramesRecebidos.Count, 10);
@@ -221,7 +257,7 @@ namespace AgroBase.Services
LimparMensagensAntigas();
}
- private static void ProcessarFrameCAN((byte, byte[]) frame)
+ private void ProcessarFrameCAN((byte, byte[]) frame)
{
byte id = frame.Item1;
byte[] data = frame.Item2;
@@ -268,7 +304,7 @@ namespace AgroBase.Services
}
}
- public static void AdicionarMensagemNaFila(T_Code Dispositivo, byte idTx, byte idRx, byte funcCodeTx, byte funcCodeRx, byte[] payload = null, bool get = true)
+ public void AdicionarMensagemNaFila(T_Code Dispositivo, byte idTx, byte idRx, byte funcCodeTx, byte funcCodeRx, byte[] payload = null, bool get = true)
{
if (!Connector.IsOpen) return;
@@ -313,7 +349,7 @@ namespace AgroBase.Services
}
}
- private static CanMessage ObterProximaMensagem()
+ private CanMessage ObterProximaMensagem()
{
List mensagensPendentes;
@@ -365,7 +401,7 @@ namespace AgroBase.Services
return proximaMsg;
}
- private static async Task EnviarCAN()
+ private async Task EnviarCAN()
{
if (!Connector.IsOpen) return;
@@ -396,7 +432,7 @@ namespace AgroBase.Services
}
}
- private static string CriarFrame(CanMessage msg)
+ private string CriarFrame(CanMessage msg)
{
string frame = $"t{msg.IdTx:X3}{msg.DataTx.Length}";
foreach (byte b in msg.DataTx)
@@ -407,7 +443,7 @@ namespace AgroBase.Services
return frame;
}
- private static bool EnviarComando(string comando, CanMessage msg = null)
+ private bool EnviarComando(string comando, CanMessage msg = null)
{
if (Connector.IsOpen)
{
@@ -427,7 +463,7 @@ namespace AgroBase.Services
return false;
}
- private static void LimparMensagensAntigas()
+ private void LimparMensagensAntigas()
{
var agora = DateTime.Now;
@@ -448,7 +484,7 @@ namespace AgroBase.Services
}
}
- public static void Fechar()
+ public void Fechar()
{
tmrOuvirCAN?.Dispose();
tmrEnviarCAN?.Dispose();
@@ -473,7 +509,7 @@ namespace AgroBase.Services
Fechar();
}
- private static byte CalcularChecksum(byte id, byte[] data)
+ private byte CalcularChecksum(byte id, byte[] data)
{
int soma = id;
foreach (var b in data)
@@ -481,7 +517,7 @@ namespace AgroBase.Services
return (byte)(soma & 0xFF);
}
- private static string GerarChaveMensagem(T_Code Dispositivo, byte Id, byte[] data)
+ private string GerarChaveMensagem(T_Code Dispositivo, byte Id, byte[] data)
{
byte parametro = 0x00;
diff --git a/AgroBase/AgroBase/Services/DispositivosService.cs b/AgroBase/AgroBase/Services/DispositivosService.cs
index c4455716a..631b2fa20 100644
--- a/AgroBase/AgroBase/Services/DispositivosService.cs
+++ b/AgroBase/AgroBase/Services/DispositivosService.cs
@@ -74,7 +74,7 @@ namespace AgroBase.Comum
{
payload.AddRange(dados);
}
- CanService.AdicionarMensagemNaFila(Dispositivo, Dados._EnderecoCAN_Tx, Dados._EnderecoCAN_Rx, (byte)PosicaoTx, (byte)PosicaoRx, payload.ToArray(), get);
+ CanManager.CanService.AdicionarMensagemNaFila(Dispositivo, Dados._EnderecoCAN_Tx, Dados._EnderecoCAN_Rx, (byte)PosicaoTx, (byte)PosicaoRx, payload.ToArray(), get);
}
public Control InstanciarDispositivo(int index)
diff --git a/AgroBase/AgroBase/Services/MKS057DCanService.cs b/AgroBase/AgroBase/Services/MKS057DCanService.cs
index 07b27e169..9514df222 100644
--- a/AgroBase/AgroBase/Services/MKS057DCanService.cs
+++ b/AgroBase/AgroBase/Services/MKS057DCanService.cs
@@ -19,7 +19,7 @@ namespace AgroBase.Services
{
get
{
- return CanService.IsConnected && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Dir) && DadosLeitura.Any(x => x.Iniciado);
+ return CanManager.CanService.IsConnected && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Dir) && DadosLeitura.Any(x => x.Iniciado);
}
}
public static bool Referenciando
@@ -40,7 +40,7 @@ namespace AgroBase.Services
public static async Task VerificaDispositivoConectado()
{
- if (!CanService.IsConnected) return false;
+ if (!CanManager.CanService.IsConnected) return false;
if (Variaveis.OperacaoEmAndamento.DispMvd == null) return false;
@@ -48,7 +48,7 @@ namespace AgroBase.Services
foreach (var Modulo in Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Where(x => !x.DirMotor.Inicializado))
{
- CanService.RegistrarHandler(Modulo.DirMotor._EnderecoCAN_Rx, _MksHandler);
+ CanManager.CanService.RegistrarHandler(Modulo.DirMotor._EnderecoCAN_Rx, _MksHandler);
RequisitarDado(Modulo.DirMotor._EnderecoCAN_Tx, Modulo.DirMotor._EnderecoCAN_Rx, MksFuncCode.Versao);
@@ -67,7 +67,7 @@ namespace AgroBase.Services
DefinirDispositivo(Mod_IDs);
}
- return Iniciado;
+ return Mod_IDs.Any();
}
private static void DefinirDispositivo(List Mod_IDs)
@@ -84,7 +84,7 @@ namespace AgroBase.Services
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Dispositivo = T_Code.Dir,
- Endereco = CanService._portName,
+ Endereco = CanManager.CanService._portName,
Versao = (Leitura.FV ?? "").ToString(),
Mod_ID = Mod_ID,
});
@@ -120,7 +120,7 @@ namespace AgroBase.Services
private static void EnviarComando(T_Code Dispositivo, byte idTx, byte idRx, byte funcCode, byte[] payload = null, bool get = true)
{
- CanService.AdicionarMensagemNaFila(Dispositivo, idTx, idRx, funcCode, funcCode, payload, get);
+ CanManager.CanService.AdicionarMensagemNaFila(Dispositivo, idTx, idRx, funcCode, funcCode, payload, get);
}
public static void SetModoOperacao(byte idTx, byte idRx, byte modo)
diff --git a/AgroBase/AgroBase/Services/OIDCanService.cs b/AgroBase/AgroBase/Services/OIDCanService.cs
index 946f8a295..2d2182690 100644
--- a/AgroBase/AgroBase/Services/OIDCanService.cs
+++ b/AgroBase/AgroBase/Services/OIDCanService.cs
@@ -20,7 +20,7 @@ namespace AgroBase.Services
{
get
{
- return CanService.IsConnected && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mov) && DadosLeitura.Any(x => x.Iniciado);
+ return CanManager.CanService.IsConnected && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mov) && DadosLeitura.Any(x => x.Iniciado);
}
}
public static int TaxaAmostragem
@@ -33,7 +33,7 @@ namespace AgroBase.Services
public static async Task VerificaDispositivoConectado()
{
- if (!CanService.IsConnected) return false;
+ if (!CanManager.CanService.IsConnected) return false;
if (Variaveis.OperacaoEmAndamento.DispMvd == null) return false;
@@ -41,7 +41,7 @@ namespace AgroBase.Services
foreach (var Modulo in Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Where(x => !x.MovMotor.Inicializado))
{
- CanService.RegistrarHandler(Modulo.MovMotor._EnderecoCAN_Rx, _OidHandler);
+ CanManager.CanService.RegistrarHandler(Modulo.MovMotor._EnderecoCAN_Rx, _OidHandler);
RequisitarDado(Modulo.MovMotor._EnderecoCAN_Tx, Modulo.MovMotor._EnderecoCAN_Rx, OidParametros.CodErro);
@@ -60,7 +60,7 @@ namespace AgroBase.Services
DefinirDispositivo(Mod_IDs);
}
- return Iniciado;
+ return Mod_IDs.Any();
}
private static void DefinirDispositivo(List Mod_IDs)
@@ -89,7 +89,7 @@ namespace AgroBase.Services
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Dispositivo = T_Code.Mov,
- Endereco = CanService._portName,
+ Endereco = CanManager.CanService._portName,
Versao = "1.0",
Mod_ID = Mod_ID,
});
@@ -103,7 +103,7 @@ namespace AgroBase.Services
private static void EnviarComando(T_Code Dispositivo, byte idTx, byte idRx, byte funcCode, byte[] payload = null, bool get = true)
{
- CanService.AdicionarMensagemNaFila(Dispositivo, idTx, idRx, funcCode, funcCode, payload, get);
+ CanManager.CanService.AdicionarMensagemNaFila(Dispositivo, idTx, idRx, funcCode, funcCode, payload, get);
}
public static void RequisitarDado(byte idTx, byte idRx, OidParametros dado)
diff --git a/AgroBase/AgroBase/Services/SerialCanService.cs b/AgroBase/AgroBase/Services/SerialCanService.cs
new file mode 100644
index 000000000..d75bd0de5
--- /dev/null
+++ b/AgroBase/AgroBase/Services/SerialCanService.cs
@@ -0,0 +1,468 @@
+using AgroBase.Models;
+using System;
+using System.Collections.Concurrent;
+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;
+
+namespace AgroBase.Services
+{
+ public class CanServiceSerial : ICanService
+ {
+ public SerialPort _PortaCAN;
+ public string _portName { get; set; }
+ private int _baudRate;
+ private object _lock = new object();
+ public bool IsConnected { get; private set; }
+ public bool Iniciado
+ {
+ get
+ {
+ return SerialService.DispositivosCan.Any(d => SerialService.DispositivosMapeados.Any(x => x.Status != StatusModulo.Desconectado && x.Dispositivo == d));
+ }
+ }
+ private AsyncTaskTimerModel tmrEnviarCAN;
+ private AsyncTaskTimerModel tmrOuvirCAN;
+ private AsyncTaskTimerModel tmrProcessarCAN;
+ private ConcurrentQueue FramesRecebidos = new ConcurrentQueue();
+ private StringBuilder SerialCANBuffer = new StringBuilder();
+ private readonly ConcurrentDictionary _roteadores = new ConcurrentDictionary();
+ private byte? _ultimoIdEnviado = null;
+
+ private List Mensagens = new List();
+ private readonly object _LockMensagens = new object();
+
+ private bool DebugMode = false;
+ private void MostrarLog(string message, byte id)
+ {
+ if (DebugMode && new List() { 0x01 }.Contains(id))
+ {
+ Console.WriteLine($"[CAN] {message}");
+ }
+ }
+
+ public void RegistrarHandler(byte endereco_rx, ICanMessageHandler handler)
+ {
+ _roteadores[endereco_rx] = handler;
+ MostrarLog($"Roteador registrado: {endereco_rx.ToString("X")}", endereco_rx);
+ }
+
+ public bool Inicializar(SerialPort Porta = null)
+ {
+ if (Porta == null && (_PortaCAN?.IsOpen ?? false))
+ {
+ Porta = _PortaCAN;
+ }
+
+ if (!IsConnected)
+ {
+ Porta.Close();
+ }
+
+ if (_PortaCAN == null || !IsConnected)
+ {
+ lock (_lock)
+ {
+ _portName = Porta.PortName;
+ _baudRate = 115200;
+
+ _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);
+
+ tmrOuvirCAN?.Dispose();
+ tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 5);
+ tmrOuvirCAN.Start();
+
+ tmrEnviarCAN?.Dispose();
+ tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 5);
+ tmrEnviarCAN.Start();
+
+ tmrProcessarCAN?.Dispose();
+ tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 10);
+ tmrProcessarCAN.Start();
+
+ IsConnected = true;
+ }
+ }
+
+ if (_PortaCAN != null && !_PortaCAN.IsOpen)
+ {
+ _PortaCAN.Open();
+ }
+
+ return IsConnected;
+ }
+
+ private async Task ProcessarCAN()
+ {
+ int mensagensParaProcessar = Math.Min(FramesRecebidos.Count, 10);
+
+ for (int i = 0; i < mensagensParaProcessar; i++)
+ {
+ if (FramesRecebidos.TryDequeue(out string frame))
+ {
+ ProcessarFrameCAN(frame);
+ }
+ else
+ {
+ // A fila ficou vazia antes de atingir o limite
+ break;
+ }
+ }
+ LimparMensagensAntigas();
+ }
+
+ private async Task OuvirCAN()
+ {
+ if (_PortaCAN.BytesToRead > 0)
+ {
+ byte[] tempBuffer = await SerialService.LerDadosDaPortaSerialAsync(_PortaCAN, _PortaCAN.BytesToRead);
+
+ foreach (byte b in tempBuffer)
+ {
+ char c = (char)b;
+
+ if (c == '\r')
+ {
+ var frame = SerialCANBuffer.ToString();
+ SerialCANBuffer.Clear();
+
+ if (!string.IsNullOrWhiteSpace(frame))
+ {
+ FramesRecebidos.Enqueue(frame);
+ }
+ }
+ else
+ {
+ SerialCANBuffer.Append(c);
+ }
+ }
+ }
+ }
+
+ private void ProcessarFrameCAN(string frame)
+ {
+ // Ex: t00183301020304
+ if (!frame.StartsWith("t")) return;
+
+ try
+ {
+ if (frame.Length < 5) return;
+
+ int id = Convert.ToInt32(frame.Substring(1, 3), 16);
+ int len = int.Parse(frame.Substring(4, 1));
+
+ byte[] data = new byte[len];
+ for (int i = 0; i < len; i++)
+ {
+ data[i] = Convert.ToByte(frame.Substring(5 + i * 2, 2), 16);
+ }
+
+ MostrarLog($"Processando frame: {frame}", (byte)id);
+
+ if (_roteadores.TryGetValue((byte)id, out ICanMessageHandler handler))
+ {
+
+ }
+
+ T_Code dispositivo = handler?.Dispositivo ?? T_Code.Vzo;
+ byte fCodeRx = data[0];
+ byte parametroRx = data[1];
+ string chave = GerarChaveMensagem(dispositivo, (byte)id, data);
+
+ CanMessage mensagem = null;
+ lock (_LockMensagens)
+ {
+ mensagem = Mensagens.FirstOrDefault(x => x.Enviado && !x.Respondido && x.Dispositivo == x.Dispositivo && x.IdRx == id && x.DataTx[1] == data[1]);
+ }
+ if (mensagem == null)
+ {
+ mensagem = new CanMessage { Dispositivo = dispositivo, IdTx = (byte)id, IdRx = (byte)id, funcCodeRx = fCodeRx, DataRx = data, ChaveInterna = chave };
+ }
+ mensagem.DataRx = data;
+ mensagem.Respondido = true;
+ mensagem.RespondidoEm = DateTime.Now;
+
+ if ((handler?.Dispositivo ?? T_Code.Vzo) != T_Code.Vzo)
+ {
+ handler.ProcessarMensagem(mensagem);
+ }
+ else
+ {
+ MostrarLog($"Roteador não registrado! ID_Num não tratado: 0x{id:X2}, fCodeRx: 0x{fCodeRx:X2}, frame: {frame}", (byte)id);
+ }
+
+
+
+
+ /*byte[] data = new byte[len];
+ for (int i = 0; i < len; i++)
+ {
+ data[i] = Convert.ToByte(frame.Substring(5 + i * 2, 2), 16);
+ }
+
+ byte funcCodeRx = data[0];
+ var mensagem = new CanMessage();
+
+ lock (Mensagens)
+ {
+ mensagem = Mensagens.Where(x => x.IdTx == id).OrderBy(x => x.EnviadoEm).FirstOrDefault(x => x.Enviado && !x.Respondido && x.funcCodeRx == funcCodeRx);
+ }
+
+ if (mensagem == null)
+ {
+ mensagem = new CanMessage { IdTx = (byte)id, DataRx = data };
+ }
+
+ mensagem.DataRx = data;
+ mensagem.Respondido = true;
+ mensagem.RespondidoEm = DateTime.Now;
+
+ if (_roteadores.TryGetValue(mensagem.IdTx, out var handler))
+ {
+ handler.ProcessarMensagem(mensagem);
+ }
+ else
+ {
+ Console.WriteLine($"[CAN] ID_Num não tratado: 0x{funcCodeRx:X2}");
+ }*/
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[CAN] Erro ao processar frame: {ex.Message}");
+ }
+ }
+
+ public void AdicionarMensagemNaFila(T_Code Dispositivo, byte idTx, byte idRx, byte funcCodeTx, byte funcCodeRx, byte[] payload = null, bool get = true)
+ {
+ if (_PortaCAN?.IsOpen != true) return;
+
+ var dados = new List() { funcCodeTx };
+
+ if (payload != null)
+ dados.AddRange(payload);
+
+ if (Dispositivo == T_Code.Mks)
+ {
+ byte crc = CalcularChecksum(idTx, dados.ToArray());
+ dados.Add(crc);
+ }
+
+ var novaMensagem = new CanMessage
+ {
+ Momento = DateTime.Now,
+ Dispositivo = Dispositivo,
+ IdTx = idTx,
+ IdRx = idRx,
+ funcCodeTx = funcCodeTx,
+ funcCodeRx = funcCodeRx,
+ DataTx = dados.ToArray(),
+ ComResposta = get,
+ ChaveInterna = GerarChaveMensagem(Dispositivo, idRx, dados.ToArray())
+ };
+
+ bool mensagemNaFila = false;
+
+ lock (_LockMensagens)
+ {
+ mensagemNaFila = Mensagens.Any(x => (!x.Enviado || (x.ComResposta && x.Enviado && !x.Respondido)) && x.IdTx == idTx && x.IdRx == idRx && x.DataTx.SequenceEqual(dados.ToArray()));
+ if (!mensagemNaFila)
+ {
+ Mensagens.Add(novaMensagem);
+ MostrarLog($"Mensagem adicionada na fila. ID: {novaMensagem.IdTx}, Data: {FuncoesGlobais.ConverterComandoBytesParaTexto(novaMensagem.DataTx)}", idTx);
+ }
+ else
+ {
+ MostrarLog($"Mensagem já pendente e idêntica. ID: {novaMensagem.IdTx}, Data: {FuncoesGlobais.ConverterComandoBytesParaTexto(novaMensagem.DataTx)}", idTx);
+ }
+ }
+ }
+
+ private CanMessage ObterProximaMensagem()
+ {
+ List mensagensPendentes;
+
+ lock (_LockMensagens)
+ {
+ mensagensPendentes = Mensagens
+ .Where(x => !x.Enviado)
+ .ToList();
+ }
+
+ if (!mensagensPendentes.Any())
+ return null;
+
+ // Primeiro tenta pegar mensagens com Get == false
+ var mensagensPrioritarias = mensagensPendentes
+ .Where(x => !x.ComResposta)
+ .ToList();
+
+ // Se não houver mensagens prioritárias, considera todas
+ var mensagensParaProcessar = mensagensPrioritarias.Any()
+ ? mensagensPrioritarias
+ : mensagensPendentes;
+
+ // Agrupa por IdTx e ordena os grupos
+ var idsDisponiveis = mensagensParaProcessar
+ .Select(x => x.IdTx)
+ .Distinct()
+ .OrderBy(x => x)
+ .ToList();
+
+ byte proximoId;
+
+ if (!_ultimoIdEnviado.HasValue || !idsDisponiveis.Contains(_ultimoIdEnviado.Value))
+ {
+ 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 = mensagensParaProcessar
+ .Where(x => x.IdTx == proximoId)
+ .OrderBy(x => x.Momento)
+ .FirstOrDefault();
+
+ return proximaMsg;
+ }
+
+ private async Task EnviarCAN()
+ {
+ if (_PortaCAN?.IsOpen != true) return;
+
+ CanMessage msg = ObterProximaMensagem();
+
+ if (msg != null)
+ {
+ string frame = CriarFrame(msg);
+
+ if (_ultimoIdEnviado.HasValue && msg.IdTx == _ultimoIdEnviado.Value)
+ {
+ await Task.Delay(5);
+ }
+
+ if (msg.Dispositivo == T_Code.Mks)
+ {
+ await Task.Delay(10);
+ }
+
+ if (!EnviarComando(frame))
+ {
+ MostrarLog("Erro ao enviar frame", msg.IdTx);
+ }
+
+ msg.Enviado = true;
+ msg.EnviadoEm = DateTime.Now;
+ _ultimoIdEnviado = msg.IdTx;
+ }
+ }
+
+ private string CriarFrame(CanMessage msg)
+ {
+ string frame = $"t{msg.IdTx:X3}{msg.DataTx.Length}";
+ foreach (byte b in msg.DataTx)
+ frame += b.ToString("X2");
+
+ frame += "\r";
+
+ return frame;
+ }
+
+ private bool EnviarComando(string comando)
+ {
+ if (_PortaCAN?.IsOpen == true)
+ {
+ _PortaCAN.Write(comando);
+ //Console.WriteLine($"[CAN] Frame enviado: {comando}");
+ return true;
+ }
+ return false;
+ }
+
+ private void LimparMensagensAntigas()
+ {
+ var agora = DateTime.Now;
+
+ lock (_LockMensagens)
+ {
+ List mensagens = Mensagens
+ .Where(x =>
+ (!x.ComResposta && x.Enviado) ||
+ (x.ComResposta && x.Respondido) ||
+ (x.ComResposta && x.Enviado && !x.Respondido && x.EnviadoEm < agora.AddSeconds(-1)) ||
+ (x.Momento < agora.AddSeconds(-30))
+ )
+ .ToList();
+ foreach (var item in mensagens)
+ {
+ Mensagens.Remove(item);
+ }
+ }
+ }
+
+ public void Fechar()
+ {
+ tmrOuvirCAN?.Dispose();
+ tmrEnviarCAN?.Dispose();
+ tmrProcessarCAN?.Dispose();
+
+ lock (_LockMensagens)
+ {
+ Mensagens.Clear();
+ }
+
+ SerialCANBuffer.Clear();
+ FramesRecebidos = new ConcurrentQueue();
+ _roteadores.Clear();
+ _ultimoIdEnviado = null;
+
+ if (_PortaCAN?.IsOpen == true)
+ {
+ EnviarComando("C\r");
+ _PortaCAN.Close();
+ }
+
+ IsConnected = false;
+ }
+
+ public void Dispose()
+ {
+ Fechar();
+ }
+
+ private byte CalcularChecksum(byte id, byte[] data)
+ {
+ int soma = id;
+ foreach (var b in data)
+ soma += b;
+ return (byte)(soma & 0xFF);
+ }
+
+ private string GerarChaveMensagem(T_Code Dispositivo, byte Id, byte[] data)
+ {
+ byte parametro = 0x00;
+
+ // Para dispositivos que não sejam MKS, usar DataTx[1] se existir
+ if (Dispositivo != T_Code.Mks && (data?.Length ?? 0) > 1)
+ {
+ parametro = data[1];
+ }
+
+ return $"{Id}_{data[0]}_{parametro}";
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/AgroBase/AgroBase/Services/SerialService.cs b/AgroBase/AgroBase/Services/SerialService.cs
index 3472b5838..2d2dfae74 100644
--- a/AgroBase/AgroBase/Services/SerialService.cs
+++ b/AgroBase/AgroBase/Services/SerialService.cs
@@ -222,6 +222,18 @@ namespace AgroBase.Services
continue;
}
}
+
+ if (CanManager.UseCanSerial && !CanManager.CanService.Iniciado)
+ {
+ AtualizarConsole($"{PortaCom} - Procurando dispositivos no barramento CAN");
+ bool dispositivoCan = await ProcurarDispositivosCAN(_Porta);
+ if (dispositivoCan)
+ {
+ _Porta.Close();
+ AtualizarConsole("Barramento CAN encontrado");
+ continue;
+ }
+ }
}
if (Variaveis.IsAgroMonitor) return;
@@ -372,17 +384,17 @@ namespace AgroBase.Services
}
}
- private static async Task ProcurarDispositivosCAN()
+ private static async Task ProcurarDispositivosCAN(SerialPort Porta = null)
{
- if (!CanService.InicializarCanal())
+ if (!CanManager.CanService.Inicializar(Porta))
{
- AtualizarConsole($"Adaptador {CanService._portName} não conectado!");
+ AtualizarConsole($"Adaptador {CanManager.CanService._portName} não conectado!");
return false;
}
if (true && Variaveis.OperacaoEmAndamento.DispSen != null && !Variaveis.OperacaoEmAndamento.DispSen.Dados.Conectado)
{
- AtualizarConsole($"{CanService._portName} - Procurando dispositivo SEN");
+ AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo SEN");
bool DispSen = await Variaveis.OperacaoEmAndamento.DispSen.Dados.VerificaDispositivoConectado();
if (DispSen)
{
@@ -392,7 +404,7 @@ namespace AgroBase.Services
if (true && Variaveis.OperacaoEmAndamento.DispAtu != null && !Variaveis.OperacaoEmAndamento.DispAtu.Dados.ConexaoAtiva)
{
- AtualizarConsole($"{CanService._portName} - Procurando dispositivo ATU");
+ AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo ATU");
bool DispAtu = await Variaveis.OperacaoEmAndamento.DispAtu.Dados.VerificaDispositivoConectado();
if (DispAtu)
{
@@ -402,7 +414,7 @@ namespace AgroBase.Services
if (true && !MKS057DCanService.Referenciando && (!MKS057DCanService.Iniciado || MKS057DCanService.DadosLeitura.Count(x => x.Iniciado) < (Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.Count() ?? 4)))
{
- AtualizarConsole($"{CanService._portName} - Procurando dispositivos MKS");
+ AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivos MKS");
bool DispMks = await MKS057DCanService.VerificaDispositivoConectado();
if (DispMks)
{
@@ -412,7 +424,7 @@ namespace AgroBase.Services
if (true && (!OIDCanService.Iniciado || OIDCanService.DadosLeitura.Count(x => x.Iniciado) < (Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.Count() ?? 4)))
{
- AtualizarConsole($"{CanService._portName} - Procurando dispositivo OID");
+ AtualizarConsole($"{CanManager.CanService._portName} - Procurando dispositivo OID");
bool DispOid = await OIDCanService.VerificaDispositivoConectado();
if (DispOid)
{
@@ -420,7 +432,7 @@ namespace AgroBase.Services
}
}
- return CanService.Iniciado;
+ return CanManager.CanService.Iniciado;
}
private static void ProcurarDispositivosUSB()