agrobot_base/AgroBase/AgroBase/Services/ModbusService.cs

146 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Emgu.CV.ML.KNearest;
namespace AgroBase.Services
{
public class ModbusService
{
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 VerifyChecksum(byte[] bytes)
{
if (bytes.Length < 2) return false;
// Extrai o CRC recebido dos últimos dois bytes da mensagem
byte[] receivedCrc = new byte[] { bytes[bytes.Length - 2], bytes[bytes.Length - 1] };
// Extrai os dados da mensagem sem o CRC
byte[] data = new byte[bytes.Length - 2];
Array.Copy(bytes, data, bytes.Length - 2);
// Calcula o CRC dos dados
byte[] computedCrc = Crc16(data);
// Verifica se o CRC calculado é igual ao CRC recebido
return receivedCrc[0] == computedCrc[0] && receivedCrc[1] == computedCrc[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 int ByteArrayToDecimal(byte[] bytes)
{
if (bytes == null)
{
throw new ArgumentNullException(nameof(bytes));
}
switch (bytes.Length)
{
case 2:
// Converter 2 bytes para short e depois para decimal
int shortValue = BitConverter.ToInt32(bytes, 0);
return shortValue;
case 4:
// Converter 4 bytes para int e depois para decimal
int intValue = BitConverter.ToInt32(bytes, 0);
return intValue;
default:
throw new ArgumentException("O array de bytes deve ter 2 ou 4 elementos.");
}
}
public static byte[] ComandoSetParametro(byte slaveAddress, ModbusParametrosModel Parametro, float valor)
{
Parametro.UltimaRequisicao = DateTime.Now;
// Convertendo o valor para o formato correto (LSB = 0.01)
int valorInt = (int)(valor * Parametro.Escala); // Convertendo para inteiro conforme a resolução
byte functionCode = Parametro.FuncaoSet;
ushort registerAddress = Parametro.Registro;
// 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 slaveAddress, ModbusParametrosModel Parametro)
{
Parametro.UltimaRequisicao = DateTime.Now;
byte functionCode = Parametro.FuncaoGet;
ushort registerAddress = Parametro.Registro;
ushort numberOfRegisters = Parametro.N_Registros; // 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 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; }
}
}