ajustes de fluxo e insercao do ultrassom

This commit is contained in:
Diego Freitas 2024-08-22 17:06:58 -03:00
parent 957fc8f30c
commit 3098cbd04b
39 changed files with 2758 additions and 390 deletions

Binary file not shown.

View File

@ -406,6 +406,7 @@
<Compile Include="Models\MapasModel.cs" />
<Compile Include="Models\MensagemFilaModel.cs" />
<Compile Include="Models\MKS057DModel.cs" />
<Compile Include="Models\ModbusModel.cs" />
<Compile Include="Models\Modules\AtuadorModel.cs" />
<Compile Include="Models\Modules\DirecionalModel.cs" />
<Compile Include="Models\Modules\DispositivoBaseModel.cs" />
@ -423,6 +424,7 @@
<Compile Include="Models\PIDModel.cs" />
<Compile Include="Models\PZEMModel.cs" />
<Compile Include="Models\SonarModel.cs" />
<Compile Include="Models\UltrasonicA05Model.cs" />
<Compile Include="Models\Variaveis.cs" />
<Compile Include="Models\Visualizador3DModel.cs" />
<Compile Include="Models\WT901CModel.cs" />
@ -455,6 +457,7 @@
<Compile Include="Services\RS485Service.cs" />
<Compile Include="Services\SerialService.cs" />
<Compile Include="Services\SocketService.cs" />
<Compile Include="Services\UltrasonicA05Service.cs" />
<Compile Include="Services\Visualizador3DService.cs" />
<Compile Include="Services\WT901CService.cs" />
<Content Include="Python\Output\Mont.mtl">

View File

@ -224,8 +224,15 @@ namespace AgroBase.Forms.Sensoriamento
else
{
PZEMService.ModoLeitura = true;
var Comando = PZEMService.ComandoGetParametro(PZEMService.Parametros[cmbBateriaParametro.Text]);
PZEMService.EnviarComando(ModbusService._PortaModbus, Comando);
var Comando = new ModbusComandoModel()
{
Dispositivo = T_Code.Pzm,
Endereco = PZEMService.slaveAddress,
Comando = PZEMService.ComandoGetParametro(PZEMService.Parametros[cmbBateriaParametro.Text])
};
ModbusService.AdicionarComandoNaFila(Comando);
Task.Run(async () =>
{
await Task.Delay(1000);
@ -244,15 +251,25 @@ namespace AgroBase.Forms.Sensoriamento
}
else
{
var Comando = PZEMService.ComandoSetParametro(PZEMService.Parametros[cmbBateriaParametro.Text], Convert.ToInt32(nudBateriaValor.Value));
PZEMService.EnviarComando(ModbusService._PortaModbus, Comando);
var Comando = new ModbusComandoModel()
{
Dispositivo = T_Code.Pzm,
Endereco = PZEMService.slaveAddress,
Comando = PZEMService.ComandoSetParametro(PZEMService.Parametros[cmbBateriaParametro.Text], Convert.ToInt32(nudBateriaValor.Value))
};
ModbusService.AdicionarComandoNaFila(Comando);
}
}
private void btnBateriaCalibrar_Click(object sender, EventArgs e)
{
var Comando = PZEMService.ComandoCalibragem();
PZEMService.EnviarComando(ModbusService._PortaModbus, Comando);
var Comando = new ModbusComandoModel()
{
Dispositivo = T_Code.Pzm,
Endereco = PZEMService.slaveAddress,
Comando = PZEMService.ComandoCalibragem()
};
ModbusService.AdicionarComandoNaFila(Comando);
}

View File

@ -113,6 +113,9 @@ namespace AgroBase.Forms
this.lblEFA_SP = new System.Windows.Forms.Label();
this.lblM_EF = new System.Windows.Forms.Label();
this.picEF = new System.Windows.Forms.PictureBox();
this.lblUL_Pzm = new System.Windows.Forms.Label();
this.lblUL_Wit = new System.Windows.Forms.Label();
this.lblUL_A05 = new System.Windows.Forms.Label();
this.pnlFundo.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.chartET)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.chartDT)).BeginInit();
@ -129,6 +132,9 @@ namespace AgroBase.Forms
//
this.pnlFundo.AutoScroll = true;
this.pnlFundo.BackColor = System.Drawing.Color.White;
this.pnlFundo.Controls.Add(this.lblUL_A05);
this.pnlFundo.Controls.Add(this.lblUL_Wit);
this.pnlFundo.Controls.Add(this.lblUL_Pzm);
this.pnlFundo.Controls.Add(this.lblB12V);
this.pnlFundo.Controls.Add(this.lblB7V2);
this.pnlFundo.Controls.Add(this.lblB5V);
@ -952,6 +958,39 @@ namespace AgroBase.Forms
this.picEF.TabIndex = 90;
this.picEF.TabStop = false;
//
// lblUL_Pzm
//
this.lblUL_Pzm.AutoSize = true;
this.lblUL_Pzm.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblUL_Pzm.Location = new System.Drawing.Point(656, 731);
this.lblUL_Pzm.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lblUL_Pzm.Name = "lblUL_Pzm";
this.lblUL_Pzm.Size = new System.Drawing.Size(126, 12);
this.lblUL_Pzm.TabIndex = 178;
this.lblUL_Pzm.Text = "Ultima Leitura PZM: 00:00:00";
//
// lblUL_Wit
//
this.lblUL_Wit.AutoSize = true;
this.lblUL_Wit.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblUL_Wit.Location = new System.Drawing.Point(656, 743);
this.lblUL_Wit.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lblUL_Wit.Name = "lblUL_Wit";
this.lblUL_Wit.Size = new System.Drawing.Size(122, 12);
this.lblUL_Wit.TabIndex = 179;
this.lblUL_Wit.Text = "Ultima Leitura WIT: 00:00:00";
//
// lblUL_A05
//
this.lblUL_A05.AutoSize = true;
this.lblUL_A05.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblUL_A05.Location = new System.Drawing.Point(656, 755);
this.lblUL_A05.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lblUL_A05.Name = "lblUL_A05";
this.lblUL_A05.Size = new System.Drawing.Size(122, 12);
this.lblUL_A05.TabIndex = 180;
this.lblUL_A05.Text = "Ultima Leitura A05: 00:00:00";
//
// frmAcompanhamento
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1054,5 +1093,8 @@ namespace AgroBase.Forms
public System.Windows.Forms.Label lblB5V;
public System.Windows.Forms.Label lblB3V;
private System.Windows.Forms.Label lblEFM_Tensao;
public System.Windows.Forms.Label lblUL_Wit;
public System.Windows.Forms.Label lblUL_Pzm;
public System.Windows.Forms.Label lblUL_A05;
}
}

