using Modbus; using Modbus.Device; using Modbus.IO; using MV485.model; using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace MV485.helper { //读写配置参数 public class RWRunConfig { private SerialPort _serialPort; private ModbusSerialMaster _modbusMaster; private ModbusSerialTransport _modbusTransport; private byte[] sentData; //发送到设备的数据 private byte[] recvData; //从设备接收的数据 //private string _sendDataHex; //private string _recvDataHex; private string _portName; private int _baudrate; //读时使用的波特率额 private byte _address; //读时使用的地址 private string _message; //public event Action SearchFinished; public event Action RWLog; public event Action SerialConnected; //串口是否已连接 public event Action SerialStatusChanged; //串口连接状态变化 private string _lastErrorMessage; //最后一次的错误说明 public string GetLastError() { return _lastErrorMessage; } public RWRunConfig() { } //cfgType 1:AI参数;2:图像参数; 3:采样时间参数 public RunConfig ReadRunConfig(string portName, int baudrate, byte devId,int cfgType) { RunConfig runConfig = null; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { if (cfgType == 1) { runConfig = GetAIConfig(devId); } else if (cfgType == 2) { runConfig = GetRegionConfig(devId); } else if (cfgType == 3) { runConfig = GetSampleConfig(devId); } else { runConfig = GetRunConfig(devId); } } CloseSerial(); return runConfig; } private RunConfig GetAIConfig(byte devId) { string readName = ""; try { RunConfig runConfig = new RunConfig(); ushort[] readRegisters; readName = "水表类型"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_METER_TYPE, Constant.MB_REGISTER_NUM_METER_TYPE); byte meterType = (byte)(readRegisters[0] & 0xFF); runConfig.MeterTypeWRFlag = true; runConfig.MeterType = meterType; GenerateSendAndRecvHexLog(true, readName); _message = $"{readName}: {meterType}"; RWLog?.Invoke(_message); readName = "每小时最大流量"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DN_VALUE, Constant.MB_REGISTER_NUM_DN_VALUE); ushort dnValue = readRegisters[0]; runConfig.DnValueWRFlag = true; runConfig.DnValue = dnValue; GenerateSendAndRecvHexLog(true, readName); _message = $"{readName}: {dnValue}"; RWLog?.Invoke(_message); if (meterType == Constant.METER_TYPE_NUM_IND || meterType == Constant.METER_TYPE_NUM) { readName = "数字个数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DIGIT_COUNT, Constant.MB_REGISTER_NUM_DIGIT_COUNT); byte digitCount = (byte)(readRegisters[0] & 0xFF); runConfig.DigitCountWRFlag = true; runConfig.DigitCount = digitCount; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, digitCount); } if (meterType == Constant.METER_TYPE_NUM_IND || meterType == Constant.METER_TYPE_IND) { readName = "指针个数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_INDICATOR_COUNT, Constant.MB_REGISTER_NUM_INDICATOR_COUNT); byte indCount = (byte)(readRegisters[0] & 0xFF); runConfig.IndCountWRFlag = true; runConfig.IndCount = indCount; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, indCount); } //此项已经不需要了 /*readName = "照片亮度放大倍率"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_BRIGHT_VALUE, Constant.MB_REGISTER_NUM_BRIGHT_VALUE); byte birghtValue = (byte)(readRegisters[0] & 0xFF); // 10f; runConfig.BrightValueWRFlag = true; runConfig.BrightValue = birghtValue / 10f; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, birghtValue);*/ readName = "尾数单位等级"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_LAST_UNIT_LEVEL, Constant.MB_REGISTER_NUM_LAST_UNIT_LEVEL); byte lastUnitLevel = (byte)(readRegisters[0] & 0xFF); runConfig.LastUnitLevelWRFlag = true; runConfig.LastUnitLevel = lastUnitLevel; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, lastUnitLevel); readName = "上传红色指针读数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_UPLOAD_REDIND, Constant.MB_REGISTER_NUM_UPLOAD_REDIND); byte uploadRedind = (byte)(readRegisters[0] & 0xFF); runConfig.UploadRedindWRFlag = true; runConfig.UploadRedind = uploadRedind; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, uploadRedind); readName = "表底读数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_LATEST_VALUE, Constant.MB_REGISTER_NUM_LATEST_VALUE); //4个寄存器 ulong latestValue = ((ulong)readRegisters[0] << 48) | ((ulong)readRegisters[1] << 32) | ((ulong)readRegisters[2] << 16) | readRegisters[3]; runConfig.LatestValueWRFlag = true; runConfig.LatestValue = latestValue; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, latestValue); readName = "表底读数时间"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_LATEST_TIME, Constant.MB_REGISTER_NUM_LATEST_TIME); //6个寄存器 int year = (byte)(readRegisters[0] & 0xFF); int month = (byte)(readRegisters[1] & 0xFF); int day = (byte)(readRegisters[2] & 0xFF); int hour = (byte)(readRegisters[3] & 0xFF); int minute = (byte)(readRegisters[4] & 0xFF); int second = (byte)(readRegisters[5] & 0xFF); //DateTime dtLatestTime = new DateTime(2000 + year, month, day, hour, minute, second); //string latestTime = dtLatestTime.ToString("yyyy-MM-dd HH:mm:ss"); string latestTime = $"{2000 + year}-{month.ToString("D2")}-{day.ToString("D2")} " + $"{hour.ToString("D2")}:{minute.ToString("D2")}:{second.ToString("D2")}"; if (DateTime.TryParse(latestTime, out DateTime dtLatestTime)) { runConfig.LatestTimeWRFlag = true; runConfig.LatestTime = dtLatestTime; } GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, latestTime); return runConfig; } catch (TimeoutException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}超时,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } } private RunConfig GetRegionConfig(byte devId) { string readName = ""; try { RunConfig runConfig = new RunConfig(); ushort[] readRegisters; readName = "水表类型"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_METER_TYPE, Constant.MB_REGISTER_NUM_METER_TYPE); byte meterType = (byte)(readRegisters[0] & 0xFF); runConfig.MeterTypeWRFlag = true; runConfig.MeterType = meterType; GenerateSendAndRecvHexLog(true, readName); _message = $"{readName}: {meterType}"; RWLog?.Invoke(_message); readName = "表盘区域坐标"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_METER_REGION, Constant.MB_REGISTER_NUM_METER_REGION); //4个寄存器 string meterRegion = $"{readRegisters[0]},{readRegisters[1]} {readRegisters[2]},{readRegisters[3]}"; runConfig.MeterRegionWRFlag = true; runConfig.MeterRegion = meterRegion; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, meterRegion); if (meterType == Constant.METER_TYPE_NUM_IND || meterType == Constant.METER_TYPE_NUM) { readName = "数字区域坐标"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DIGIT_REGION, Constant.MB_REGISTER_NUM_DIGIT_REGION); //8个寄存器 string digitRegion = $"{readRegisters[0]},{readRegisters[1]} {readRegisters[2]},{readRegisters[3]} " + $"{readRegisters[4]},{readRegisters[5]} {readRegisters[6]},{readRegisters[7]}"; runConfig.DigitRegionWRFlag = true; runConfig.DigitRegion = digitRegion; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, digitRegion); } if (meterType == Constant.METER_TYPE_IND) { readName = "首尾指针坐标"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_FTIND_REGION, Constant.MB_REGISTER_NUM_FTIND_REGION); //4个寄存器 string ftIndRegion = $"{readRegisters[0]},{readRegisters[1]} {readRegisters[2]},{readRegisters[3]}"; runConfig.FTIndRegionWRFlag = true; runConfig.FTIndRegion = ftIndRegion; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, ftIndRegion); } return runConfig; } catch (TimeoutException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}超时,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } } private RunConfig GetSampleConfig(byte devId) { string readName = ""; try { RunConfig runConfig = new RunConfig(); ushort[] readRegisters; readName = "采样识别时间间隔(分)"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_SAMPLE_INTERVAL, Constant.MB_REGISTER_NUM_SAMPLE_INTERVAL); ushort sampleInterval = readRegisters[0]; runConfig.SampleIntervalFlag = true; runConfig.SampleInterval = sampleInterval; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, sampleInterval); readName = "首次采样整点小时"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_SAMPLE_FIRST_HOUR, Constant.MB_REGISTER_NUM_SAMPLE_FIRST_HOUR); byte firstHour = (byte)(readRegisters[0] & 0xFF); runConfig.FirstHourFlag = true; runConfig.FirstHour = firstHour; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, firstHour); return runConfig; } catch (TimeoutException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}超时,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } } private RunConfig GetRunConfig(byte devId) { string readName = ""; try { RunConfig runConfig = new RunConfig(); ushort[] readRegisters; readName = "水表类型"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_METER_TYPE, Constant.MB_REGISTER_NUM_METER_TYPE); byte meterType = (byte)(readRegisters[0] & 0xFF); runConfig.MeterTypeWRFlag = true; runConfig.MeterType = meterType; GenerateSendAndRecvHexLog(true,readName); _message = $"{readName}: {meterType}"; RWLog?.Invoke(_message); readName = "每小时最大流量"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DN_VALUE, Constant.MB_REGISTER_NUM_DN_VALUE); ushort dnValue = readRegisters[0]; runConfig.DnValueWRFlag = true; runConfig.DnValue = dnValue; GenerateSendAndRecvHexLog(true, readName); _message = $"{readName}: {dnValue}"; RWLog?.Invoke(_message); if (meterType == Constant.METER_TYPE_NUM_IND || meterType == Constant.METER_TYPE_NUM) { readName = "数字个数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DIGIT_COUNT, Constant.MB_REGISTER_NUM_DIGIT_COUNT); byte digitCount = (byte)(readRegisters[0] & 0xFF); runConfig.DigitCountWRFlag = true; runConfig.DigitCount = digitCount; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, digitCount); } if (meterType == Constant.METER_TYPE_NUM_IND || meterType == Constant.METER_TYPE_IND) { readName = "指针个数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_INDICATOR_COUNT, Constant.MB_REGISTER_NUM_INDICATOR_COUNT); byte indCount = (byte)(readRegisters[0] & 0xFF); runConfig.IndCountWRFlag = true; runConfig.IndCount = indCount; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, indCount); } //此项已经不需要了 /*readName = "照片亮度放大倍率"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_BRIGHT_VALUE, Constant.MB_REGISTER_NUM_BRIGHT_VALUE); byte birghtValue = (byte)(readRegisters[0] & 0xFF); // 10f; runConfig.BrightValueWRFlag = true; runConfig.BrightValue = birghtValue / 10f; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, birghtValue);*/ readName = "尾数单位等级"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_LAST_UNIT_LEVEL, Constant.MB_REGISTER_NUM_LAST_UNIT_LEVEL); byte lastUnitLevel = (byte)(readRegisters[0] & 0xFF); runConfig.LastUnitLevelWRFlag = true; runConfig.LastUnitLevel = lastUnitLevel; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, lastUnitLevel); readName = "上传红色指针读数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_UPLOAD_REDIND, Constant.MB_REGISTER_NUM_UPLOAD_REDIND); byte uploadRedind = (byte)(readRegisters[0] & 0xFF); runConfig.UploadRedindWRFlag = true; runConfig.UploadRedind = uploadRedind; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, uploadRedind); readName = "表底读数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_LATEST_VALUE, Constant.MB_REGISTER_NUM_LATEST_VALUE); //4个寄存器 ulong latestValue = ((ulong)readRegisters[0] << 48) | ((ulong)readRegisters[1] << 32) | ((ulong)readRegisters[2] << 16) | readRegisters[3]; runConfig.LatestValueWRFlag = true; runConfig.LatestValue = latestValue; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, latestValue); readName = "表底读数时间"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_LATEST_TIME, Constant.MB_REGISTER_NUM_LATEST_TIME); //6个寄存器 int year = (byte)(readRegisters[0] & 0xFF); int month = (byte)(readRegisters[1] & 0xFF); int day = (byte)(readRegisters[2] & 0xFF); int hour = (byte)(readRegisters[3] & 0xFF); int minute = (byte)(readRegisters[4] & 0xFF); int second = (byte)(readRegisters[5] & 0xFF); //DateTime dtLatestTime = new DateTime(2000 + year, month, day, hour, minute, second); //string latestTime = dtLatestTime.ToString("yyyy-MM-dd HH:mm:ss"); string latestTime = $"{2000 + year}-{month.ToString("D2")}-{day.ToString("D2")} " + $"{hour.ToString("D2")}:{minute.ToString("D2")}:{second.ToString("D2")}"; if(DateTime.TryParse(latestTime,out DateTime dtLatestTime)) { runConfig.LatestTimeWRFlag = true; runConfig.LatestTime = dtLatestTime; } GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, latestTime); readName = "表盘区域坐标"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_METER_REGION, Constant.MB_REGISTER_NUM_METER_REGION); //4个寄存器 string meterRegion = $"{readRegisters[0]},{readRegisters[1]} {readRegisters[2]},{readRegisters[3]}"; runConfig.MeterRegionWRFlag = true; runConfig.MeterRegion = meterRegion; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, meterRegion); if (meterType == Constant.METER_TYPE_NUM_IND || meterType == Constant.METER_TYPE_NUM) { readName = "数字区域坐标"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DIGIT_REGION, Constant.MB_REGISTER_NUM_DIGIT_REGION); //8个寄存器 string digitRegion = $"{readRegisters[0]},{readRegisters[1]} {readRegisters[2]},{readRegisters[3]} " + $"{readRegisters[4]},{readRegisters[5]} {readRegisters[6]},{readRegisters[7]}"; runConfig.DigitRegionWRFlag = true; runConfig.DigitRegion = digitRegion; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, digitRegion); } if (meterType == Constant.METER_TYPE_IND) { readName = "首尾指针坐标"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_FTIND_REGION, Constant.MB_REGISTER_NUM_FTIND_REGION); //4个寄存器 string ftIndRegion = $"{readRegisters[0]},{readRegisters[1]} {readRegisters[2]},{readRegisters[3]}"; runConfig.FTIndRegionWRFlag = true; runConfig.FTIndRegion = ftIndRegion; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, ftIndRegion); } readName = "采样识别时间间隔(分)"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_SAMPLE_INTERVAL, Constant.MB_REGISTER_NUM_SAMPLE_INTERVAL); ushort sampleInterval = readRegisters[0]; runConfig.SampleIntervalFlag = true; runConfig.SampleInterval = sampleInterval; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, sampleInterval); readName = "首次采样整点小时"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_SAMPLE_FIRST_HOUR, Constant.MB_REGISTER_NUM_SAMPLE_FIRST_HOUR); byte firstHour = (byte)(readRegisters[0] & 0xFF); runConfig.FirstHourFlag = true; runConfig.FirstHour = firstHour; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, lastUnitLevel); return runConfig; } catch (TimeoutException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}超时,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } catch (Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; RWLog?.Invoke(_message); return null; } } public WMData ReadWMData(string portName,int baudrate,byte devId) { WMData wmData = null; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { wmData = GetWMData(devId); } CloseSerial(); return wmData; } private WMData GetWMData(byte devId) { string readName = ""; try { WMData data = new WMData(); ushort[] readRegisters; readName = "波特率"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_BAUDRATE, Constant.MB_REGISTER_NUM_BAUDRATE); //data.BaudRate = readRegisters[0]; byte baudRateType = (byte)(readRegisters[0] & 0xFF); int baudRate = Tools.GetBaudRate(baudRateType); data.BaudRate = baudRate; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, baudRate); readName = "485地址"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_ADDRESS, Constant.MB_REGISTER_NUM_ADDRESS); byte slaveAddress = (byte)(readRegisters[0] & 0xFF); data.SlaveAddress = slaveAddress; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, slaveAddress); readName = "固件版本"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_FIREWARE, Constant.MB_REGISTER_NUM_FIREWARE); string fireware = $"{(readRegisters[0] & 0xFF).ToString("D2")}." + $"{(readRegisters[1] >> 8).ToString("D2")}." + $"{(readRegisters[1] & 0xFF).ToString("D2")}"; data.McuVer = fireware; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, fireware); readName = "设备SN"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DEVICE_SN, Constant.MB_REGISTER_NUM_DEVICE_SN); string deviceSn = Tools.SNBcdToString(readRegisters); data.DeviceSn = deviceSn; GenerateSendAndRecvHexLog(true, deviceSn); GenerateValueLog(readName, deviceSn); //水表类型,暂无 readName = "累计用水量"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_SAMPLE_RESULT, Constant.MB_REGISTER_NUM_SAMPLE_RESULT); ulong sampleResult = ((ulong)readRegisters[0] << 48) | ((ulong)readRegisters[1] << 32) | ((ulong)readRegisters[2] << 16) | readRegisters[3]; data.TotalFlow = sampleResult; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, sampleResult); readName = "采样时间"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_SAMPLE_TIME, Constant.MB_REGISTER_NUM_SAMPLE_TIME); GenerateSendAndRecvHexLog(true, readName); //DateTime sampleTime = new DateTime(2000+ readRegisters[0], readRegisters[1], // readRegisters[2], readRegisters[3], readRegisters[4], readRegisters[5]); string strSampleTime = $"{2000 + readRegisters[0]}-{readRegisters[1]}-{readRegisters[2]} " + $"{readRegisters[3]}:{readRegisters[4]}:{readRegisters[5]}"; if(DateTime.TryParse(strSampleTime,out DateTime sampleTime)) { data.SampleTime = sampleTime; } else { RWLog?.Invoke($"采样时间错误:{readRegisters[0]}-{readRegisters[1]}-{readRegisters[2]} " + $"{readRegisters[3]}:{readRegisters[4]}:{readRegisters[5]}"); data.SampleTime = DateTime.MinValue; } GenerateValueLog(readName, sampleTime.ToString("yyyy-MM-dd HH:mm")); //结果说明 readName = "识别结果类型"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_RESULT_TYPE, Constant.MB_REGISTER_NUM_RESULT_TYPE); byte resultType = (byte)(readRegisters[0] & 0xFF); data.ResultType = resultType; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, resultType); //保留的小数位数 readName = "单位为立方时保留的小数位数"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_RESULT_DECIMAL_PLACES, Constant.MB_REGISTER_NUM_RESULT_DECIMAL_PLACES); byte decimalPlaces = (byte)(readRegisters[0] & 0xFF); data.ResultDecimalPlaces = decimalPlaces; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, decimalPlaces); return data; } catch(TimeoutException ex) { _message = $"读取{readName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return null; } catch(SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return null; } catch(Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return null; } } //读取抄表器的当前时钟 public string ReadDeviceTime(string portName,int baudrate,byte devId) { string deviceTime = null; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { deviceTime = GetDeviceTime(devId); } CloseSerial(); return deviceTime; } private string GetDeviceTime(byte devId) { string readName = ""; try { readName = "读抄表器时钟"; ushort[] readRegisters; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DEVICE_TIME, Constant.MB_REGISTER_NUM_DEVICE_TIME); int year = (byte)(readRegisters[0] & 0xFF); int month = (byte)(readRegisters[1] & 0xFF); int day = (byte)(readRegisters[2] & 0xFF); int hour = (byte)(readRegisters[3] & 0xFF); int minute = (byte)(readRegisters[4] & 0xFF); int second = (byte)(readRegisters[5] & 0xFF); string deviceTime = $"{2000 + year}-{month.ToString("D2")}-{day.ToString("D2")} " + $"{hour.ToString("D2")}:{minute.ToString("D2")}:{second.ToString("D2")}"; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, deviceTime); return deviceTime; } catch (TimeoutException ex) { _message = $"读取{readName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return null; } catch (SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return null; } catch (Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return null; } } public bool ReadFireware(string portName,int baudrate,byte devId,out string deviceSn,out string fireware) { bool blRead = false; deviceSn = ""; fireware = ""; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { blRead = GetFirewareInfo(devId, out deviceSn, out fireware); } CloseSerial(); return blRead; } private bool GetFirewareInfo(byte devId,out string outDeviceSn,out string outFireware) { outDeviceSn = ""; outFireware = ""; string readName = ""; try { ushort[] readRegisters; readName = "固件版本"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_FIREWARE, Constant.MB_REGISTER_NUM_FIREWARE); string fireware = $"{(readRegisters[0] & 0xFF).ToString("D2")}." + $"{(readRegisters[1] >> 8).ToString("D2")}." + $"{(readRegisters[1] & 0xFF).ToString("D2")}"; outFireware = fireware; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, fireware); readName = "设备SN"; readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_DEVICE_SN, Constant.MB_REGISTER_NUM_DEVICE_SN); string deviceSn = Tools.SNBcdToString(readRegisters); outDeviceSn = deviceSn; GenerateSendAndRecvHexLog(true, deviceSn); GenerateValueLog(readName, deviceSn); return true; } catch (TimeoutException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return false; } catch (SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return false; } catch (Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); return false; } } //读取照片字节数 public ushort ReadImageSize(string portName,int baudrate,byte devId) { _portName = portName; _baudrate = baudrate; _address = devId; ushort imageSize = 0; if (OpenSerial(portName, baudrate)) { string readName = ""; // = "照片文件大小"; try { readName = "照片文件大小"; //读取照片字节数 ushort[] readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_IMAGE_SIZE, 1); imageSize = readRegisters[0]; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, imageSize); } catch (TimeoutException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch(SlaveException ex) { GenerateSendHexLog(readName); _message = $"读取{readName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch(Exception ex) { GenerateSendHexLog(readName); _message = $"读取{readName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } } CloseSerial(); return imageSize; } public bool ConnectTest(string portName, int baudrate, byte devId,out string message) { _portName = portName; _baudrate = baudrate; _address = devId; bool blConnected = false; if (OpenSerial(portName, baudrate)) { string readName = ""; // = "照片文件大小"; try { readName = "设备地址"; //读取照片字节数 ushort[] readRegisters = _modbusMaster.ReadHoldingRegisters(devId, Constant.MB_REGISTER_ADD_ADDRESS, Constant.MB_REGISTER_NUM_ADDRESS); byte slaveAddress = (byte)(readRegisters[0] & 0xFF); blConnected = slaveAddress == devId; GenerateSendAndRecvHexLog(true, readName); GenerateValueLog(readName, devId); } catch (Exception ex) { GenerateSendHexLog(readName); _lastErrorMessage = $"{_message},{ex.Message}"; RWLog?.Invoke(_message); } } CloseSerial(); _message = $"端口:{portName},波特率:{baudrate},设备地址:{devId},连接测试{(blConnected ? "通过":"失败")}"; RWLog?.Invoke(_message); message = _message; return blConnected; } public bool WriteRunConfig(string portName,int baudrate,byte devId,RunConfig runConfig) { bool blWrite = false; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName,baudrate)) { blWrite = SetRunConfig(devId,runConfig); } CloseSerial(); return blWrite; } //向设备写入配置值 private bool SetRunConfig(byte devId,RunConfig runConfig) { bool blWrite = false; string writeName = ""; try { if (runConfig.MeterTypeWRFlag) { writeName = "水表类型"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_METER_TYPE, runConfig.MeterType); GenerateValueLog(writeName, runConfig.LatestValue); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.DnValueWRFlag) { writeName = "每小时最大水流"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_DN_VALUE, runConfig.DnValue); GenerateValueLog(writeName, runConfig.DnValue); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.DigitCountWRFlag) { writeName = "数字个数"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_DIGIT_COUNT, runConfig.DigitCount); GenerateValueLog(writeName, runConfig.DigitCount); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.IndCountWRFlag) { writeName = "指针个数"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_INDICATOR_COUNT, runConfig.IndCount); GenerateValueLog(writeName, runConfig.IndCount); GenerateSendAndRecvHexLog(false, writeName); } //此项已经不需要了 /*if (runConfig.BrightValueWRFlag) { writeName = "照片亮度系数"; ushort brightValue = (ushort)(runConfig.BrightValue * 10); _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_BRIGHT_VALUE, brightValue); GenerateValueLog(writeName, runConfig.BrightValue); GenerateSendAndRecvHexLog(false, writeName); }*/ if (runConfig.LastUnitLevelWRFlag) { writeName = "尾数单位等级"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_LAST_UNIT_LEVEL, runConfig.LastUnitLevel); GenerateValueLog(writeName, runConfig.LastUnitLevel); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.UploadRedindWRFlag) { writeName = "上传红色指针读数"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_UPLOAD_REDIND , runConfig.UploadRedind); GenerateValueLog(writeName, runConfig.UploadRedind); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.LatestValueWRFlag) { writeName = "表底读数"; _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_LATEST_VALUE, runConfig.LatestValues); GenerateValueLog(writeName, runConfig.LatestValue); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.LatestTimeWRFlag && runConfig.LatestTimes != null) { writeName = "表底读数时间"; _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_LATEST_TIME, runConfig.LatestTimes); GenerateValueLog(writeName, runConfig.LatestTime.ToString("yyyy-MM-dd HH:mm:ss")); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.MeterRegionWRFlag && runConfig.MeterRegions != null) { writeName = "表盘区域坐标"; _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_METER_REGION, runConfig.MeterRegions); GenerateValueLog(writeName, runConfig.MeterRegion); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.DigitRegionWRFlag && runConfig.DigitRegions != null) { writeName = "数字区域坐标"; _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_DIGIT_REGION, runConfig.DigitRegions); GenerateValueLog(writeName, runConfig.DigitRegion); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.FTIndRegionWRFlag && runConfig.FTIndRegions != null) { writeName = "指针水表首尾同刻度坐标"; _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_FTIND_REGION, runConfig.FTIndRegions); GenerateValueLog(writeName, runConfig.FTIndRegion); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.SampleIntervalFlag) { writeName = "识别采样时间间隔(分)"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_SAMPLE_INTERVAL, runConfig.SampleInterval); GenerateValueLog(writeName, runConfig.SampleInterval); GenerateSendAndRecvHexLog(false, writeName); } if (runConfig.FirstHourFlag) { writeName = "每日首次采样"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_SAMPLE_FIRST_HOUR, runConfig.FirstHour); GenerateValueLog(writeName, runConfig.FirstHour); GenerateSendAndRecvHexLog(false, writeName); } writeName = "配置确认"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_EFFECT_FLAG, 1); GenerateValueLog(writeName, runConfig.LatestValue); GenerateSendAndRecvHexLog(false, writeName); blWrite = true; } catch (TimeoutException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch (SlaveException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch (Exception ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } return blWrite; } public bool WriteDeviceTime(string portName,int baudrate,byte devId,DateTime dateTime) { bool blWrite = false; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { blWrite = SetDeviceTime(devId, dateTime); } CloseSerial(); return blWrite; } private bool SetDeviceTime(byte devId,DateTime dateTime) { bool blWrite = false; string writeName = ""; try { writeName = "抄表器时钟"; ushort[] result = new ushort[6]; result[0] = (ushort)(dateTime.Year - 2000); result[1] = (ushort)dateTime.Month; result[2] = (ushort)dateTime.Day; result[3] = (ushort)dateTime.Hour; result[4] = (ushort)dateTime.Minute; result[5] = (ushort)dateTime.Second; _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_DEVICE_TIME , result); GenerateValueLog(writeName, dateTime.ToString("yyyy-MM-dd HH:mm:ss")); GenerateSendAndRecvHexLog(false, writeName); blWrite = true; } catch (TimeoutException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch (SlaveException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch (Exception ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } return blWrite; } //设置抄表器进行固件版本的回滚 public bool WriteDeviceRollback(string portName,int baudrate,byte devId) { bool blWrite = false; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { blWrite = SetDeviceRollback(devId); } CloseSerial(); return blWrite; } private bool SetDeviceRollback(byte devId) { bool blWrite = false; string writeName = ""; try { writeName = "固件版本回滚"; _modbusMaster.WriteSingleRegister(devId, Constant.MB_REGISTER_ADD_FIREWARE_ROLLBACK, 0x0001); GenerateValueLog(writeName, "=1"); GenerateSendAndRecvHexLog(false, writeName); blWrite = true; } catch (TimeoutException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}超时,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch (SlaveException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}Modbus错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } catch (Exception ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}错误,{ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); } return blWrite; } //写升级包的信息 public bool WrtieUpgradeInfo(string portName,int baudrate,byte devId,uint fileSize,uint fileCrc32) { bool blWrite = false; _portName = portName; _baudrate = baudrate; _address = devId; if (OpenSerial(portName, baudrate)) { blWrite = SetUpgradeInfo(devId, fileSize, fileCrc32); } CloseSerial(); return blWrite; } private bool SetUpgradeInfo(byte devId,uint fileSize,uint fileCrc32) { bool blWrite = false; string writeName = ""; try { writeName = "升级文件信息"; ushort[] infos = new ushort[4]; infos[0] = (ushort)(fileSize >> 16); infos[1] = (ushort)(fileSize & 0xFFFF); infos[2] = (ushort)(fileCrc32 >> 16); infos[3] = (ushort)(fileCrc32 & 0xFFFF); _modbusMaster.WriteMultipleRegisters(devId, Constant.MB_REGISTER_ADD_UPGRADE_DATA, infos); string upgradeInfo = $"文件长度: {fileSize},CRC32: {fileCrc32}"; GenerateValueLog(writeName, upgradeInfo); GenerateSendAndRecvHexLog(false, writeName); blWrite = true; } catch (TimeoutException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}超时,{ex.Message}"; RWLog?.Invoke(_message); } catch (SlaveException ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (Exception ex) { GenerateSendHexLog(writeName); _message = $"写入{writeName}错误,{ex.Message}"; RWLog?.Invoke(_message); } return blWrite; } private bool OpenSerial(string portName, int baudRate) { CloseSerial(); try { //除去波特率外,其它参数默认为不会被修改 SerialPort serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One); serialPort.ReadTimeout = 1000; //读取的超时时间应该短一些 serialPort.WriteTimeout = 1000; serialPort.Open(); _serialPort = serialPort; _modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort); _modbusTransport = (ModbusSerialTransport)_modbusMaster.Transport; //_modbusTransport.Retries = 1; //_modbusTransport.WaitToRetryMilliseconds = 1000; //_modbusTransport.RetryOnOldResponseThreshold = 500; _message = $"串口{portName}连接成功"; RWLog?.Invoke(_message); Logger.Info(_message); SerialConnected?.Invoke(true,_portName,_baudrate,_address); return true; } catch (Exception ex) { _message = $"串口{portName}连接失败"; _lastErrorMessage = ex.Message; RWLog?.Invoke(_message); SerialConnected?.Invoke(false,_portName,_baudrate,_address); Logger.Info(_message); Logger.Error(ex.Message); return false; } } private void CloseSerial() { try { if (_serialPort != null) { if (_serialPort.IsOpen) { _serialPort.Close(); _message = $"串口{_portName}已关闭"; SerialStatusChanged?.Invoke(false,_portName,_baudrate,_address); //串口关闭 RWLog?.Invoke(_message); Logger.Info(_message); } _serialPort.Dispose(); _serialPort = null; } _modbusTransport?.Dispose(); _modbusTransport = null; } catch (Exception ex) { _message = $"关闭串口{_portName}失败: {ex.Message}"; _lastErrorMessage = _message; RWLog?.Invoke(_message); Logger.Error(_message); } } private void GenerateValueLog(string readName,object value) { _message = $"{readName}: {value.ToString()}"; RWLog?.Invoke(_message); } private void GenerateSendHexLog(string readName) { _message = $"读取{readName},发送: {GetSendDataString()}"; RWLog?.Invoke(_message); } //发送和接收数据的日志 private void GenerateSendAndRecvHexLog(bool blRead,string wrName) { _message = $"{(blRead?"读取":"写入")}{wrName},发送: {GetSendDataString()}, 接收: {GetRecvDataString()}"; RWLog?.Invoke(_message); } private string GetSendDataString() { sentData = _modbusTransport.GetLastSentData(); if (sentData != null) { return BitConverter.ToString(sentData).Replace("-", " "); } else { return ""; } } private string GetRecvDataString() { recvData = _modbusTransport.GetLastReceivedData(); if (recvData != null) { return BitConverter.ToString(recvData).Replace("-", " "); } else { return ""; } } //----------------------------------------------- } }