SerialPollingGroup.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using MV485.db;
  2. using MV485.Dlg;
  3. using MV485.model;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Collections.ObjectModel;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. namespace MV485.helper
  13. {
  14. public class SerialPollingGroup
  15. {
  16. public string PortName { get; } //串口号为主键
  17. private List<TSlave> _slaveList = new List<TSlave>();
  18. private RWRunConfig _reader = new RWRunConfig();
  19. private Timer _pollingTimer;
  20. //private bool _isReading = false; //控制串行读取
  21. private int _isPolling = 0; // 控制是否正在轮询中,防止重入
  22. private SemaphoreSlim _portLock = new SemaphoreSlim(1, 1);
  23. public event Action<TSlaveDetail> SlaveDetailAdded;
  24. public event Action<string, RunStatusType> SlaveStatusChanged;
  25. private bool _isPause;
  26. public SerialPollingGroup(string portName,bool isPause)
  27. {
  28. PortName = portName;
  29. _isPause = isPause;
  30. }
  31. public void Pause()
  32. {
  33. _isPause = true;
  34. }
  35. public void Resume()
  36. {
  37. _isPause = false;
  38. }
  39. public void AddDevice(TSlave slave)
  40. {
  41. if (_slaveList.Find(a => a.SlaveId == slave.SlaveId) == null)
  42. {
  43. _slaveList.Add(slave);
  44. }
  45. }
  46. public void AddDevice(ObservableCollection<TSlave> slaveList)
  47. {
  48. foreach(var slave in slaveList)
  49. {
  50. _slaveList.Add(slave);
  51. }
  52. }
  53. public void RemoveDevice(string slaveId)
  54. {
  55. _slaveList.RemoveAll(d => d.SlaveId == slaveId);
  56. }
  57. public void RemoveAllDevice()
  58. {
  59. _slaveList.Clear();
  60. }
  61. public bool HasAnyDevice()
  62. {
  63. return _slaveList.Count > 0;
  64. }
  65. public void StartPolling()
  66. {
  67. _pollingTimer = new Timer(PollDevices, null, 0, 1000 * 1);
  68. }
  69. private void PollDevices(object state)
  70. {
  71. if (_isPause == true) return;
  72. // 如果已经有轮询在进行,直接跳过这轮触发
  73. if (Interlocked.CompareExchange(ref _isPolling, 1, 0) == 1)
  74. return;
  75. try
  76. {
  77. foreach (var slave in _slaveList)
  78. {
  79. if (DateTime.Now >= slave.NextReadTime && slave.RunFlag == 1)
  80. {
  81. // 每轮最多处理一个设备
  82. _ = PollDeviceAsync(slave); // fire-and-forget 异步执行
  83. break;
  84. }
  85. }
  86. }
  87. catch(Exception ex)
  88. {
  89. throw new Exception(ex.Message);
  90. }
  91. Interlocked.Exchange(ref _isPolling, 0); // 标记当前已完成
  92. }
  93. private async Task PollDeviceAsync(TSlave slave)
  94. {
  95. await _portLock.WaitAsync();
  96. try
  97. {
  98. SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_READING);
  99. var data = _reader.ReadWMData(slave.PortName, slave.BaudRate, (byte)slave.Address);
  100. var dtReadTime = DateTime.Now;
  101. var detail = new TSlaveDetail
  102. {
  103. DetailId = Guid.NewGuid().ToString("N"),
  104. SlaveId = slave.SlaveId,
  105. ReadTime = dtReadTime.ToString("yyyy-MM-dd HH:mm:ss"),
  106. DeviceSn = "",
  107. SampleResult = 0,
  108. SampleTime = "",
  109. MeterType = 0,
  110. ImageFile = "",
  111. };
  112. //判断是否读取照片
  113. string imageFilePath = "";
  114. if(data != null && detail != null &&slave.ReadImageFlag == 1)
  115. {
  116. ushort imageSize = _reader.ReadImageSize(slave.PortName, slave.BaudRate, (byte)slave.Address);
  117. imageFilePath = $"{data.DeviceSn}_{data.SampleTime.ToString("yyyyMMddHHmm")}_{dtReadTime.ToString("yyyyMMddHHmmss")}.jpg";
  118. string savePath = ConfigManager.Instance.GetConfigValue(ConfigKey.SaveImagePath, DlgSaveImagePath.DefaultImagePath);
  119. //imageFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
  120. // "wm_image", $"{DateTime.Now.ToString("yyyyMMdd")}",imageFilePath);
  121. imageFilePath = Path.Combine(savePath, $"{DateTime.Now.ToString("yyyyMMdd")}", imageFilePath);
  122. if (imageSize > 0)
  123. {
  124. XModemReceiver receiver = new XModemReceiver();
  125. receiver.OnProgress += (receiveSize, fileSize) =>
  126. {
  127. Console.WriteLine($"已接受{receiveSize}/{fileSize}");
  128. };
  129. receiver.RWLog += message =>
  130. {
  131. Console.WriteLine(message);
  132. };
  133. bool blRecv = receiver.StartReceiveFile(slave.PortName, slave.BaudRate, imageFilePath,imageSize);
  134. if (blRecv)
  135. {
  136. detail.ImageFile = imageFilePath;
  137. }
  138. }
  139. }
  140. if (data != null)
  141. {
  142. detail.DeviceSn = data.DeviceSn;
  143. //detail.ReadTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  144. detail.SampleResult = data.TotalFlow;
  145. detail.SampleTime = data.SampleTime.ToString("yyyy-MM-dd HH:mm:ss");
  146. detail.MeterType = data.ResultType;
  147. //detail.ImageFile = "";
  148. detail.ReadMemo = "成功读取";
  149. }
  150. else
  151. {
  152. detail.ReadMemo = _reader.GetLastError();
  153. }
  154. if (DBSlaveDetail.InsertTSlaveDetail(detail))
  155. {
  156. SlaveDetailAdded?.Invoke(detail);
  157. }
  158. slave.LastReadTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  159. SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_IDLE);
  160. }
  161. catch (Exception ex)
  162. {
  163. SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_UNCONNECTED);
  164. Logger.Error(ex.Message);
  165. }
  166. finally
  167. {
  168. //SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_IDLE);
  169. _portLock.Release();
  170. }
  171. }
  172. //private void PollDevices(object state)
  173. //{
  174. // if (_isReading) return;
  175. // foreach (var slave in _slaveList)
  176. // {
  177. // DateTime dtReadTime = DateTime.Now;
  178. // if (dtReadTime >= slave.NextReadTime && slave.RunFlag == 1)
  179. // {
  180. // _isReading = true;
  181. // Task.Run(() =>
  182. // {
  183. // try
  184. // {
  185. // slave.RunStatus = RunStatusType.STATUS_READING;
  186. // SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_READING);
  187. // var data = _reader.ReadWMData(slave.PortName, slave.BaudRate, (byte)slave.Address);
  188. // //根据WMData生成TSlaveDetail
  189. // if (data != null)
  190. // {
  191. // TSlaveDetail detail = new TSlaveDetail()
  192. // {
  193. // DetailId = Guid.NewGuid().ToString().Replace("-", ""),
  194. // SlaveId = slave.SlaveId,
  195. // DeviceSn = data.DeviceSn,
  196. // ReadTime = dtReadTime.ToString("yyyy-MM-dd HH:mm:ss"),
  197. // SampleResult = data.TotalFlow,
  198. // SampleTime = data.SampleTime.ToString("yyyy-MM-dd HH:mm:ss"),
  199. // MeterType = data.MeterType,
  200. // ImageFile = ""
  201. // };
  202. // //插入数据库
  203. // bool blInsert = DBSlaveDetail.InsertTSlaveDetail(detail);
  204. // if (blInsert)
  205. // {
  206. // SlaveDetailAdded?.Invoke(detail);
  207. // }
  208. // }
  209. // }
  210. // catch (Exception ex)
  211. // {
  212. // slave.RunStatus = RunStatusType.STATUS_UNCONNECTED;
  213. // SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_UNCONNECTED);
  214. // //日志等处理
  215. // Logger.Error(ex.Message);
  216. // }
  217. // finally
  218. // {
  219. // //设置上一次读的时间
  220. // slave.LastReadTime = dtReadTime.ToString("yyyy-MM-dd HH:mm:ss");
  221. // //DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  222. // //slave.RunStatus = RunStatusType.STATUS_IDLE;
  223. // SlaveStatusChanged?.Invoke(slave.SlaveId, RunStatusType.STATUS_IDLE);
  224. // _isReading = false;
  225. // }
  226. // });
  227. // break; //当前时间只处理一个
  228. // }
  229. // }//for each
  230. //}
  231. public void StopPolling()
  232. {
  233. _pollingTimer?.Dispose();
  234. }
  235. //----------------------------------------------------------------------------------------------------
  236. }
  237. //-------------------------------------------------------------------------------------------------------
  238. }