using MV485.db; using MV485.Dlg; using MV485.model; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MV485.helper { public class SerialPollingGroup { public string PortName { get; } //串口号为主键 private List _slaveList = new List(); private RWRunConfig _reader = new RWRunConfig(); private Timer _pollingTimer; //private bool _isReading = false; //控制串行读取 private int _isPolling = 0; // 控制是否正在轮询中,防止重入 private SemaphoreSlim _portLock = new SemaphoreSlim(1, 1); public event Action SlaveDetailAdded; public event Action SlaveStatusChanged; private bool _isPause; public SerialPollingGroup(string portName,bool isPause) { PortName = portName; _isPause = isPause; } public void Pause() { _isPause = true; } public void Resume() { _isPause = false; } public void AddDevice(TSlave slave) { if (_slaveList.Find(a => a.SlaveId == slave.SlaveId) == null) { _slaveList.Add(slave); } } public void AddDevice(ObservableCollection slaveList) { foreach(var slave in slaveList) { _slaveList.Add(slave); } } public void RemoveDevice(string slaveId) { _slaveList.RemoveAll(d => d.SlaveId == slaveId); } public void RemoveAllDevice() { _slaveList.Clear(); } public bool HasAnyDevice() { return _slaveList.Count > 0; } public void StartPolling() { _pollingTimer = new Timer(PollDevices, null, 0, 1000 * 1); } private void PollDevices(object state) { if (_isPause == true) return; // 如果已经有轮询在进行,直接跳过这轮触发 if (Interlocked.CompareExchange(ref _isPolling, 1, 0) == 1) return; try { foreach (var slave in _slaveList) { if (DateTime.Now >= slave.NextReadTime && slave.RunFlag == 1) { // 每轮最多处理一个设备 _ = PollDeviceAsync(slave); // fire-and-forget 异步执行 break; } } } catch(Exception ex) { throw new Exception(ex.Message); } Interlocked.Exchange(ref _isPolling, 0); // 标记当前已完成 } private async Task PollDeviceAsync(TSlave slave) { await _portLock.WaitAsync(); try { SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_READING); var data = _reader.ReadWMData(slave.PortName, slave.BaudRate, (byte)slave.Address); var dtReadTime = DateTime.Now; var detail = new TSlaveDetail { DetailId = Guid.NewGuid().ToString("N"), SlaveId = slave.SlaveId, ReadTime = dtReadTime.ToString("yyyy-MM-dd HH:mm:ss"), DeviceSn = "", SampleResult = 0, SampleTime = "", MeterType = 0, ImageFile = "", }; //判断是否读取照片 string imageFilePath = ""; if(data != null && detail != null &&slave.ReadImageFlag == 1) { ushort imageSize = _reader.ReadImageSize(slave.PortName, slave.BaudRate, (byte)slave.Address); imageFilePath = $"{data.DeviceSn}_{data.SampleTime.ToString("yyyyMMddHHmm")}_{dtReadTime.ToString("yyyyMMddHHmmss")}.jpg"; string savePath = ConfigManager.Instance.GetConfigValue(ConfigKey.SaveImagePath, DlgSaveImagePath.DefaultImagePath); //imageFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, // "wm_image", $"{DateTime.Now.ToString("yyyyMMdd")}",imageFilePath); imageFilePath = Path.Combine(savePath, $"{DateTime.Now.ToString("yyyyMMdd")}", imageFilePath); if (imageSize > 0) { XModemReceiver receiver = new XModemReceiver(); receiver.OnProgress += (receiveSize, fileSize) => { Console.WriteLine($"已接受{receiveSize}/{fileSize}"); }; receiver.RWLog += message => { Console.WriteLine(message); }; bool blRecv = receiver.StartReceiveFile(slave.PortName, slave.BaudRate, imageFilePath,imageSize); if (blRecv) { detail.ImageFile = imageFilePath; } } } if (data != null) { detail.DeviceSn = data.DeviceSn; //detail.ReadTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); detail.SampleResult = data.TotalFlow; detail.SampleTime = data.SampleTime.ToString("yyyy-MM-dd HH:mm:ss"); detail.MeterType = data.ResultType; //detail.ImageFile = ""; detail.ReadMemo = "成功读取"; } else { detail.ReadMemo = _reader.GetLastError(); } if (DBSlaveDetail.InsertTSlaveDetail(detail)) { SlaveDetailAdded?.Invoke(detail); } slave.LastReadTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_IDLE); } catch (Exception ex) { SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_UNCONNECTED); Logger.Error(ex.Message); } finally { //SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_IDLE); _portLock.Release(); } } //private void PollDevices(object state) //{ // if (_isReading) return; // foreach (var slave in _slaveList) // { // DateTime dtReadTime = DateTime.Now; // if (dtReadTime >= slave.NextReadTime && slave.RunFlag == 1) // { // _isReading = true; // Task.Run(() => // { // try // { // slave.RunStatus = RunStatusType.STATUS_READING; // SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_READING); // var data = _reader.ReadWMData(slave.PortName, slave.BaudRate, (byte)slave.Address); // //根据WMData生成TSlaveDetail // if (data != null) // { // TSlaveDetail detail = new TSlaveDetail() // { // DetailId = Guid.NewGuid().ToString().Replace("-", ""), // SlaveId = slave.SlaveId, // DeviceSn = data.DeviceSn, // ReadTime = dtReadTime.ToString("yyyy-MM-dd HH:mm:ss"), // SampleResult = data.TotalFlow, // SampleTime = data.SampleTime.ToString("yyyy-MM-dd HH:mm:ss"), // MeterType = data.MeterType, // ImageFile = "" // }; // //插入数据库 // bool blInsert = DBSlaveDetail.InsertTSlaveDetail(detail); // if (blInsert) // { // SlaveDetailAdded?.Invoke(detail); // } // } // } // catch (Exception ex) // { // slave.RunStatus = RunStatusType.STATUS_UNCONNECTED; // SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_UNCONNECTED); // //日志等处理 // Logger.Error(ex.Message); // } // finally // { // //设置上一次读的时间 // slave.LastReadTime = dtReadTime.ToString("yyyy-MM-dd HH:mm:ss"); // //DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // //slave.RunStatus = RunStatusType.STATUS_IDLE; // SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_IDLE); // _isReading = false; // } // }); // break; //当前时间只处理一个 // } // }//for each //} public void StopPolling() { _pollingTimer?.Dispose(); } //---------------------------------------------------------------------------------------------------- } //------------------------------------------------------------------------------------------------------- }