Advantech.cs 13 KB

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