From 9cffd005a299186ea7aa0af5121c098c1e30f859 Mon Sep 17 00:00:00 2001 From: parallelbgls Date: Wed, 19 Jun 2024 13:55:18 +0800 Subject: [PATCH] Add Modbus RTU receiver module --- .../Modbus.Net.Modbus/ModbusReceiver.cs | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 Modbus.Net/Modbus.Net.Modbus/ModbusReceiver.cs diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusReceiver.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusReceiver.cs new file mode 100644 index 0000000..a962203 --- /dev/null +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusReceiver.cs @@ -0,0 +1,194 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using AddressUnit = Modbus.Net.AddressUnit; +using DataReturnDef = Modbus.Net.DataReturnDef; + +namespace Modbus.Net.Modbus +{ + public class ModbusRtuDataReceiver + { + private ModbusRtuProtocolReceiver _receiver; + + private readonly IConfigurationRoot configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json") + .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", true) + .Build(); + + private bool[] zerox = new bool[10000]; + private byte[] threex = new byte[20000]; + + public delegate Dictionary ReturnValuesDelegate(DataReturnDef returnValues); + + public event ReturnValuesDelegate ReturnValueDictionary; + + protected void AddValueToValueDic(Dictionary valueDic, Dictionary> returnDic, AddressUnit address, double value, MachineDataType dataType) + { + switch (dataType) + { + case MachineDataType.Id: + { + valueDic.Add(address.Id, value); + returnDic.Add(address.Id, new ReturnUnit() { AddressUnit = address.MapAddressUnitTUnitKeyToAddressUnit(), DeviceValue = value }); + break; + } + case MachineDataType.Name: + { + valueDic.Add(address.Name, value); + returnDic.Add(address.Name, new ReturnUnit() { AddressUnit = address.MapAddressUnitTUnitKeyToAddressUnit(), DeviceValue = value }); + break; + } + case MachineDataType.Address: + { + valueDic.Add(new AddressFormaterModbus().FormatAddress(address.Area, address.Address, address.SubAddress), value); + returnDic.Add(new AddressFormaterModbus().FormatAddress(address.Area, address.Address, address.SubAddress), new ReturnUnit() { AddressUnit = address.MapAddressUnitTUnitKeyToAddressUnit(), DeviceValue = value }); + break; + } + case MachineDataType.CommunicationTag: + { + valueDic.Add(address.CommunicationTag, value); + returnDic.Add(address.CommunicationTag, new ReturnUnit() { AddressUnit = address.MapAddressUnitTUnitKeyToAddressUnit(), DeviceValue = value }); + break; + } + } + } + + public ModbusRtuDataReceiver(MachineDataType dataType) + { + _receiver = new ModbusRtuProtocolReceiver(ConfigurationReader.GetValue("Receiver", "d:connectionString"), int.Parse(ConfigurationReader.GetValue("Receiver", "g:slaveAddress"))); + var machineName = ConfigurationReader.GetValue("Receiver", "a:id"); + var addressMapName = ConfigurationReader.GetValue("Receiver", "e:addressMap"); + var endian = ValueHelper.GetInstance(Endian.Parse(ConfigurationReader.GetValue("Receiver", "i:endian"))); + _receiver.DataProcess = receiveContent => + { + var returnTime = DateTime.Now; + byte[] returnBytes = null; + var readContent = new byte[receiveContent.Count * 2]; + var values = receiveContent.WriteContent; + var valueDic = new Dictionary(); + var returnDic = new Dictionary>(); + List addressMap = AddressReader.ReadAddresses(addressMapName).ToList(); + if (values != null) + { + try + { + for (int i = 0; i < addressMap.Count; i++) + { + var pos = (addressMap[i].Address - 1) * 2; + var subpos = addressMap[i].SubAddress; + string valueString = null; + if (addressMap[i].Area == "4X") + { + valueString = endian.GetValue(threex, ref pos, ref subpos, addressMap[i].DataType).ToString(); + } + else if (addressMap[i].Area == "0X") + { + valueString = zerox[addressMap[i].Address - 1].ToString(); + } + if (valueString == "True") valueString = "1"; + if (valueString == "False") valueString = "0"; + var value = double.Parse(valueString); + value = value * addressMap[i].Zoom; + value = Math.Round(value, addressMap[i].DecimalPos); + AddValueToValueDic(valueDic, returnDic, addressMap[i], value, dataType); + if (ReturnValueDictionary != null) + { + var dataReturn = new DataReturnDef(); + dataReturn.MachineId = machineName; + dataReturn.ReturnValues = new ReturnStruct>>() { IsSuccess = true, Datas = returnDic }; + ReturnValueDictionary(dataReturn); + } + } + } + catch (Exception ex) + { + //_logger.LogError(ex, "Error"); + } + switch (receiveContent.FunctionCode) + { + case (byte)ModbusProtocolFunctionCode.WriteMultiRegister: + { + Array.Copy(receiveContent.WriteContent, 0, threex, receiveContent.StartAddress * 2, receiveContent.WriteContent.Length); + returnBytes = new WriteDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, receiveContent.StartAddress, receiveContent.Count); + break; + } + case (byte)ModbusProtocolFunctionCode.WriteSingleCoil: + { + if (receiveContent.WriteContent[0] == 255) + { + zerox[receiveContent.StartAddress] = true; + } + else + { + zerox[receiveContent.StartAddress] = false; + } + returnBytes = new WriteDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, receiveContent.StartAddress, receiveContent.WriteContent); + break; + } + case (byte)ModbusProtocolFunctionCode.WriteMultiCoil: + { + var pos = 0; + List bitList = new List(); + for (int i = 0; i < receiveContent.WriteByteCount; i++) + { + var bitArray = BigEndianLsbValueHelper.Instance.GetBits(receiveContent.WriteContent, ref pos); + bitList.AddRange(bitArray.ToList()); + } + Array.Copy(bitList.ToArray(), 0, zerox, receiveContent.StartAddress, bitList.Count); + returnBytes = new WriteDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, receiveContent.StartAddress, receiveContent.Count); + break; + } + case (byte)ModbusProtocolFunctionCode.WriteSingleRegister: + { + Array.Copy(receiveContent.WriteContent, 0, threex, receiveContent.StartAddress * 2, receiveContent.Count * 2); + returnBytes = new WriteDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, receiveContent.StartAddress, receiveContent.Count); + break; + } + } + } + else + { + switch (receiveContent.FunctionCode) + { + case (byte)ModbusProtocolFunctionCode.ReadHoldRegister: + { + Array.Copy(threex, receiveContent.StartAddress, readContent, 0, readContent.Length); + returnBytes = new ReadDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, (byte)receiveContent.Count, readContent); + break; + } + case (byte)ModbusProtocolFunctionCode.ReadCoilStatus: + { + var bitCount = receiveContent.WriteByteCount * 8; + var boolContent = new bool[bitCount]; + Array.Copy(zerox, receiveContent.StartAddress, boolContent, 0, bitCount); + var byteList = new List(); + for (int i = 0; i < receiveContent.WriteByteCount; i++) + { + byte result = 0; + for (int j = i; j < i + 8; j++) + { + // 将布尔值转换为对应的位 + + byte bit = boolContent[j] ? (byte)1 : (byte)0; + + // 使用左移位运算将位合并到结果字节中 + + result = (byte)((result << 1) | bit); + } + byteList.Add(result); + } + readContent = byteList.ToArray(); + returnBytes = new ReadDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, receiveContent.WriteByteCount, readContent); + break; + } + } + } + if (returnBytes != null) return returnBytes; + else return null; + }; + } + } +}