View File

@ -337,6 +337,9 @@ namespace AgroBase.Forms
Texto.Contains("5V") ? lblB5V :
Texto.Contains("7V2") ? lblB7V2 :
Texto.Contains("12V") ? lblB12V :
Texto.Contains("PZM") ? lblUL_Pzm :
Texto.Contains("WIT") ? lblUL_Wit :
Texto.Contains("A05") ? lblUL_A05 :
new Label();
if (lbl.InvokeRequired)
{

View File

@ -38,6 +38,7 @@ namespace AgroBase.Forms
FilaService.Inicializar();
BLD300RService.IniciarRotinas();
MKS057DService.IniciarRotinas();
ModbusService.IniciarRotinas();
}
private void frmInstancial_Shown(object sender, EventArgs e)

View File

@ -63,6 +63,7 @@ namespace AgroBase.Models
Mks = 111,
Cam = 112,
Knt = 113,
A05 = 114,
}
public enum F_Code

View File

@ -0,0 +1,44 @@
using OpenTK.Platform.Windows;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
namespace AgroBase.Models
{
public class ModbusModel
{
}
public class ModbusParametrosModel
{
public DateTime UltimaRequisicao { get; set; } = DateTime.MaxValue;
public string Descricao { get; set; }
public string Chave { get; set; }
public byte FuncaoGet { get; set; }
public byte FuncaoSet { get; set; }
public byte Registro { get; set; }
public byte N_Registros { get; set; }
public bool LeituraLoop { get; set; }
public bool LeituraGeral { get; set; }
public double Escala { get; set; }
public byte[] Valor { get; set; }
}
public class ModbusComandoModel
{
public DateTime Momento { get; set; } = DateTime.Now;
public T_Code Dispositivo { get; set; }
public byte Endereco { get; set; }
public byte[] Comando { get; set; }
public bool Enviado { get; set; } = false;
public int TamanhoEsperado { get; set; } = 3;
public int TimeoutResposta { get; set; } = 500;
public byte[] Resposta { get; set; }
public DateTime RespondidoEm { get; set; } = DateTime.MinValue;
public bool Verificacao { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AgroBase.Models
{
public class UltrasonicA05Model
{
public DateTime Momento { get; set; }
public byte Endereco { get; set; }
public int U1 { get; set; }
public int U2 { get; set; }
public int U3 { get; set; }
public int U4 { get; set; }
}
}

View File

@ -8,6 +8,7 @@ namespace AgroBase.Models
{
public class WT901CModel
{
public DateTime Momento { get; set; }
public string Versao { get; set; }
public DateTime DataHora { get; set; }
public double AccX { get; set; }

View File

@ -517,19 +517,25 @@ namespace AgroBase.Services
Parametro.Valor = bytes_resposta;
Parametro.UltimaRequisicao = DateTime.MaxValue;
ParametroLeitura.Valor = Parametro.Valor;
Leitura.UltimoComandoRecebido = DateTime.Now;
return true;
}
else if (Parametros.Any(x => x.FuncaoSet == resposta[1]))
{
Parametro.Valor = resposta.Skip(4).Take(2).ToArray();
ParametroLeitura.Valor = Parametro.Valor;
Leitura.UltimoComandoRecebido = DateTime.Now;
return true;
}
else
{
RegisrarErrosComunicacao(Addr, $"Resposta inválida ou código de função incorreto. {BitConverter.ToString(resposta)}");
}
ParametroLeitura.Valor = Parametro.Valor;
Leitura.UltimoComandoRecebido = DateTime.Now;
return true;
return false;
}
RegisrarErrosComunicacao(Addr, $"Resposta inválida. {BitConverter.ToString(resposta)}");

View File

@ -1,19 +1,21 @@
using AgroBase.Forms;
using AgroBase.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
namespace AgroBase.Services
{
public class ModbusService
{
public static readonly object _lock = new object();
public static int TaxaAmostragem { get; set; } = 500;
public static bool Verificando { get; set; } = false;
public static bool EnvioLiberado { get; set; } = true;
public static bool FilaEmEspera { get; set; } = false;
public static SerialPort _PortaModbus;
public static bool Iniciado
@ -39,33 +41,231 @@ namespace AgroBase.Services
}
}
public static List<ModbusComandoModel> FilaComandos = new List<ModbusComandoModel>();
private static readonly object FilaLock = new object();
private static System.Windows.Forms.Timer tmrLoopComandos = new System.Windows.Forms.Timer() { Interval = 100 };
public static async Task EnviarComando(byte[] Comando)
public static void IniciarRotinas()
{
while (!EnvioLiberado || Verificando)
Task.Run(() => ReceberDados());
if (!tmrLoopComandos.Enabled)
{
await Task.Delay(FilaEmEspera ? 200 : 100);
FilaEmEspera = true;
tmrLoopComandos.Tick += TmrLoopComandos_Tick;
tmrLoopComandos.Start();
}
}
public static void DefinirPortaCOM(SerialPort Porta)
{
if (!Iniciado)
{
Porta.Close();
}
FilaEmEspera = false;
if (frmInstancial.Fechando)
if (_PortaModbus == null || !Iniciado)
{
EnvioLiberado = true;
return;
lock (_lock)
{
_PortaModbus = new SerialPort();
_PortaModbus.BaudRate = 9600;
_PortaModbus.PortName = Porta.PortName;
}
}
if (_PortaModbus != null && !_PortaModbus.IsOpen)
{
_PortaModbus.Open();
}
}
public static void LimparDadosPorta()
{
_PortaModbus.Close();
_PortaModbus = null;
}
private static void DescartarDadosBuffer()
{
_PortaModbus.DiscardInBuffer();
_PortaModbus.DiscardOutBuffer();
}
private static async Task<bool> ReceberDados()
{
while (true)
{
await Task.Delay(TaxaAmostragem);
if (!Iniciado)
{
continue;
}
if (PZEMService.Iniciado && !PZEMService.ModoLeitura)
{
AdicionarComandoNaFila(new ModbusComandoModel()
{
Dispositivo = T_Code.Pzm,
Endereco = PZEMService.slaveAddress,
Comando = PZEMService.ComandoAquisicaoDados(),
Verificacao = false,
TamanhoEsperado = 16,
TimeoutResposta = 1000,
});
}
if (WT901CService.Iniciado)
{
AdicionarComandoNaFila(new ModbusComandoModel()
{
Dispositivo = T_Code.Wit,
Endereco = WT901CService.slaveAddress,
Comando = WT901CService.ComandoAquisicaoDados(),
Verificacao = false,
TamanhoEsperado = 101,
TimeoutResposta = 1000,
});
}
if (UltrasonicA05Service.Iniciado)
{
AdicionarComandoNaFila(new ModbusComandoModel()
{
Dispositivo = T_Code.A05,
Endereco = UltrasonicA05Service.slaveAddress,
Comando = UltrasonicA05Service.ComandoAquisicaoDados(),
Verificacao = false,
TamanhoEsperado = 11,
TimeoutResposta = 1000,
});
}
}
}
private static void TmrLoopComandos_Tick(object sender, EventArgs e)
{
if (EnvioLiberado && !Verificando && !frmInstancial.Fechando)
{
Task.Run(() => LoopEnvioComandos());
}
}
private static async Task LoopEnvioComandos()
{
EnvioLiberado = false;
if (Iniciado)
try
{
_PortaModbus.Write(Comando, 0, Comando.Length);
List<ModbusComandoModel> comandosParaEnviar;
await Task.Delay(200);
lock (FilaLock)
{
comandosParaEnviar = FilaComandos.Where(x => !x.Enviado).OrderByDescending(x => x.Verificacao).ThenBy(x => x.Momento).ToList();
}
foreach (var Comando in comandosParaEnviar)
{
await EnviarComando(Comando);
}
}
catch (Exception ex)
{
RegisrarErrosComunicacao(T_Code.Mbs, 0, $"Erro ao processar fila de comandos. Erro={ex.Message}");
}
finally
{
EnvioLiberado = true;
}
}
private static void RegisrarErrosComunicacao(T_Code dispositivo, byte addr, string mensagem)
{
var Caminho = Variaveis.CaminhoLogsDispositivos;
if (!Directory.Exists(Caminho))
{
Directory.CreateDirectory(Caminho);
}
EnvioLiberado = true;
var Arquivo = dispositivo.ToString() + "_err.txt";
Caminho += "/" + Arquivo;
mensagem = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff") + " - Porta " + (_PortaModbus?.PortName ?? "COM") + " - " + addr + ": " + mensagem + Environment.NewLine;
if (!File.Exists(Caminho))
{
File.WriteAllText(Caminho, mensagem);
}
else
{
File.AppendAllText(Caminho, mensagem);
}
}
public static void AdicionarComandoNaFila(ModbusComandoModel Comando)
{
lock (FilaLock)
{
if (!FilaComandos.Any(x => x.Dispositivo == Comando.Dispositivo && x.Comando.SequenceEqual(Comando.Comando) && !x.Enviado))
{
FilaComandos.Add(Comando);
}
}
}
public static async Task EnviarComando(ModbusComandoModel Comando)
{
if (_PortaModbus != null && _PortaModbus.IsOpen)
{
try
{
//await Task.Delay(100);
DescartarDadosBuffer();
_PortaModbus.Write(Comando.Comando, 0, Comando.Comando.Length);
Comando.Enviado = true;
Comando.Resposta = await SerialService.LerDadosDaPortaSerialAsync(_PortaModbus, Comando.TamanhoEsperado, Comando.TimeoutResposta);
Comando.RespondidoEm = DateTime.Now;
ProcessarResposta(Comando);
}
catch (Exception ex)
{
RegisrarErrosComunicacao(Comando.Dispositivo, Comando.Endereco, $"Erro ao processar fila de comandos. Erro={ex.Message}");
}
finally
{
DescartarDadosBuffer();
}
}
}
private static void ProcessarResposta(ModbusComandoModel Comando)
{
bool sucesso = false;
switch (Comando.Dispositivo)
{
case T_Code.Pzm:
{
sucesso = PZEMService.ProcessarResposta(Comando.Resposta);
frmInstancial.frmAcompanhamento.AtualizarSensores("Ultima Leitura PZM: " + PZEMService.UltimaLeitura.DataHora.ToString("HH:mm:ss"));
break;
}
case T_Code.Wit:
{
sucesso = WT901CService.ProcessarResposta(Comando.Resposta);
frmInstancial.frmAcompanhamento.AtualizarSensores("Ultima Leitura WIT: " + WT901CService.DadosLeitura.Momento.ToString("HH:mm:ss"));
break;
}
case T_Code.A05:
{
sucesso = UltrasonicA05Service.DecifrarRespostaAquisicao(Comando.Resposta);
frmInstancial.frmAcompanhamento.AtualizarSensores("Ultima Leitura A05: " + UltrasonicA05Service.DadosLeitura.Momento.ToString("HH:mm:ss"));
break;
}
}
}
@ -261,18 +461,4 @@ namespace AgroBase.Services
}
public class ModbusParametrosModel
{
public DateTime UltimaRequisicao { get; set; } = DateTime.MaxValue;
public string Descricao { get; set; }
public string Chave { get; set; }
public byte FuncaoGet { get; set; }
public byte FuncaoSet { get; set; }
public byte Registro { get; set; }
public byte N_Registros { get; set; }
public bool LeituraLoop { get; set; }
public bool LeituraGeral { get; set; }
public double Escala { get; set; }
public byte[] Valor { get; set; }
}
}

View File

@ -20,7 +20,7 @@ namespace AgroBase.Services
{
public static bool Iniciado { get; set; }
public static int TaxaAmostragem { get; set; } = 500;
private static byte slaveAddress = 0x01;
public static byte slaveAddress = 0x01;
public static PZEMModel UltimaLeitura = new PZEMModel();
public static PZEMModel PenultimaLeitura = new PZEMModel();
@ -51,60 +51,40 @@ namespace AgroBase.Services
public static async Task<bool> VerificaPortaPZEM(SerialPort porta)
{
ModbusService.Verificando = true;
ModbusService.DefinirPortaCOM(porta);
porta.BaudRate = 9600;
var comando = ComandoGetParametro(Parametros["AlarmeTensaoMaxima"]);
EnviarComando(porta, comando);
var resposta = SerialService.LerDadosDaPortaSerial(porta, 7, 1000);
//var resposta = SerialService.VerificarRespostaPortasDesconhecidas(porta);
ModbusService.Verificando = false;
Iniciado = DecifrarRespostaAquisicao(resposta) != null;
if (resposta.Length > 3 && resposta[1] == CodigosFuncoes["LeituraParametro"] && Iniciado)
var Comando = new ModbusComandoModel()
{
AtualizarPortaCOM(porta);
Dispositivo = T_Code.Pzm,
Endereco = slaveAddress,
Comando = ComandoAquisicaoDados(),
Verificacao = true,
TamanhoEsperado = 16
};
ModbusService.AdicionarComandoNaFila(Comando);
while (Comando.RespondidoEm == DateTime.MinValue)
{
await Task.Delay(200);
}
Iniciado = DecifrarRespostaAquisicao(Comando.Resposta);
if (Iniciado)
{
DefinirDispositivo();
return Iniciado;
}
if (!ModbusService.Iniciado)
{
porta.Close();
ModbusService.LimparDadosPorta();
}
return false;
}
public static void AtualizarPortaCOM(SerialPort Porta)
{
if (ModbusService._PortaModbus == null || !ModbusService.Iniciado)
{
lock (ModbusService._lock)
{
ModbusService._PortaModbus = new SerialPort();
ModbusService._PortaModbus.BaudRate = Porta.BaudRate;
ModbusService._PortaModbus.PortName = Porta.PortName;
}
}
if (ModbusService._PortaModbus != null && !ModbusService._PortaModbus.IsOpen)
{
Porta.Close();
}
if (Iniciado)
{
bool i = ModbusService.Iniciado;
DefinirDispositivo();
ContadorCarga = new CoulombCounterService(VariaveisEquipamento.BateriaMax);
ReceberDados().ConfigureAwait(false);
}
}
private static void DefinirDispositivo()
{
if (Iniciado)
@ -119,216 +99,13 @@ namespace AgroBase.Services
}
}
public static void EnviarComando(SerialPort _Porta, byte[] Comando)
{
if (_Porta != null)
{
if (!_Porta.IsOpen)
{
_Porta.Open();
}
if (_Porta.IsOpen)
{
_Porta.Write(Comando, 0, Comando.Length);
}
}
}
private static async Task<bool> ReceberDados()
{
if (!ModbusService.Iniciado)
{
Iniciado = false;
return false;
}
PenultimaLeitura = new PZEMModel()
{
AlarmeTensaoMax = UltimaLeitura.AlarmeTensaoMax,
AlarmeTensaoMin = UltimaLeitura.AlarmeTensaoMin,
Corrente = UltimaLeitura.Corrente,
DataHora = UltimaLeitura.DataHora,
Energia = UltimaLeitura.Energia,
Potencia = UltimaLeitura.Potencia,
Tensao = UltimaLeitura.Tensao
};
await ModbusService.EnviarComando(ComandoAquisicaoDados());
byte[] resposta = SerialService.VerificarRespostaPortasDesconhecidas(ModbusService._PortaModbus);
DecifrarRespostaAquisicao(resposta);
ContadorCarga.AtualizarConsumo();
double percent = FuncoesMatematicas.Map(UltimaLeitura.Tensao, TensaoMinima, TensaoMaxima, 0, 100);
Variaveis.OperacaoEmAndamento.Sensoriamento.PorcentagemBateria = percent;
frmInstancial.frmAcompanhamento.AtualizarSensores("Bateria: " + UltimaLeitura.Tensao.ToString("0.00") + " V - " + UltimaLeitura.Corrente.ToString("0.00") + " A - " + UltimaLeitura.Potencia.ToString("0.00") + " W");
Variaveis.OperacaoEmAndamento.Sensoriamento.BateriaConsumida = ContadorCarga.PercentualConsumido;
await Task.Delay(TaxaAmostragem);
if (ModbusService.Iniciado)
{
return await ReceberDados();
}
else
{
return false;
}
}
#region Comandos
public static byte[] ComandoAquisicaoDados()
{
byte functionCode = CodigosFuncoes["AquisicaoDados"];
ushort startAddress = 0x0000;
ushort numOfRegisters = 0x0008;
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
command.AddRange(BitConverter.GetBytes(startAddress).Reverse()); // Big endian
command.AddRange(BitConverter.GetBytes(numOfRegisters).Reverse()); // Big endian
byte[] crc = Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoSetParametro(byte Parametro, float valor)
{
// Convertendo o valor para o formato correto (LSB = 0.01)
int valorInt = (int)(valor * 100); // Convertendo para inteiro conforme a resolução
byte functionCode = CodigosFuncoes["GravacaoParametro"];
ushort registerAddress = Parametro;
// Construindo o comando
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
command.AddRange(BitConverter.GetBytes(registerAddress).Reverse()); // Little endian
command.AddRange(BitConverter.GetBytes((ushort)valorInt).Reverse()); // Little endian
byte[] crc = Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoGetParametro(byte Parametro)
{
byte functionCode = CodigosFuncoes["LeituraParametro"];
ushort registerAddress = Parametro;
ushort numberOfRegisters = 0x0001; // Lendo apenas um registro
// Construindo o comando
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
command.AddRange(BitConverter.GetBytes(registerAddress).Reverse()); // Big endian
command.AddRange(BitConverter.GetBytes(numberOfRegisters).Reverse()); // Big endian
byte[] crc = Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoResetEnergia()
{
// Código de função específico para reset de energia
byte functionCode = CodigosFuncoes["ResetEnergia"];
// Construindo o comando
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
// Adicionando o CRC ao comando
byte[] crc = Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoCalibragem()
{
byte functionCode = CodigosFuncoes["Calibrar"];
// Bytes fixos para o comando de calibragem
byte[] bytesComando = new byte[] { 0xF8, functionCode, 0x37, 0x21 };
// Calculando o CRC para os bytes do comando
byte[] crc = Crc16(bytesComando);
// Adicionando o CRC ao comando
List<byte> comandoCalibragem = new List<byte>(bytesComando);
comandoCalibragem.AddRange(crc);
return comandoCalibragem.ToArray();
}
#endregion
public static byte[] Crc16(byte[] data)
{
ushort crc = 0xFFFF;
foreach (byte pos in data)
{
crc ^= pos;
for (int i = 0; i < 8; i++)
{
if ((crc & 1) != 0)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return new byte[] { (byte)crc, (byte)(crc >> 8) };
}
public static bool VerificarCrc(string respostaHex)
{
byte[] respostaBytes = HexStringToByteArray(respostaHex);
byte[] crcRecebido = new byte[] { respostaBytes[respostaBytes.Length - 2], respostaBytes[respostaBytes.Length - 1] };
byte[] dados = new byte[respostaBytes.Length - 2];
Array.Copy(respostaBytes, 0, dados, 0, dados.Length);
byte[] crcCalculado = Crc16(dados);
return crcRecebido[0] == crcCalculado[0] && crcRecebido[1] == crcCalculado[1];
}
public static byte[] HexStringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
public static PZEMModel DecifrarRespostaAquisicao(byte[] resposta)
public static bool DecifrarRespostaAquisicao(byte[] resposta)
{
try
{
/*if (!VerificarCrc(resposta))
{
Console.Write("CRC inválido. A resposta pode estar corrompida.");
return null;
}*/
if (!resposta.Any())
{
return null;
return false;
}
if (resposta[1] == CodigosFuncoes["AquisicaoDados"])
@ -355,7 +132,7 @@ namespace AgroBase.Services
UltimaLeitura = modelo;
return modelo;
return true;
}
else
{
@ -392,16 +169,138 @@ namespace AgroBase.Services
Console.WriteLine("Resposta inválida ou código de função incorreto.");
}
return new PZEMModel();
return false;
}
catch (Exception ex)
{
}
return null;
return true;
}
public static bool ProcessarResposta(byte[] Resposta)
{
PenultimaLeitura = new PZEMModel()
{
AlarmeTensaoMax = UltimaLeitura.AlarmeTensaoMax,
AlarmeTensaoMin = UltimaLeitura.AlarmeTensaoMin,
Corrente = UltimaLeitura.Corrente,
DataHora = UltimaLeitura.DataHora,
Energia = UltimaLeitura.Energia,
Potencia = UltimaLeitura.Potencia,
Tensao = UltimaLeitura.Tensao
};
bool Sucesso = DecifrarRespostaAquisicao(Resposta);
ContadorCarga.AtualizarConsumo();
double percent = FuncoesMatematicas.Map(UltimaLeitura.Tensao, TensaoMinima, TensaoMaxima, 0, 100);
Variaveis.OperacaoEmAndamento.Sensoriamento.PorcentagemBateria = percent;
frmInstancial.frmAcompanhamento.AtualizarSensores("Bateria: " + UltimaLeitura.Tensao.ToString("0.00") + " V - " + UltimaLeitura.Corrente.ToString("0.00") + " A - " + UltimaLeitura.Potencia.ToString("0.00") + " W");
Variaveis.OperacaoEmAndamento.Sensoriamento.BateriaConsumida = ContadorCarga.PercentualConsumido;
return Sucesso;
}
#region Comandos
public static byte[] ComandoAquisicaoDados()
{
byte functionCode = CodigosFuncoes["AquisicaoDados"];
ushort startAddress = 0x0000;
ushort numOfRegisters = 0x0008;
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
command.AddRange(BitConverter.GetBytes(startAddress).Reverse()); // Big endian
command.AddRange(BitConverter.GetBytes(numOfRegisters).Reverse()); // Big endian
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoSetParametro(byte Parametro, float valor)
{
// Convertendo o valor para o formato correto (LSB = 0.01)
int valorInt = (int)(valor * 100); // Convertendo para inteiro conforme a resolução
byte functionCode = CodigosFuncoes["GravacaoParametro"];
ushort registerAddress = Parametro;
// Construindo o comando
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
command.AddRange(BitConverter.GetBytes(registerAddress).Reverse()); // Little endian
command.AddRange(BitConverter.GetBytes((ushort)valorInt).Reverse()); // Little endian
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoGetParametro(byte Parametro)
{
byte functionCode = CodigosFuncoes["LeituraParametro"];
ushort registerAddress = Parametro;
ushort numberOfRegisters = 0x0001; // Lendo apenas um registro
// Construindo o comando
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
command.AddRange(BitConverter.GetBytes(registerAddress).Reverse()); // Big endian
command.AddRange(BitConverter.GetBytes(numberOfRegisters).Reverse()); // Big endian
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoResetEnergia()
{
// Código de função específico para reset de energia
byte functionCode = CodigosFuncoes["ResetEnergia"];
// Construindo o comando
List<byte> command = new List<byte>();
command.Add(slaveAddress);
command.Add(functionCode);
// Adicionando o CRC ao comando
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static byte[] ComandoCalibragem()
{
byte functionCode = CodigosFuncoes["Calibrar"];
// Bytes fixos para o comando de calibragem
byte[] bytesComando = new byte[] { 0xF8, functionCode, 0x37, 0x21 };
// Calculando o CRC para os bytes do comando
byte[] crc = ModbusService.Crc16(bytesComando);
// Adicionando o CRC ao comando
List<byte> comandoCalibragem = new List<byte>(bytesComando);
comandoCalibragem.AddRange(crc);
return comandoCalibragem.ToArray();
}
#endregion

View File

@ -25,7 +25,7 @@ namespace AgroBase.Services
public static string SplitParams = ",";
public static List<T_Code> DispositivosMotores = new List<T_Code>() { T_Code.Mov, T_Code.Dir };
public static List<T_Code> DispositivosConexaoInicial = new List<T_Code>() { T_Code.Mvd, T_Code.Atu, T_Code.Sen };
public static List<T_Code> DispositivosModbus = new List<T_Code>() { T_Code.Pzm, T_Code.Wit };
public static List<T_Code> DispositivosModbus = new List<T_Code>() { T_Code.Pzm, T_Code.Wit, T_Code.A05 };
public static List<T_Code> DispositivosMultiplos = new List<T_Code>() { T_Code.Bld, T_Code.Mks, T_Code.Mvd };
public class DispositivoDetalhesModel
@ -49,6 +49,10 @@ namespace AgroBase.Services
{
DispositivoConectado = PZEMService.Iniciado;
}
else if (Dispositivo == T_Code.A05)
{
DispositivoConectado = UltrasonicA05Service.Iniciado;
}
else if (Dispositivo == T_Code.Lra)
{
DispositivoConectado = LoRaService.Iniciado;
@ -497,6 +501,16 @@ namespace AgroBase.Services
return Encontrado;
}
}
if (!UltrasonicA05Service.Iniciado || !DispositivosMapeados.Any(x => x.Dispositivo == T_Code.A05))
{
AtualizarConsole("Procurando dispositivo A05");
Encontrado = await UltrasonicA05Service.VerificaPortaA05(ModbusService.Iniciado ? ModbusService._PortaModbus : porta);
if (Encontrado && PararAoEncontrar)
{
AtualizarConsole("Dispositivo A05 encontrado");
return Encontrado;
}
}
/*if (Variaveis.OperacaoEmAndamento.DispMvd != null && Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Any(x => !x.MovMotor.DadosDriver.Iniciado))
{
foreach (var Modulo in Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Where(x => !x.MovMotor.DadosDriver.Iniciado))

View File

@ -0,0 +1,149 @@
using AgroBase.Forms;
using AgroBase.Models;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
using System.Windows.Forms;
namespace AgroBase.Services
{
public class UltrasonicA05Service
{
public static bool Iniciado { get; set; }
public static int TaxaAmostragem { get; set; } = 500;
public static byte slaveAddress = 0x01;
public static UltrasonicA05Model DadosLeitura = new UltrasonicA05Model();
public static async Task<bool> VerificaPortaA05(SerialPort porta)
{
ModbusService.DefinirPortaCOM(porta);
var Comando = new ModbusComandoModel()
{
Dispositivo = T_Code.A05,
Endereco = slaveAddress,
Comando = ComandoAquisicaoDados(),
Verificacao = true,
TamanhoEsperado = 11,
TimeoutResposta = 1000,
};
ModbusService.AdicionarComandoNaFila(Comando);
while (Comando.RespondidoEm == DateTime.MinValue)
{
await Task.Delay(200);
}
Iniciado = DecifrarRespostaAquisicao(Comando.Resposta);
if (Iniciado)
{
DefinirDispositivo();
return Iniciado;
}
if (!ModbusService.Iniciado)
{
ModbusService.LimparDadosPorta();
}
return false;
}
private static void DefinirDispositivo()
{
if (Iniciado)
{
SerialService.DispositivosMapeados.Add(new SerialService.DispositivoDetalhesModel()
{
PortaCOM = ModbusService._PortaModbus.PortName,
Dispositivo = T_Code.A05,
Erro = !Iniciado,
Versao = "1"
});
}
}
public static byte[] ComandoAquisicaoDados()
{
byte functionCode = 0x03;
byte startAddress = 0x0001;
byte firstRegister = 0x0006;
byte numOfRegisters = 0x0004;
List<byte> command = new List<byte>() { slaveAddress, functionCode, startAddress, firstRegister, 0x00, numOfRegisters };
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
command.AddRange(crc);
return command.ToArray();
}
public static bool DecifrarRespostaAquisicao(byte[] resposta)
{
try
{
if (resposta == null || !resposta.Any())
{
return false;
}
if (resposta.Length >= 18)
{
resposta = resposta.Skip(5).ToArray();
}
if (resposta[1] == 0x03)
{
int numBytes = resposta[2];
if (numBytes == 8) // Se o número de bytes de dados for 8
{
// Decifrar os valores dos sensores
int u1 = (resposta[3] << 8) + resposta[4];
int u2 = (resposta[5] << 8) + resposta[6];
int u3 = (resposta[7] << 8) + resposta[8];
int u4 = (resposta[9] << 8) + resposta[10];
UltrasonicA05Model modelo = new UltrasonicA05Model()
{
Momento = DateTime.Now,
Endereco = resposta[0],
U1 = u1,
U2 = u2,
U3 = u3,
U4 = u4
};
DadosLeitura = modelo;
return true;
}
else
{
Console.WriteLine("Número de bytes de dados não esperado.");
}
}
else
{
Console.WriteLine("Resposta inválida ou código de função incorreto.");
}
return false;
}
catch (Exception ex)
{
Console.WriteLine("Erro ao decifrar a resposta: " + ex.Message);
}
return false;
}
}
}

View File

@ -20,108 +20,45 @@ namespace AgroBase.Services
public static byte slaveAddress = 0x50;
private static Dictionary<string, object> DadosSensor { get; } = new Dictionary<string, object>();
public static WT901CModel DadosLeitura { get; set; } = new WT901CModel();
private static byte[] ComandoAquisicao = new byte[8] { slaveAddress, 0x03, 0x00, 0x30, 0x00, 0x30, 0x48, 0x50 };
public static byte[] ComandoAquisicao = new byte[8] { slaveAddress, 0x03, 0x00, 0x30, 0x00, 0x30, 0x48, 0x50 };
public static async Task<bool> VerificaPortaWT901C(SerialPort porta)
{
ModbusService.Verificando = true;
ModbusService.DefinirPortaCOM(porta);
porta.BaudRate = 9600;
var comando = ModbusService.ComandoGetParametro(slaveAddress, new ModbusParametrosModel() { FuncaoGet = 0x03, N_Registros = 2, Registro = 0x2e });
EnviarComando(porta, comando);
var resposta = SerialService.LerDadosDaPortaSerial(porta, 7, 1000);
//var resposta = SerialService.VerificarRespostaPortasDesconhecidas(porta);
ModbusService.Verificando = false;
Iniciado = DecifrarRespostaAquisicao(comando, resposta);
if (resposta.Length > 3 && resposta[1] == 0x03 && Iniciado)
var Comando = new ModbusComandoModel()
{
var magType = ModbusService.ComandoGetParametro(slaveAddress, new ModbusParametrosModel() { FuncaoGet = 0x03, N_Registros = 2, Registro = 0x72 });
Dispositivo = T_Code.Wit,
Endereco = slaveAddress,
Comando = ComandoAquisicaoDados(),
Verificacao = true,
TamanhoEsperado = 101,
TimeoutResposta = 1000
};
EnviarComando(porta, magType);
ModbusService.AdicionarComandoNaFila(Comando);
while (Comando.RespondidoEm == DateTime.MinValue)
{
await Task.Delay(200);
var res = SerialService.VerificarRespostaPortasDesconhecidas(porta);
DecifrarRespostaAquisicao(magType, res);
}
AtualizarPortaCOM(porta);
Iniciado = DecifrarRespostaAquisicao(Comando.Resposta);
if (Iniciado)
{
DefinirDispositivo();
return Iniciado;
}
if (!ModbusService.Iniciado)
{
porta.Close();
ModbusService.LimparDadosPorta();
}
return false;
}
public static void AtualizarPortaCOM(SerialPort Porta)
{
if (ModbusService._PortaModbus == null || !ModbusService.Iniciado)
{
lock (ModbusService._lock)
{
ModbusService._PortaModbus = new SerialPort();
ModbusService._PortaModbus.BaudRate = Porta.BaudRate;
ModbusService._PortaModbus.PortName = Porta.PortName;
}
}
if (ModbusService._PortaModbus != null && !ModbusService._PortaModbus.IsOpen)
{
Porta.Close();
}
if (Iniciado)
{
bool i = ModbusService.Iniciado;
DefinirDispositivo();
ReceberDados().ConfigureAwait(false);
}
}
private static async Task<bool> ReceberDados()
{
if (!ModbusService.Iniciado)
{
Iniciado = false;
return false;
}
await ModbusService.EnviarComando(ComandoAquisicao);
byte[] resposta = SerialService.LerDadosDaPortaSerial(ModbusService._PortaModbus, 101);
//await Task.Delay(100);
//Iniciado = DecifrarRespostaAquisicao(ComandoAquisicao, resposta);
DecifrarRespostaAquisicao(ComandoAquisicao, resposta);
if (Iniciado)
{
PreencherDadosLeitura();
Variaveis.OperacaoEmAndamento.Sensoriamento.InclinacaoX = DadosLeitura.AngleX;
Variaveis.OperacaoEmAndamento.Sensoriamento.InclinacaoY = DadosLeitura.AngleY;
Variaveis.OperacaoEmAndamento.Sensoriamento.InclinacaoZ = DadosLeitura.AngleZ;
Variaveis.OperacaoEmAndamento.Sensoriamento.AnguloCarroBussola = DadosLeitura.AngleZ * -1;
}
await Task.Delay(TaxaAmostragem);
if (ModbusService.Iniciado)
{
return await ReceberDados();
}
else
{
return false;
}
}
private static void DefinirDispositivo()
{
if (Iniciado)
@ -136,24 +73,32 @@ namespace AgroBase.Services
}
}
public static void EnviarComando(SerialPort _Porta, byte[] Comando)
public static bool ProcessarResposta(byte[] Resposta)
{
if (_Porta != null)
bool Sucesso = DecifrarRespostaAquisicao(Resposta);
if (Iniciado)
{
if (!_Porta.IsOpen)
{
_Porta.Open();
}
if (_Porta.IsOpen)
{
_Porta.Write(Comando, 0, Comando.Length);
}
PreencherDadosLeitura();
Variaveis.OperacaoEmAndamento.Sensoriamento.InclinacaoX = DadosLeitura.AngleX;
Variaveis.OperacaoEmAndamento.Sensoriamento.InclinacaoY = DadosLeitura.AngleY;
Variaveis.OperacaoEmAndamento.Sensoriamento.InclinacaoZ = DadosLeitura.AngleZ;
Variaveis.OperacaoEmAndamento.Sensoriamento.AnguloCarroBussola = DadosLeitura.AngleZ * -1;
}
return Sucesso;
}
private static bool DecifrarRespostaAquisicao(byte[] comando, byte[] resposta)
public static byte[] ComandoAquisicaoDados()
{
return ComandoAquisicao;
}
private static bool DecifrarRespostaAquisicao(byte[] resposta)
{
byte[] modbusBytes;
byte[] comando = ComandoAquisicaoDados();
if (comando != null && resposta != null && resposta.Length >= 7 && ModbusService.FindModbus(comando, resposta, out modbusBytes))
{
int readReg = comando[2] << 8 | comando[3];
@ -167,6 +112,8 @@ namespace AgroBase.Services
DadosSensor[key] = value;
}
DadosLeitura.Momento = DateTime.Now;
return true;
}
else
@ -176,6 +123,8 @@ namespace AgroBase.Services
}
}
private static dynamic GetDeviceData(string key)
{
if (DadosSensor.ContainsKey(key))

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
22/08/2024 14:49:56:227 - Porta COM29 - 0: Erro ao processar fila de comandos. Erro=Value cannot be null.
22/08/2024 15:59:48:813 - Porta COM3 - 0: Erro ao processar fila de comandos. Erro=The port is closed.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
2c241a8042a47f4b7f12cdb88ec84cae700bfb617404a8de188de541b0438c6f
ff68edbc961306d3db9a64f9fb7f5d615c8594a326799b9c62341ff2f37258f0

View File

@ -0,0 +1,80 @@
import serial
import struct
import time
def calculate_crc(data):
crc = 0xFFFF
for pos in data:
crc ^= pos
for _ in range(8):
if (crc & 1) != 0:
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
return crc
def send_command(ser, command):
# Calcular o checksum
crc = calculate_crc(command)
command.append(crc & 0xFF) # CRC Low byte
command.append((crc >> 8) & 0xFF) # CRC High byte
# Enviar o comando via serial
ser.write(command)
# Ler a resposta
response = ser.read(13) # Ler a resposta completa, 13 bytes no caso de todos os sensores
return response
def parse_response(response):
if len(response) < 11:
print(f"Resposta incompleta ou inválida. Tamanho recebido: {len(response)}")
return None
sensor_values = []
try:
for i in range(3, 11, 2):
value = (response[i] << 8) + response[i + 1]
sensor_values.append(value)
except IndexError:
print("Erro ao processar a resposta. Dados insuficientes.")
sensor_values.append(-1)
return sensor_values
def main():
# Configurar a porta serial para COM29
ser = serial.Serial('COM29', 9600, timeout=1)
# Comando para requisitar dados de todos os sensores (1, 2, 3, e 4)
command_all_sensors = [0x01, 0x03, 0x01, 0x06, 0x00, 0x04]
try:
while True:
# Enviar o comando e receber a resposta
response_all = send_command(ser, command_all_sensors)
print(response_all.hex())
# Converter a resposta para milímetros
sensor_values_all = parse_response(response_all)
# Exibir a saída formatada
if sensor_values_all and len(sensor_values_all) == 4:
print(f"S1: {sensor_values_all[0]} mm S2: {sensor_values_all[1]} mm S3: {sensor_values_all[2]} mm S4: {sensor_values_all[3]} mm")
else:
print("Dados incompletos ou inválidos recebidos dos sensores.")
# Esperar 1 segundo antes da próxima requisição
time.sleep(1)
except KeyboardInterrupt:
print("Parando a execução...")
finally:
# Fechar a conexão serial
ser.close()
if __name__ == "__main__":
main()