Peak.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. using GSG.NET.Concurrent;
  2. using GSG.NET.Extensions;
  3. using GSG.NET.Logging;
  4. using GSG.NET.Utils;
  5. using Peak.Can.Basic;
  6. using System;
  7. using System.Collections;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Threading;
  11. using VehicleControlSystem.ControlLayer.Serial.DataModel;
  12. namespace VehicleControlSystem.ControlLayer.Serial.BatteryTabos
  13. {
  14. public class Peak : ICanConnecter
  15. {
  16. /// <summary>
  17. /// Peak USB Handle
  18. /// </summary>
  19. UInt16 handle = PCANBasic.PCAN_PCIBUS2;
  20. static Logger logger = Logger.GetLogger();
  21. protected TsQueue<object> qqW = new TsQueue<object>(128);//write
  22. BMUManager manager = null;
  23. object lockObject = new object();
  24. uint idOffset = 0x460;
  25. string errormsg = string.Empty;
  26. #region Enum
  27. public enum eSendMode
  28. {
  29. MANUAL = 0,
  30. AUTO,
  31. AUTO_STOP
  32. }
  33. public enum eCanRecvCase
  34. {
  35. NONE = 0,
  36. CASE1,
  37. CASE2,
  38. CASE3,
  39. }
  40. enum eMsgCaseFirst : int
  41. {
  42. Voltage_LOW = 2,
  43. Voltage_HIGH = 3,
  44. Current_LOW = 4,
  45. Current_HIGH = 5,
  46. BatteryBitStatus_LOW = 6,
  47. BatteryBitStatus_HIGH = 7
  48. }
  49. enum eMsgCaseSecond : int
  50. {
  51. ChargeFull_LOW = 2,
  52. ChargeFull_HIGH = 3,
  53. DisChargeEmpty_LOW,
  54. DisChargeEmpty_HIGH,
  55. SOC,
  56. SOH
  57. }
  58. enum eMsgCaseThird
  59. {
  60. Capacity_LOW = 2,
  61. Capacity_High,
  62. Energy_LOW,
  63. Energy_HIGH,
  64. Temperature_LOW,
  65. Temperature_HIGH
  66. }
  67. #endregion
  68. public Peak(BMUManager mrg)
  69. {
  70. this.manager = mrg;
  71. }
  72. public void Enqueue(object o)
  73. {
  74. this.qqW.Enqueue(o);
  75. }
  76. void TryToConnect()
  77. {
  78. this.qqW.Clear();
  79. var ll = PCANBasic.Reset(this.handle);
  80. ll = PCANBasic.Uninitialize(this.handle);
  81. var result = PCANBasic.Initialize(this.handle, TPCANBaudrate.PCAN_BAUD_500K, TPCANType.PCAN_TYPE_ISA, IOPort: 460, 3);
  82. if (result == TPCANStatus.PCAN_ERROR_OK)
  83. this.IsConnected = this.GetStatus();
  84. }
  85. DateTime occurDisconnectTime;
  86. bool isConnected = false;
  87. public bool IsConnected
  88. {
  89. get => this.isConnected;
  90. set
  91. {
  92. if (this.isConnected == value) return;
  93. this.isConnected = value;
  94. if (value)
  95. this.manager._OnConnected();
  96. else { }
  97. //! Pooling Thread 내부로 이동 1분이후 알람 발생을 위해.
  98. //this.manager._OnDisconnected();
  99. }
  100. }
  101. bool isOccurDisconnect = false;
  102. public void _ThreadPoolingReceiveData()
  103. {
  104. while (!this.manager.cancel.Canceled)
  105. {
  106. try
  107. {
  108. if (!IsConnected)
  109. {
  110. Thread.Sleep(3000);
  111. this.TryToConnect();
  112. //! 정해진 시간동안 Disconnect 상태가 유지 되면 상태 보고.
  113. if (!this.isOccurDisconnect)
  114. {
  115. this.occurDisconnectTime = DateTime.Now;
  116. this.isOccurDisconnect = true;
  117. }
  118. if (DateTime.Now.Subtract(this.occurDisconnectTime).TotalMinutes > 1)
  119. {
  120. if (this.isOccurDisconnect)
  121. {
  122. this.manager._OnDisconnected();
  123. this.occurDisconnectTime = DateTime.Now;
  124. }
  125. }
  126. continue;
  127. }
  128. this.isOccurDisconnect = false;
  129. object o = this.qqW.Dequeue();
  130. if (o is PollingObject) //Scan 을 주기적 으로 진행.
  131. {
  132. //this.PollingBattery();
  133. this.Write(eSendMode.MANUAL);
  134. this.ReadMessage();
  135. }
  136. //else if ( o is ISetData ) //하나의 명령을 수행.
  137. //{
  138. // //ExecuteSetData( o as ISetData );
  139. //}
  140. else if (o is DoInvokeChangedReceivedData) //Scan 이후 결과를 처리. Manager 에서 처리
  141. {
  142. //this.manager._InvokeChgdReceivedData();
  143. this.manager._InvokeChgdWordsAndBits();
  144. }
  145. }
  146. catch (ThreadAbortException exception)
  147. {
  148. logger.E($"eSlnet {this.manager.BMUConfig.ID} - {exception.Message}");
  149. //h.CloseSocket();
  150. }
  151. catch (ObjectDisposedException exception)
  152. {
  153. logger.E(exception);
  154. this.CanError();
  155. }
  156. catch (IOException exception)
  157. {
  158. logger.E(exception);
  159. this.CanError();
  160. }
  161. catch (Exception exception)
  162. {
  163. this.CanError();
  164. logger.E($"eSlnet {exception.Message}");
  165. }
  166. }
  167. }
  168. private void PollingBattery()
  169. {
  170. var ll = this.manager.ReceivedDataDic.Values.ToList();
  171. ll.ForEach(x =>
  172. {
  173. var kind = CastTo<eDataKind>.From<Enum>(x.DataKind);
  174. switch (kind)
  175. {
  176. case eDataKind.Voltage:
  177. break;
  178. case eDataKind.Current:
  179. break;
  180. case eDataKind.BatteryState:
  181. break;
  182. case eDataKind.ChargeCompleteTime:
  183. break;
  184. case eDataKind.DisChargeCompleteTime:
  185. break;
  186. case eDataKind.SOC:
  187. break;
  188. case eDataKind.SOH:
  189. break;
  190. case eDataKind.ResidualCapacity:
  191. break;
  192. case eDataKind.ResidualEnergy:
  193. break;
  194. case eDataKind.Temperature:
  195. break;
  196. default:
  197. break;
  198. }
  199. });
  200. }
  201. int Write(eSendMode mode)
  202. {
  203. var data = new TPCANMsg();
  204. data.DATA = new byte[8];
  205. data.ID = idOffset + Convert.ToByte(this.manager.BMUConfig.ID);
  206. data.LEN = Convert.ToByte(8);
  207. data.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD;
  208. switch (mode)
  209. {
  210. case eSendMode.MANUAL:
  211. data.DATA[0] = Convert.ToByte(0x60 + Convert.ToByte(this.manager.BMUConfig.ID));
  212. break;
  213. case eSendMode.AUTO:
  214. data.DATA[0] = 0xAA;
  215. data.DATA[1] = 0xE0;
  216. break;
  217. case eSendMode.AUTO_STOP:
  218. data.DATA[0] = 0xAA;
  219. data.DATA[1] = 0x60;
  220. break;
  221. }
  222. var result = PCANBasic.Write(this.handle, ref data);
  223. if (result != TPCANStatus.PCAN_ERROR_OK)
  224. throw new Exception("Peak Write Fail");
  225. return 0;
  226. }
  227. int Write(bool auto = false)
  228. {
  229. var data = new TPCANMsg();
  230. data.DATA = new byte[8];
  231. data.ID = idOffset + Convert.ToByte(this.manager.BMUConfig.ID);
  232. data.LEN = Convert.ToByte(8);
  233. data.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD;
  234. if (auto)
  235. {
  236. data.DATA[0] = 0xAA;
  237. data.DATA[1] = 0xE0;
  238. }
  239. else
  240. {
  241. data.DATA[0] = Convert.ToByte(0x60 + Convert.ToByte(this.manager.BMUConfig.ID));
  242. }
  243. var result = PCANBasic.Write(this.handle, ref data);
  244. // Write Error
  245. if (result != TPCANStatus.PCAN_ERROR_OK)
  246. {
  247. logger.E($"[Battery Peak] - {result} -");
  248. return 9999;
  249. }
  250. return (int)result;
  251. }
  252. /// <summary>
  253. /// Peak Receive
  254. /// </summary>
  255. /// <returns></returns>
  256. TPCANStatus ReadMessage()
  257. {
  258. TPCANMsg canMsg = new TPCANMsg();
  259. canMsg.DATA = new byte[8];
  260. TPCANTimestamp CANTimeStamp;
  261. TPCANStatus stsResult = TPCANStatus.PCAN_ERROR_UNKNOWN;
  262. for (int i = 0; i < 3; i++)
  263. {
  264. Thread.Sleep(30);
  265. stsResult = PCANBasic.Read(this.handle, out canMsg, out CANTimeStamp);
  266. if (stsResult == TPCANStatus.PCAN_ERROR_OK)
  267. {
  268. if (canMsg.ID == 0x460)
  269. this.PeackCANRecv(canMsg);
  270. }
  271. else
  272. {
  273. this.IsConnected = this.GetStatus();
  274. return stsResult;
  275. }
  276. //else if (canMsg.ID != 0x460)
  277. //{
  278. // this.IsConnected = this.GetStatus();
  279. // return stsResult = TPCANStatus.PCAN_ERROR_UNKNOWN;
  280. //}
  281. }
  282. return stsResult;
  283. }
  284. void PeackCANRecv(TPCANMsg recv)
  285. {
  286. var mb = new MemoryBuffer(recv.DATA);
  287. if (mb.Length < 8)
  288. {
  289. logger.E($" - [Battery Recv Length Error] - {mb.Length} -");
  290. return;
  291. }
  292. mb.Read1Byte();
  293. var index = (eCanRecvCase)mb.Read1Byte();
  294. switch (index)
  295. {
  296. case eCanRecvCase.NONE:
  297. break;
  298. case eCanRecvCase.CASE1:
  299. this.manager.ReceivedDataDic[eDataKind.Voltage].Value = mb.ReadLeShort();
  300. this.manager. ReceivedDataDic[eDataKind.Current].Value = mb.ReadLeShort();
  301. this.manager.ReceivedDataDic[eDataKind.BatteryState].Value = mb.ReadLeShort();
  302. break;
  303. case eCanRecvCase.CASE2:
  304. this.manager.ReceivedDataDic[eDataKind.ChargeCompleteTime].Value = mb.ReadLeShort();
  305. this.manager.ReceivedDataDic[eDataKind.DisChargeCompleteTime].Value = mb.ReadLeShort();
  306. this.manager.ReceivedDataDic[eDataKind.SOC].Value = mb.ReadByte();
  307. this.manager.ReceivedDataDic[eDataKind.SOH].Value = mb.ReadByte();
  308. break;
  309. case eCanRecvCase.CASE3:
  310. this.manager.ReceivedDataDic[eDataKind.ResidualCapacity].Value = mb.ReadLeShort();
  311. this.manager.ReceivedDataDic[eDataKind.ResidualEnergy].Value = mb.ReadLeShort();
  312. this.manager.ReceivedDataDic[eDataKind.Temperature].Value = mb.ReadLeShort();
  313. break;
  314. }
  315. }
  316. /// <summary>
  317. /// Battery State To -> [2^6] Bool List
  318. /// </summary>
  319. /// <param name="state"></param>
  320. void BatteryStateCheck(double state)
  321. {
  322. var cd = Convert.ToByte(state);
  323. var rs = new BitArray(new byte[] { cd });
  324. var result = rs.Cast<object>().ToList();
  325. }
  326. void CanError()
  327. {
  328. this.IsConnected = false;
  329. var result = PCANBasic.Uninitialize(this.handle);
  330. }
  331. bool GetStatus()
  332. {
  333. TPCANMsg msg;
  334. msg.DATA = new byte[8];
  335. TPCANTimestamp canTimeStamp;
  336. Write(eSendMode.MANUAL);
  337. Thread.Sleep(100);
  338. var state = PCANBasic.Read(this.handle, out msg, out canTimeStamp);
  339. if (state != TPCANStatus.PCAN_ERROR_OK)
  340. {
  341. logger.E($"[BMS] - Disconnected [{state}]");
  342. return false;
  343. }
  344. //if (msg.ID == 0x460)
  345. // result = true;
  346. //else
  347. // result = false;
  348. return true;
  349. }
  350. private void DisConnect()
  351. {
  352. this.IsConnected = false;
  353. PCANBasic.Reset(this.handle);
  354. PCANBasic.Uninitialize(this.handle);
  355. this.manager._OnDisconnected();
  356. }
  357. }
  358. }