Peak.cs 13 KB

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