TemperatureSerialDevice.cs 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308
  1. using Aitex.Core.RT.Event;
  2. using Aitex.Core.RT.Log;
  3. using Aitex.Core.RT.OperationCenter;
  4. using Aitex.Core.RT.Routine;
  5. using Aitex.Core.RT.SCCore;
  6. using Aitex.Core.Util;
  7. using MECF.Framework.Common.Device.TemperatureController;
  8. using System;
  9. using System.Collections.Concurrent;
  10. using System.Collections.Generic;
  11. using System.IO.Ports;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. namespace MECF.Framework.Common.Device.ResistivityProbe
  17. {
  18. public enum TemperatureVariableType
  19. {
  20. Decade=0,
  21. Kilo=1,
  22. Buffer=2,
  23. SignedDecade=3,
  24. Alarm=4
  25. }
  26. public class TemperatureSerialDevice
  27. {
  28. #region Delegate
  29. public delegate void UpdateVariableValueChanged(string name,byte address, string variableName, object variableValue);
  30. #endregion
  31. #region 常量
  32. private const byte SOH = 0x01;
  33. private const byte STX = 0x02;
  34. private const byte ETX = 0x03;
  35. private const byte ENQ = 0x05;
  36. private const byte ACK = 0x06;
  37. private const byte CR = 0x0D;
  38. private const byte ADD_FLAG = 0x30;
  39. private const byte MINUS_FLAG = 0x2D;
  40. #endregion
  41. #region 内部变量
  42. /// <summary>
  43. /// 串口
  44. /// </summary>
  45. private SerialPort _serialPort;
  46. /// <summary>
  47. /// 连接状态
  48. /// </summary>
  49. private bool _connected;
  50. /// <summary>
  51. /// 模块名称
  52. /// </summary>
  53. private string _name;
  54. /// <summary>
  55. /// 重连
  56. /// </summary>
  57. private bool _reconnect;
  58. /// <summary>
  59. /// 队列锁
  60. /// </summary>
  61. private object _locker = new object();
  62. /// <summary>
  63. /// 发送队列
  64. /// </summary>
  65. private List<TemperatureSendData> _sendQueueDatas = new List<TemperatureSendData>();
  66. /// <summary>
  67. /// 定时器
  68. /// </summary>
  69. private PeriodicJob _periodJob;
  70. /// <summary>
  71. /// 离线时间
  72. /// </summary>
  73. private DateTime _offlineDateTime;
  74. /// <summary>
  75. /// 接收超时
  76. /// </summary>
  77. private int _receiveTimeOut;
  78. /// <summary>
  79. /// 错误
  80. /// </summary>
  81. private string _errorMsg = "";
  82. /// <summary>
  83. /// 首次连接成功
  84. /// </summary>
  85. private bool _isFirstConnected = false;
  86. #endregion
  87. #region 事件
  88. /// <summary>
  89. /// 变量变更事件
  90. /// </summary>
  91. public event UpdateVariableValueChanged OnUpdateVariableValueChanged;
  92. #endregion
  93. #region 属性
  94. /// <summary>
  95. /// 连接状态
  96. /// </summary>
  97. public bool Connected
  98. {
  99. get { return _connected; }
  100. set
  101. {
  102. _connected = value;
  103. }
  104. }
  105. #endregion
  106. /// <summary>
  107. /// 初始化
  108. /// </summary>
  109. /// <param name="portName"></param>
  110. /// <param name="baudRate"></param>
  111. /// <param name="stopBits"></param>
  112. /// <param name="dataBits"></param>
  113. /// <param name="parity"></param>
  114. public TemperatureSerialDevice(string name, string portName, int baudRate = 9600, StopBits stopBits = StopBits.One, int dataBits = 8, Parity parity = Parity.None,bool reconnect=false,int receiveTimeout=2000)
  115. {
  116. _serialPort = new SerialPort();
  117. _serialPort.BaudRate = baudRate;
  118. _serialPort.StopBits = stopBits;
  119. _serialPort.DataBits = dataBits;
  120. _serialPort.Parity = parity;
  121. _serialPort.PortName = portName;
  122. _serialPort.ReadTimeout = receiveTimeout;
  123. _serialPort.ErrorReceived += SerialPort_ErrorReceived;
  124. _name = name;
  125. _reconnect = reconnect;
  126. _receiveTimeOut = receiveTimeout;
  127. _periodJob = new PeriodicJob(50, OnTimer, $"{_name}_sender", false, true);
  128. }
  129. /// <summary>
  130. /// 初始化
  131. /// </summary>
  132. public void Initialize()
  133. {
  134. _periodJob.Start();
  135. }
  136. /// <summary>
  137. /// 启动
  138. /// </summary>
  139. public void Start()
  140. {
  141. Open();
  142. }
  143. /// <summary>
  144. /// 打开
  145. /// </summary>
  146. private void Open()
  147. {
  148. if (!_connected)
  149. {
  150. try
  151. {
  152. if (!_serialPort.IsOpen)
  153. {
  154. _serialPort.Open();
  155. }
  156. _connected = true;
  157. if (!_isFirstConnected)
  158. {
  159. _isFirstConnected = true;
  160. }
  161. LOG.WriteLog(eEvent.INFO_TEMPERATURE, _name, $"connect {_serialPort.PortName} Success");
  162. }
  163. catch (Exception ex)
  164. {
  165. WriteErrorMsg(ex.Message);
  166. }
  167. }
  168. }
  169. /// <summary>
  170. /// 关闭
  171. /// </summary>
  172. public void Close()
  173. {
  174. try
  175. {
  176. _connected = false;
  177. _serialPort.Close();
  178. }
  179. catch (Exception ex)
  180. {
  181. WriteErrorMsg(ex.Message);
  182. }
  183. }
  184. /// <summary>
  185. /// 出现错误
  186. /// </summary>
  187. /// <param name="sender"></param>
  188. /// <param name="e"></param>
  189. private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
  190. {
  191. LOG.WriteLog(eEvent.ERR_TEMPERATURE, _name, e.EventType.ToString());
  192. }
  193. /// <summary>
  194. /// 定时器
  195. /// </summary>
  196. /// <returns></returns>
  197. private bool OnTimer()
  198. {
  199. if (!_connected)
  200. {
  201. ///离线超过5秒清理发送队列
  202. if(DateTime.Now.Subtract(_offlineDateTime).TotalSeconds>=5&&_sendQueueDatas.Count>0)
  203. {
  204. ClearSendQueue();
  205. }
  206. if (_reconnect)
  207. {
  208. if (_isFirstConnected)
  209. {
  210. Open();
  211. }
  212. }
  213. else
  214. {
  215. _periodJob.Stop();
  216. }
  217. return true;
  218. }
  219. else
  220. {
  221. SendData();
  222. }
  223. return true;
  224. }
  225. /// <summary>
  226. /// 发送数据
  227. /// </summary>
  228. private void SendData()
  229. {
  230. int queueCount = _sendQueueDatas.Count;
  231. if (_sendQueueDatas.Count != 0)
  232. {
  233. lock (_locker)
  234. {
  235. TemperatureSendData data = _sendQueueDatas[0];
  236. _sendQueueDatas.RemoveAt(0);
  237. if (data != null)
  238. {
  239. if (data.Type == 0)//设置
  240. {
  241. WriteInfoMsg(0, $"execute set {data.Type} queue length {queueCount}");
  242. try
  243. {
  244. SettingOperation(data.Id, data.Command, data.Data);
  245. }
  246. catch (Exception ex)
  247. {
  248. WriteErrorMsg(ex.Message);
  249. }
  250. }
  251. else//读取变量
  252. {
  253. WriteInfoMsg(0, $"execute read {data.Type} queue length {queueCount}");
  254. ReadVariableData(data);
  255. }
  256. }
  257. }
  258. }
  259. }
  260. /// <summary>
  261. /// 读取变量
  262. /// </summary>
  263. /// <param name="data"></param>
  264. private void ReadVariableData(TemperatureSendData data)
  265. {
  266. switch(data.VariableType)
  267. {
  268. case TemperatureVariableType.Decade:
  269. if (ReadDecadeParam(data.Id, data.Command, out double decadeValue))
  270. {
  271. _errorMsg = "";
  272. UpdateVariableValue(data,decadeValue);
  273. }
  274. break;
  275. case TemperatureVariableType.Kilo:
  276. if (ReadKiloParam(data.Id, data.Command, out int kiloValue))
  277. {
  278. _errorMsg = "";
  279. UpdateVariableValue(data,kiloValue);
  280. }
  281. break;
  282. case TemperatureVariableType.SignedDecade:
  283. if(ReadSignedDecadeParam(data.Id,data.Command,out double signedDecadeValue))
  284. {
  285. _errorMsg = "";
  286. UpdateVariableValue(data,signedDecadeValue);
  287. }
  288. break;
  289. case TemperatureVariableType.Buffer:
  290. if(ReadBufferParam(data.Id,data.Command,out byte[] buffer,11))
  291. {
  292. _errorMsg = "";
  293. UpdateVariableValue(data,BitConverter.ToString(buffer));
  294. }
  295. break;
  296. default:
  297. break;
  298. }
  299. }
  300. /// <summary>
  301. /// 变量数据
  302. /// </summary>
  303. /// <param name="data"></param>
  304. private void UpdateVariableValue(TemperatureSendData data,object variableValue)
  305. {
  306. data.VariableValue = variableValue;
  307. if(OnUpdateVariableValueChanged!=null)
  308. {
  309. OnUpdateVariableValueChanged(_name,data.Id, data.VariableName, data.VariableValue);
  310. }
  311. }
  312. /// <summary>
  313. /// 清空发送队列
  314. /// </summary>
  315. private void ClearSendQueue()
  316. {
  317. try
  318. {
  319. while (_sendQueueDatas.Count != 0)
  320. {
  321. _sendQueueDatas.Clear();
  322. }
  323. }
  324. catch(Exception ex)
  325. {
  326. WriteErrorMsg(ex.Message,false);
  327. }
  328. }
  329. /// <summary>
  330. /// 插入数据
  331. /// </summary>
  332. /// <param name="data"></param>
  333. private void InsertDataToQueue(TemperatureSendData data)
  334. {
  335. lock (_locker)
  336. {
  337. _sendQueueDatas.Insert(0, data);
  338. }
  339. }
  340. /// 插入数据
  341. /// </summary>
  342. /// <param name="data"></param>
  343. private void AddDataToQueue(TemperatureSendData data)
  344. {
  345. lock (_locker)
  346. {
  347. _sendQueueDatas.Add(data);
  348. }
  349. }
  350. #region Temperature
  351. /// <summary>
  352. /// 插入数据
  353. /// </summary>
  354. /// <param name="data"></param>
  355. private void InsertDatasToQueue(TemperatureSendData data,TemperatureSendData readData)
  356. {
  357. lock(_locker)
  358. {
  359. _sendQueueDatas.Insert(0, readData);
  360. _sendQueueDatas.Insert(0, data);
  361. }
  362. }
  363. /// <summary>
  364. /// 设置温度
  365. /// </summary>
  366. /// <param name="id"></param>
  367. /// <param name="temperature"></param>
  368. /// <returns></returns>
  369. public bool SetTargetTemperature(byte id,double temperature)
  370. {
  371. TemperatureSendData data = new TemperatureSendData();
  372. data.Id = id;
  373. data.Command = 0x31;
  374. data.Data=GetDecadeBytes(temperature);
  375. data.Type = 0;
  376. TemperatureSendData readData = GetReadTargetTemperature(id);
  377. InsertDatasToQueue(data,readData);
  378. return true;
  379. }
  380. /// <summary>
  381. /// 获取读取目标温度指令
  382. /// </summary>
  383. /// <param name="id"></param>
  384. /// <returns></returns>
  385. private TemperatureSendData GetReadTargetTemperature(byte id)
  386. {
  387. TemperatureSendData data = new TemperatureSendData();
  388. data.Id = id;
  389. data.Type = 1;
  390. data.Command = 0x31;
  391. data.VariableName = "TargetTemperature";
  392. data.VariableType = TemperatureVariableType.Decade;
  393. return data;
  394. }
  395. /// <summary>
  396. /// 读取温度
  397. /// </summary>
  398. /// <param name="id"></param>
  399. /// <param name="temperature"></param>
  400. /// <returns></returns>
  401. public void ReadTargetTemperature(byte id)
  402. {
  403. TemperatureSendData data=GetReadTargetTemperature(id);
  404. AddDataToQueue(data);
  405. }
  406. /// <summary>
  407. /// 读取Heat Exchanger温度
  408. /// </summary>
  409. /// <param name="id"></param>
  410. /// <param name="temperature"></param>
  411. /// <returns></returns>
  412. public void ReadHeatExchangerInternelSensorTemperature(byte id)
  413. {
  414. TemperatureSendData data = new TemperatureSendData();
  415. data.Id = id;
  416. data.Type = 1;
  417. data.Command = 0x32;
  418. data.VariableName = "HeatExchangerTemperature";
  419. data.VariableType = TemperatureVariableType.Decade;
  420. AddDataToQueue(data);
  421. }
  422. /// <summary>
  423. /// 读取Reservior温度
  424. /// </summary>
  425. /// <param name="id"></param>
  426. /// <param name="temperature"></param>
  427. /// <returns></returns>
  428. public void ReadReserviorExtendSensorTemperature(byte id)
  429. {
  430. TemperatureSendData data = new TemperatureSendData();
  431. data.Id = id;
  432. data.Type = 1;
  433. data.Command = 0x33;
  434. data.VariableName = "ReserviorTemperature";
  435. data.VariableType = TemperatureVariableType.Decade;
  436. AddDataToQueue(data);
  437. }
  438. #endregion
  439. #region Alarm
  440. /// <summary>
  441. /// 读取Alarm状态
  442. /// </summary>
  443. /// <param name="id"></param>
  444. /// <param name="status"></param>
  445. /// <returns></returns>
  446. public void ReadAlarmStatus(byte id)
  447. {
  448. TemperatureSendData data = new TemperatureSendData();
  449. data.Id = id;
  450. data.Type = 1;
  451. data.VariableName = "Alarm";
  452. data.Command = 0x34;
  453. data.VariableType = TemperatureVariableType.Buffer;
  454. AddDataToQueue(data);
  455. }
  456. #endregion
  457. #region Offset
  458. /// <summary>
  459. /// 设置温度
  460. /// </summary>
  461. /// <param name="id"></param>
  462. /// <param name="temperature"></param>
  463. /// <returns></returns>
  464. public void SetOffsetValue(byte id, double temperature)
  465. {
  466. TemperatureSendData data = new TemperatureSendData();
  467. data.Id = id;
  468. data.Type = 0;
  469. data.Command = 0x36;
  470. data.Data = GetOffsetBytes(temperature);
  471. TemperatureSendData readData = GetReadOffsetData(id);
  472. InsertDatasToQueue(data,readData);
  473. }
  474. /// <summary>
  475. /// 获取读取Offset数据
  476. /// </summary>
  477. /// <param name="id"></param>
  478. /// <returns></returns>
  479. private TemperatureSendData GetReadOffsetData(byte id)
  480. {
  481. TemperatureSendData data = new TemperatureSendData();
  482. data.Id = id;
  483. data.Type = 1;
  484. data.VariableName = "Offset";
  485. data.Command = 0x36;
  486. data.VariableType = TemperatureVariableType.SignedDecade;
  487. return data;
  488. }
  489. /// <summary>
  490. /// 读取Alarm状态
  491. /// </summary>
  492. /// <param name="id"></param>
  493. /// <param name="offset"></param>
  494. /// <returns></returns>
  495. public void ReadOffsetValue(byte id)
  496. {
  497. TemperatureSendData data=GetReadOffsetData(id);
  498. AddDataToQueue(data);
  499. }
  500. #endregion
  501. #region Control Operation Model
  502. /// <summary>
  503. /// 设置Control Operation模式
  504. /// </summary>
  505. /// <param name="id"></param>
  506. /// <param name="temperature"></param>
  507. /// <returns></returns>
  508. public void SetControlOperationModel(byte id, int controlOperationModel)
  509. {
  510. TemperatureSendData data = new TemperatureSendData();
  511. data.Id = id;
  512. data.Type = 0;
  513. data.Command = 0x39;
  514. data.Data = GetKiloBytes(controlOperationModel);
  515. TemperatureSendData readData=GetReadControlOperationData(id);
  516. InsertDatasToQueue(data, readData);
  517. }
  518. /// <summary>
  519. /// 获取读取操作模式的数据
  520. /// </summary>
  521. /// <param name="id"></param>
  522. /// <returns></returns>
  523. private TemperatureSendData GetReadControlOperationData(byte id)
  524. {
  525. TemperatureSendData data = new TemperatureSendData();
  526. data.Id = id;
  527. data.Type = 1;
  528. data.VariableName = "ControlOperationModel";
  529. data.Command = 0x39;
  530. data.VariableType = TemperatureVariableType.Kilo;
  531. return data;
  532. }
  533. /// <summary>
  534. /// 读取Control Operation Model
  535. /// </summary>
  536. /// <param name="id"></param>
  537. /// <param name="offset"></param>
  538. /// <returns></returns>
  539. public void ReadControlOperationModel(byte id)
  540. {
  541. TemperatureSendData data = GetReadControlOperationData(id);
  542. InsertDataToQueue(data);
  543. }
  544. #endregion
  545. #region PB Range
  546. /// <summary>
  547. /// 设置PB范围
  548. /// </summary>
  549. /// <param name="id"></param>
  550. /// <param name="temperature"></param>
  551. /// <returns></returns>
  552. public void SetPBRange(byte id, double pbrange)
  553. {
  554. TemperatureSendData data = new TemperatureSendData();
  555. data.Id = id;
  556. data.Type = 0;
  557. data.Command = 0x41;
  558. data.Data = GetDecadeBytes(pbrange);
  559. InsertDataToQueue(data);
  560. }
  561. /// <summary>
  562. /// 读取PB范围
  563. /// </summary>
  564. /// <param name="id"></param>
  565. /// <param name="pbrange"></param>
  566. /// <returns></returns>
  567. public void ReadPBRange(byte id)
  568. {
  569. TemperatureSendData data = new TemperatureSendData();
  570. data.Id = id;
  571. data.Type = 1;
  572. data.VariableName = "PBRange";
  573. data.Command = 0x41;
  574. data.VariableType = TemperatureVariableType.Decade;
  575. AddDataToQueue(data);
  576. }
  577. #endregion
  578. #region ARW
  579. /// <summary>
  580. /// 设置ARW范围
  581. /// </summary>
  582. /// <param name="id"></param>
  583. /// <param name="temperature"></param>
  584. /// <returns></returns>
  585. public void SetARWRange(byte id, double arwRange)
  586. {
  587. TemperatureSendData data = new TemperatureSendData();
  588. data.Id = id;
  589. data.Type = 0;
  590. data.Command = 0x42;
  591. data.Data = GetDecadeBytes(arwRange);
  592. InsertDataToQueue(data);
  593. }
  594. /// <summary>
  595. /// 读取Heat Exchanger温度
  596. /// </summary>
  597. /// <param name="id"></param>
  598. /// <param name="arwrange"></param>
  599. /// <returns></returns>
  600. public void ReadARWRange(byte id)
  601. {
  602. TemperatureSendData data = new TemperatureSendData();
  603. data.Id = id;
  604. data.Type = 1;
  605. data.VariableName = "ARWRange";
  606. data.Command = 0x42;
  607. data.VariableType = TemperatureVariableType.Decade;
  608. AddDataToQueue(data);
  609. }
  610. #endregion
  611. #region I constant
  612. /// <summary>
  613. /// 设置I Constant
  614. /// </summary>
  615. /// <param name="id"></param>
  616. /// <param name="temperature"></param>
  617. /// <returns></returns>
  618. public void SetIConstant(byte id, int iConstant)
  619. {
  620. TemperatureSendData data = new TemperatureSendData();
  621. data.Id = id;
  622. data.Type = 0;
  623. data.Command = 0x43;
  624. data.Data = GetKiloBytes(iConstant);
  625. InsertDataToQueue(data);
  626. }
  627. /// <summary>
  628. /// 读取Heat Exchanger温度
  629. /// </summary>
  630. /// <param name="id"></param>
  631. /// <param name="arwrange"></param>
  632. /// <returns></returns>
  633. public void ReadIConstant(byte id)
  634. {
  635. TemperatureSendData data = new TemperatureSendData();
  636. data.Id = id;
  637. data.Type = 1;
  638. data.VariableName = "IConstant";
  639. data.Command = 0x43;
  640. data.VariableType = TemperatureVariableType.Kilo;
  641. AddDataToQueue(data);
  642. }
  643. #endregion
  644. #region D constant
  645. /// <summary>
  646. /// 设置D Constant
  647. /// </summary>
  648. /// <param name="id"></param>
  649. /// <param name="temperature"></param>
  650. /// <returns></returns>
  651. public void SetDConstant(byte id, int dConstant)
  652. {
  653. TemperatureSendData data = new TemperatureSendData();
  654. data.Id = id;
  655. data.Type = 0;
  656. data.Command = 0x44;
  657. data.Data = GetDecadeBytes(dConstant);
  658. InsertDataToQueue(data);
  659. }
  660. /// <summary>
  661. /// 读取D Constant
  662. /// </summary>
  663. /// <param name="id"></param>
  664. /// <param name="arwrange"></param>
  665. /// <returns></returns>
  666. public void ReadDConstant(byte id)
  667. {
  668. TemperatureSendData data = new TemperatureSendData();
  669. data.Id = id;
  670. data.Type = 1;
  671. data.VariableName = "DConstant";
  672. data.Command = 0x44;
  673. data.VariableType = TemperatureVariableType.Decade;
  674. AddDataToQueue(data);
  675. }
  676. #endregion
  677. #region Output Ratio
  678. /// <summary>
  679. /// Output 比例
  680. /// </summary>
  681. /// <param name="id"></param>
  682. /// <param name="temperature"></param>
  683. /// <returns></returns>
  684. public void SetOutputRatio(byte id, int outputRatio)
  685. {
  686. TemperatureSendData data = new TemperatureSendData();
  687. data.Id = id;
  688. data.Type = 0;
  689. data.Command = 0x45;
  690. data.Data = GetKiloBytes(outputRatio);
  691. InsertDataToQueue(data);
  692. }
  693. /// <summary>
  694. /// 读取output比例
  695. /// </summary>
  696. /// <param name="id"></param>
  697. /// <param name="arwrange"></param>
  698. /// <returns></returns>
  699. public void ReadOutputRatio(byte id)
  700. {
  701. TemperatureSendData data = new TemperatureSendData();
  702. data.Id = id;
  703. data.Type = 1;
  704. data.VariableName = "OutputRatio";
  705. data.Command = 0x45;
  706. data.VariableType = TemperatureVariableType.Kilo;
  707. AddDataToQueue(data);
  708. }
  709. #endregion
  710. #region Heating Power upper limit
  711. /// <summary>
  712. /// Heating Power upper limit 比例
  713. /// </summary>
  714. /// <param name="id"></param>
  715. /// <param name="temperature"></param>
  716. /// <returns></returns>
  717. public void SetHeatingPowerUpperLimit(byte id, int upperLimit)
  718. {
  719. TemperatureSendData data = new TemperatureSendData();
  720. data.Id = id;
  721. data.Type = 0;
  722. data.Command = 0x46;
  723. data.Data = GetKiloBytes(upperLimit);
  724. InsertDataToQueue(data);
  725. }
  726. /// <summary>
  727. /// 读取output比例
  728. /// </summary>
  729. /// <param name="id"></param>
  730. /// <param name="arwrange"></param>
  731. /// <returns></returns>
  732. public void ReadHeatingPowerUpperLimit(byte id)
  733. {
  734. TemperatureSendData data = new TemperatureSendData();
  735. data.Id = id;
  736. data.Type = 1;
  737. data.VariableName = "HeatingPowerUpperLimit";
  738. data.Command = 0x46;
  739. data.VariableType = TemperatureVariableType.Kilo;
  740. AddDataToQueue(data);
  741. }
  742. #endregion
  743. #region Cooling Power upper limit
  744. /// <summary>
  745. /// Heating Power upper limit 比例
  746. /// </summary>
  747. /// <param name="id"></param>
  748. /// <param name="temperature"></param>
  749. /// <returns></returns>
  750. public void SetCoolingPowerUpperLimit(byte id, int upperLimit)
  751. {
  752. TemperatureSendData data = new TemperatureSendData();
  753. data.Id = id;
  754. data.Type = 0;
  755. data.Command = 0x47;
  756. data.Data = GetKiloBytes(upperLimit);
  757. InsertDataToQueue(data);
  758. }
  759. /// <summary>
  760. /// 读取output比例
  761. /// </summary>
  762. /// <param name="id"></param>
  763. /// <param name="arwrange"></param>
  764. /// <returns></returns>
  765. public void ReadCoolingPowerUpperLimit(byte id)
  766. {
  767. TemperatureSendData data = new TemperatureSendData();
  768. data.Id = id;
  769. data.Type = 1;
  770. data.VariableName = "CoolingPowerUpperLimit";
  771. data.Command = 0x47;
  772. data.VariableType = TemperatureVariableType.Kilo;
  773. AddDataToQueue(data);
  774. }
  775. #endregion
  776. #region Saving RAM to EEPROM
  777. /// <summary>
  778. /// 将RAM保存至EEPROM
  779. /// </summary>
  780. /// <param name="id"></param>
  781. /// <param name="temperature"></param>
  782. /// <returns></returns>
  783. public void SaveRAMToEEPROM(byte id)
  784. {
  785. TemperatureSendData data = new TemperatureSendData();
  786. data.Id = id;
  787. data.Type = 0;
  788. data.Command = 0x48;
  789. data.Data = new byte[] { };
  790. InsertDataToQueue(data);
  791. }
  792. #endregion
  793. /// <summary>
  794. /// 读取千单位数据
  795. /// </summary>
  796. /// <param name="id"></param>
  797. /// <param name="command"></param>
  798. /// <param name="param"></param>
  799. /// <returns></returns>
  800. private bool ReadKiloParam(byte id,byte command,out int param,int responseLength=12)
  801. {
  802. param = 0;
  803. try
  804. {
  805. byte[] response = AfterSendDataWithResponse(id, command,responseLength);
  806. if (response==null)
  807. {
  808. return false;
  809. }
  810. //解析
  811. if (response[0] == SOH && response[11] == CR && response[3] == command)
  812. {
  813. if (response[1] == GetSendByteData(id))
  814. {
  815. byte[] byt = new byte[4];
  816. Array.Copy(response, 4, byt, 0, byt.Length);
  817. param = GetOriginalData(byt[0]) * 1000 + GetOriginalData(byt[1]) * 100 + GetOriginalData(byt[2]) * 10 + GetOriginalData(byt[3]);
  818. return true;
  819. }
  820. else
  821. {
  822. string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
  823. WriteErrorMsg(msg, false);
  824. return false;
  825. }
  826. }
  827. else
  828. {
  829. string msg = "response data invalid";
  830. WriteErrorMsg(msg, false);
  831. return false;
  832. }
  833. }
  834. catch (Exception ex)
  835. {
  836. WriteErrorMsg(ex.Message);
  837. return false;
  838. }
  839. }
  840. /// <summary>
  841. /// 根据十单位数据
  842. /// </summary>
  843. /// <param name="id"></param>
  844. /// <param name="command"></param>
  845. /// <param name="decadeValue"></param>
  846. /// <returns></returns>
  847. private bool ReadDecadeParam(byte id, byte command, out double decadeValue, int responseLength = 12)
  848. {
  849. decadeValue = 0;
  850. byte[] response = AfterSendDataWithResponse(id, command,responseLength);
  851. if(response==null)
  852. {
  853. return false;
  854. }
  855. //解析
  856. if (response[0] == SOH && response[11] == CR && response[3] == command)
  857. {
  858. if (response[1] == GetSendByteData(id))
  859. {
  860. byte[] tmpData = new byte[4];
  861. Array.Copy(response, 4, tmpData, 0, tmpData.Length);
  862. decadeValue = GetOriginalData(tmpData[0]) * 10 + GetOriginalData(tmpData[1]) + GetOriginalData(tmpData[2]) * 0.1 + GetOriginalData(tmpData[3]) * 0.01;
  863. return true;
  864. }
  865. else
  866. {
  867. string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
  868. WriteErrorMsg(msg, false);
  869. return false;
  870. }
  871. }
  872. else
  873. {
  874. string msg = "response data invalid";
  875. WriteErrorMsg(msg,false);
  876. return false;
  877. }
  878. }
  879. /// <summary>
  880. /// 根据有符号十单位数据
  881. /// </summary>
  882. /// <param name="id"></param>
  883. /// <param name="command"></param>
  884. /// <param name="signedDecadeValue"></param>
  885. /// <returns></returns>
  886. private bool ReadSignedDecadeParam(byte id, byte command, out double signedDecadeValue, int responseLength = 12)
  887. {
  888. signedDecadeValue = 0;
  889. byte[] response = AfterSendDataWithResponse(id, command, responseLength);
  890. if (response == null)
  891. {
  892. return false;
  893. }
  894. string err = "response data invalid";
  895. //解析
  896. if (response[0] == SOH && response[11] == CR && response[3] == command)
  897. {
  898. if (response[1] == GetSendByteData(id))
  899. {
  900. byte[] byt = new byte[4];
  901. Array.Copy(response, 4, byt, 0, byt.Length);
  902. double tmp = GetOriginalData(byt[1]) + GetOriginalData(byt[2]) * 0.1 + GetOriginalData(byt[3]) * 0.01;
  903. if (byt[0] == MINUS_FLAG)
  904. {
  905. signedDecadeValue = -tmp;
  906. return true;
  907. }
  908. else if (byt[0] == ADD_FLAG)
  909. {
  910. signedDecadeValue = tmp;
  911. return true;
  912. }
  913. else
  914. {
  915. WriteErrorMsg(err, false);
  916. return false;
  917. }
  918. }
  919. else
  920. {
  921. string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
  922. WriteErrorMsg(msg, false);
  923. return false;
  924. }
  925. }
  926. else
  927. {
  928. WriteErrorMsg(err, false);
  929. return false;
  930. }
  931. }
  932. /// <summary>
  933. /// 根据数组数据
  934. /// </summary>
  935. /// <param name="id"></param>
  936. /// <param name="command"></param>
  937. /// <param name="signedDecadeValue"></param>
  938. /// <returns></returns>
  939. private bool ReadBufferParam(byte id, byte command, out byte[] buffer, int responseLength = 12)
  940. {
  941. buffer = null;
  942. byte[] response = AfterSendDataWithResponse(id, command, responseLength);
  943. if (response == null)
  944. {
  945. return false;
  946. }
  947. //解析
  948. if (response[0] == SOH && response[responseLength-1] == CR && response[3] == command)
  949. {
  950. if (response[1] == GetSendByteData(id))
  951. {
  952. buffer = new byte[responseLength - 8];
  953. Array.Copy(response, 4, buffer, 0, buffer.Length);
  954. return true;
  955. }
  956. else
  957. {
  958. string msg = $"receive id {GetOriginalData(response[1])} is not matched with command id {id}";
  959. WriteErrorMsg(msg, false);
  960. return false;
  961. }
  962. }
  963. else
  964. {
  965. string err = "response data invalid";
  966. WriteErrorMsg(err,false);
  967. return false;
  968. }
  969. }
  970. /// <summary>
  971. /// 设置操作
  972. /// </summary>
  973. /// <param name="id"></param>
  974. /// <param name="command"></param>
  975. /// <param name="byt"></param>
  976. /// <returns></returns>
  977. private bool SettingOperation(byte id, byte command, byte[] byt)
  978. {
  979. ClearPreCache();
  980. byte ut = GetSendByteData(id);
  981. byte[] data = new byte[byt.Length + 8];
  982. data[0] = SOH;
  983. data[1] = ut;
  984. data[2] = STX;
  985. data[3] = command;
  986. if (byt != null && byt.Length != 0)
  987. {
  988. Array.Copy(byt, 0, data, 4, byt.Length);
  989. }
  990. data[data.Length - 4] = ETX;
  991. data[data.Length - 3] = 0;
  992. data[data.Length - 2] = 0;
  993. data[data.Length - 1] = CR;
  994. //检验
  995. byte[] checksumData = new byte[data.Length - 5];
  996. //从数据第2位至ETX前所有数组
  997. Array.Copy(data, 1, checksumData, 0, checksumData.Length);
  998. byte[] checkSumByte = CalculateCheckSum(checksumData);
  999. Array.Copy(checkSumByte, 0, data, data.Length - 3, checkSumByte.Length);
  1000. _serialPort.Write(data, 0, data.Length);
  1001. WriteInfoMsg(1, data);
  1002. //接收
  1003. byte[] response = ReadData(id,command,3);
  1004. if (response != null)
  1005. {
  1006. if (response[0] == ACK && response[2] == CR && response[1] == ut)
  1007. {
  1008. return true;
  1009. }
  1010. else
  1011. {
  1012. string err = "response data invalid";
  1013. WriteErrorMsg(err, false);
  1014. return false;
  1015. }
  1016. }
  1017. else
  1018. {
  1019. return false;
  1020. }
  1021. }
  1022. /// <summary>
  1023. /// 发送数据后获取数组
  1024. /// </summary>
  1025. /// <param name="id"></param>
  1026. /// <param name="command"></param>
  1027. /// <returns></returns>
  1028. private byte[] AfterSendDataWithResponse(byte id,byte command,int responseLength=12)
  1029. {
  1030. try
  1031. {
  1032. ClearPreCache();
  1033. byte ut = GetSendByteData(id);
  1034. byte[] data = new byte[7] { SOH, ut, ENQ, command, 0, 0, CR };
  1035. //检验
  1036. byte[] checksumData = new byte[data.Length - 4];
  1037. //从数据第2位至ETX前所有数组
  1038. Array.Copy(data, 1, checksumData, 0, checksumData.Length);
  1039. byte[] checkSumByte = CalculateCheckSum(checksumData);
  1040. Array.Copy(checkSumByte, 0, data, data.Length - 3, checkSumByte.Length);
  1041. _serialPort.Write(data, 0, data.Length);
  1042. WriteInfoMsg(1, data);
  1043. //接收
  1044. byte[] response = ReadData(id,command,responseLength);
  1045. if (response == null)
  1046. {
  1047. return null;
  1048. }
  1049. //ack
  1050. byte[] ack = new byte[] { ACK, ut, CR };
  1051. _serialPort.Write(ack, 0, ack.Length);
  1052. WriteInfoMsg(1, ack);
  1053. return response;
  1054. }
  1055. catch(Exception ex)
  1056. {
  1057. _connected = false;
  1058. WriteErrorMsg(ex.Message);
  1059. return null;
  1060. }
  1061. }
  1062. /// <summary>
  1063. /// 计算获取检验和数组
  1064. /// </summary>
  1065. /// <param name="checkSumData"></param>
  1066. /// <returns></returns>
  1067. private byte[] CalculateCheckSum(byte[] checkSumData)
  1068. {
  1069. short checksum = 0;
  1070. for(int i=0;i<checkSumData.Length;i++)
  1071. {
  1072. checksum += checkSumData[i];
  1073. }
  1074. byte[] byt=BitConverter.GetBytes(checksum);
  1075. byte[] data = new byte[2];
  1076. data[0] = GetSendByteData((byte)(byt[0]/16));
  1077. data[1] = GetSendByteData((byte)(byt[0]&0x0F));
  1078. return data;
  1079. }
  1080. /// <summary>
  1081. /// 获取温度数组(10|1|0.1|0.01)
  1082. /// </summary>
  1083. /// <param name="temperature"></param>
  1084. /// <returns></returns>
  1085. private byte[] GetDecadeBytes(double temperature)
  1086. {
  1087. byte decade = GetSendByteData((byte)Math.Floor(temperature / 10));
  1088. byte unit = GetSendByteData((byte)Math.Floor(temperature % 10));
  1089. byte digital = GetSendByteData((byte)Math.Floor(temperature * 10 % 10));
  1090. return new byte[4] { decade, unit, digital, ADD_FLAG };
  1091. }
  1092. /// <summary>
  1093. /// 获取Offset数组(正/负|1|0.1|0.01)
  1094. /// </summary>
  1095. /// <param name="temperature"></param>
  1096. /// <returns></returns>
  1097. private byte[] GetOffsetBytes(double temperature)
  1098. {
  1099. byte decade = temperature>0?ADD_FLAG:MINUS_FLAG;
  1100. byte unit = GetSendByteData((byte)Math.Floor(temperature % 10));
  1101. byte digital = GetSendByteData((byte)Math.Floor(temperature * 10 % 10));
  1102. byte digital2 = GetSendByteData((byte)Math.Floor(temperature * 100 % 10));
  1103. return new byte[4] { decade, unit, digital, digital2 };
  1104. }
  1105. /// <summary>
  1106. /// 获取Control Operation Model(1000|100|10|1)
  1107. /// </summary>
  1108. /// <param name="controlOperationModel"></param>
  1109. /// <returns></returns>
  1110. private byte[] GetKiloBytes(int controlOperationModel)
  1111. {
  1112. byte kilo= GetSendByteData((byte)(controlOperationModel / 1000));
  1113. byte hundred = GetSendByteData((byte)(controlOperationModel %1000/ 100));
  1114. byte decade = GetSendByteData((byte)(controlOperationModel %100/ 10));
  1115. byte unit = GetSendByteData((byte)(controlOperationModel % 10));
  1116. return new byte[4] { kilo, hundred, decade, unit };
  1117. }
  1118. /// <summary>
  1119. /// 获取发送位数据
  1120. /// </summary>
  1121. /// <param name="originalData"></param>
  1122. /// <returns></returns>
  1123. private byte GetSendByteData(byte originalData)
  1124. {
  1125. return (byte)(ADD_FLAG + originalData);
  1126. }
  1127. /// <summary>
  1128. /// 解析源数据
  1129. /// </summary>
  1130. /// <param name="receivedData"></param>
  1131. /// <returns></returns>
  1132. private byte GetOriginalData(byte receivedData)
  1133. {
  1134. return (byte)(receivedData - ADD_FLAG);
  1135. }
  1136. /// <summary>
  1137. /// 读取数据
  1138. /// </summary>
  1139. /// <param name="length"></param>
  1140. /// <returns></returns>
  1141. private byte[] ReadData(byte id,byte command ,int length)
  1142. {
  1143. byte[] response=new byte[length];
  1144. DateTime dt = DateTime.Now;
  1145. int count = 0;
  1146. bool hasReceivedData = false; // 新增标志,用于记录是否接收到数据
  1147. while (true)
  1148. {
  1149. int bytLength = _serialPort.BytesToRead;
  1150. if (bytLength > 0)
  1151. {
  1152. byte[] bytes = new byte[bytLength];
  1153. _serialPort.Read(bytes,0,bytes.Length);
  1154. WriteInfoMsg(0, bytes);
  1155. if (bytLength + count >= length)
  1156. {
  1157. Array.Copy(bytes, 0, response, count, length-count);
  1158. hasReceivedData = true;
  1159. break;
  1160. }
  1161. else
  1162. {
  1163. Array.Copy(bytes, 0, response, count, bytLength);
  1164. }
  1165. count += bytLength;
  1166. }
  1167. if (DateTime.Now.Subtract(dt).TotalMilliseconds >= _receiveTimeOut)
  1168. {
  1169. string err =$"receive id {id} command {command.ToString("X2")} timeout {length}";
  1170. TemperatureConfigManager.Instance.UpdataTCPowerConnectDic(_name + '-' + id.ToString(),false);//读取数据超时认为TC断联
  1171. WriteErrorMsg(err,false);
  1172. return null;
  1173. }
  1174. Thread.Sleep(2);
  1175. }
  1176. TemperatureConfigManager.Instance.UpdataTCPowerConnectDic(_name + '-' + id.ToString(), hasReceivedData);
  1177. WriteInfoMsg(0, response);
  1178. return response;
  1179. }
  1180. /// <summary>
  1181. /// 记录错误信息
  1182. /// </summary>
  1183. /// <param name="msg"></param>
  1184. private void WriteErrorMsg(string msg,bool disConnected=true)
  1185. {
  1186. if (disConnected)
  1187. {
  1188. _connected = false;
  1189. _offlineDateTime = DateTime.Now;
  1190. }
  1191. bool enableLog = false;
  1192. if (SC.ContainsItem("Log.EnableTemperatureLog"))
  1193. {
  1194. enableLog = SC.GetValue<bool>("Log.EnableTemperatureLog");
  1195. }
  1196. if (enableLog)
  1197. {
  1198. if (_errorMsg != msg)
  1199. {
  1200. _errorMsg = msg;
  1201. LOG.WriteBackgroundLog(eEvent.ERR_TEMPERATURE, _name, msg);
  1202. }
  1203. }
  1204. }
  1205. /// <summary>
  1206. /// 写日志
  1207. /// </summary>
  1208. /// <param name="bytes"></param>
  1209. private void WriteInfoMsg(int logType, byte[] bytes)
  1210. {
  1211. bool enableLog = false;
  1212. if (SC.ContainsItem("Log.EnableTemperatureLog"))
  1213. {
  1214. enableLog = SC.GetValue<bool>("Log.EnableTemperatureLog");
  1215. }
  1216. if (enableLog)
  1217. {
  1218. string str = string.Join(" ", Array.ConvertAll(bytes, x => x.ToString("X2")));
  1219. string type = logType == 0 ? "receive" : "send";
  1220. LOG.WriteBackgroundLog(eEvent.INFO_TEMPERATURE, _name, $"{type} {str}");
  1221. }
  1222. }
  1223. /// <summary>
  1224. /// 写日志
  1225. /// </summary>
  1226. /// <param name="bytes"></param>
  1227. private void WriteInfoMsg(int logType, string str)
  1228. {
  1229. bool enableLog = false;
  1230. if (SC.ContainsItem("Log.EnableTemperatureLog"))
  1231. {
  1232. enableLog = SC.GetValue<bool>("Log.EnableTemperatureLog");
  1233. }
  1234. if (enableLog)
  1235. {
  1236. string type = logType == 0 ? "receive" : "send";
  1237. LOG.WriteBackgroundLog(eEvent.INFO_TEMPERATURE, _name, $"{type} {str}");
  1238. }
  1239. }
  1240. /// <summary>
  1241. /// 清除前面的缓存
  1242. /// </summary>
  1243. private void ClearPreCache()
  1244. {
  1245. while (_serialPort.BytesToRead != 0)
  1246. {
  1247. byte[] bytes = new byte[_serialPort.BytesToRead];
  1248. _serialPort.Read(bytes, 0, bytes.Length);
  1249. }
  1250. }
  1251. }
  1252. /// <summary>
  1253. /// 发送数据类
  1254. /// </summary>
  1255. internal class TemperatureSendData
  1256. {
  1257. public byte Id { get; set; }
  1258. public byte Command { get; set; }
  1259. public byte[] Data { get; set; }
  1260. /// <summary>
  1261. /// 0-set,1-get
  1262. /// </summary>
  1263. public byte Type { get; set; }
  1264. /// <summary>
  1265. /// 变量
  1266. /// </summary>
  1267. public string VariableName { get; set; }
  1268. /// <summary>
  1269. /// 变量数值
  1270. /// </summary>
  1271. public object VariableValue { get; set; }
  1272. /// <summary>
  1273. /// 变量类型(0-十位数据,1-千位数据,2-数组,3-有符号十位数据)
  1274. /// </summary>
  1275. public TemperatureVariableType VariableType { get; set; }
  1276. }
  1277. }