SerialPortocol.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. using AwInitilizer.Model;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace AwInitilizer.Assist
  10. {
  11. public class SerialPortocol : INotifyPropertyChanged
  12. {
  13. private static int TimeoutDuration = 1 * 1000;
  14. public event EventHandler<EvseSerialResponseModel> OnMsgReceived;
  15. public event PropertyChangedEventHandler PropertyChanged;
  16. public string LatestErrorMessage { get; private set; }
  17. private Interface.ISerialPort _serialPort;
  18. private SemaphoreQueue receivedBufferLock = new SemaphoreQueue(1, 1);
  19. private byte[] receivedBuffer = new byte[0];
  20. private bool IsSerialPortAvaliable
  21. {
  22. get
  23. {
  24. if (_serialPort == null || _serialPort.ConnectStatus != Interface.ConnectStatus.Connected)
  25. return false;
  26. return true;
  27. }
  28. }
  29. public void Open() => _serialPort?.Open();
  30. public void Close() => _serialPort?.Close();
  31. public Interface.ConnectStatus ConnectStatus => _serialPort == null ? Interface.ConnectStatus.Cleared : _serialPort.ConnectStatus;
  32. public SerialPortocol(Interface.ISerialPort serialPort)
  33. {
  34. _serialPort = serialPort;
  35. _serialPort.OnDataReceived += _serialPort_OnDataReceived;
  36. _serialPort.PropertyChanged += _serialPort_PropertyChanged;
  37. }
  38. public async Task<string> GetModelName()
  39. {
  40. return await SendAndWait(0x24, SimpleStringParser);
  41. }
  42. public async Task<bool> SetModelName(string modelName)
  43. {
  44. var param = Encoding.ASCII.GetBytes(modelName);
  45. return await SendAndWait(0x83, SimpleResultParser, parameter: param);
  46. }
  47. public async Task<string> GetSerialNumber()
  48. {
  49. return await SendAndWait(0x23, SerialNumberParser);
  50. string SerialNumberParser(byte[] parameter)
  51. {
  52. if (parameter == null || parameter.Length < 19)
  53. return null;
  54. var snBytes = parameter.Skip(8).ToArray();
  55. return SimpleStringParser(snBytes);
  56. }
  57. }
  58. public async Task<bool> SetSerialNumber(string serialNumber)
  59. {
  60. DateTime nowTime = DateTime.Now.ToUniversalTime();
  61. var DataString = nowTime.ToString("yyyyMMdd");
  62. var dateTimeParam = Encoding.ASCII.GetBytes(DataString);
  63. var snParam = Encoding.ASCII.GetBytes(serialNumber);
  64. var param = new byte[dateTimeParam.Length + snParam.Length];
  65. Array.Copy(dateTimeParam, 0, param, 0, dateTimeParam.Length);
  66. Array.Copy(snParam, 0, param, dateTimeParam.Length, snParam.Length);
  67. return await SendAndWait(0x82, SimpleResultParser, parameter: param);
  68. }
  69. public async Task<DateTime?> GetUTCTime()
  70. {
  71. return await SendAndWait(0x26, TimeParser);
  72. DateTime? TimeParser(byte[] parameter)
  73. {
  74. if (parameter == null || parameter.Length < 14)
  75. return null;
  76. string rawDateString = Encoding.ASCII.GetString(parameter);
  77. var year = int.Parse(rawDateString.Substring(0,4));
  78. var month = int.Parse(rawDateString.Substring(4, 2));
  79. var day = int.Parse(rawDateString.Substring(6, 2));
  80. var hour = int.Parse(rawDateString.Substring(8, 2));
  81. var minut = int.Parse(rawDateString.Substring(10, 2));
  82. var sec = int.Parse(rawDateString.Substring(12, 2));
  83. try
  84. {
  85. DateTime dateTime = new DateTime(year, month, day, hour, minut, sec);
  86. return dateTime;
  87. }
  88. catch
  89. {
  90. return null;
  91. }
  92. }
  93. }
  94. public async Task<bool> SetUTCTime(DateTime dateTime)
  95. {
  96. var DataString = dateTime.ToString("yyyyMMddHHmmss");
  97. var param = Encoding.ASCII.GetBytes(DataString);
  98. return await SendAndWait(0x87, SimpleResultParser, parameter: param);
  99. }
  100. public async Task<string> GetFourGenModuleVersion()
  101. {
  102. return await SendAndWait(0x31, SimpleStringParser, WaitSec: 5);
  103. }
  104. public async Task<SimStatus> GetSimStatus()
  105. {
  106. return await SendAndWait(0x34, SimStatusParser);
  107. SimStatus SimStatusParser(byte[] param)
  108. {
  109. if(param==null || param.Length != 39)
  110. {
  111. return null;
  112. }
  113. SimStatus toReturn = new SimStatus();
  114. toReturn.IsInstalled = param[0] == 0x01;
  115. toReturn.ICCID = param.Skip(1).Take(22).ToArray();
  116. toReturn.IMSI = param.Skip(22).Take(16).ToArray();
  117. return toReturn;
  118. }
  119. }
  120. public async Task<bool> SettingChangeConfirm()
  121. {
  122. return await SendAndWait(0x91, SimpleResultParser, WaitSec: 10);
  123. }
  124. private void _serialPort_PropertyChanged(object sender, PropertyChangedEventArgs e)
  125. {
  126. if (e.PropertyName == nameof(Interface.ISerialPort.ConnectStatus))
  127. {
  128. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SerialPortocol.ConnectStatus)));
  129. }
  130. }
  131. private async Task<T> SendAndWait<T>(byte command, Func<byte[], T> ParserFunction, byte[] parameter = null, T defauit = default(T), int WaitSec = -1)
  132. {
  133. if (!IsSerialPortAvaliable)
  134. return defauit;
  135. T result = defauit;
  136. SemaphoreSlim signal = new SemaphoreSlim(0, 1);
  137. OnMsgReceived += EvseSerialProtocal_OnMsgReceived;
  138. if (SendMessage(command, parameter))
  139. {
  140. if (WaitSec < 0)
  141. await signal.WaitAsync(TimeoutDuration);
  142. else
  143. await signal.WaitAsync(WaitSec * 1000);
  144. }
  145. OnMsgReceived -= EvseSerialProtocal_OnMsgReceived;
  146. if (signal.CurrentCount == 0)
  147. {
  148. //timeout
  149. LatestErrorMessage = "Serial portocol timeout";
  150. }
  151. return result;
  152. void EvseSerialProtocal_OnMsgReceived(object sender, EvseSerialResponseModel e)
  153. {
  154. if (e.Command == command)
  155. {
  156. result = ParserFunction(e.Parameter);
  157. signal.Release();
  158. }
  159. }
  160. }
  161. private bool SendMessage(byte command, byte[] parameter = null)
  162. {
  163. if (!IsSerialPortAvaliable)
  164. return false;
  165. int parameterLength = parameter == null ? 0 : parameter.Length;
  166. int messagLength = parameterLength + 7;
  167. byte[] message = new byte[parameterLength + 7];
  168. message[0] = 0xAA;
  169. message[1] = 0x10; //Master
  170. message[2] = 0xFF; //broadcast
  171. message[3] = command;
  172. message[4] = (byte)(parameterLength % 256);
  173. message[5] = (byte)(parameterLength / 256);
  174. if (parameter != null && parameter.Length > 0)
  175. Array.Copy(parameter, 0, message, 6, parameter.Length);
  176. byte chksum = 0x00;
  177. for (int idx = 0; idx < parameterLength; idx++)
  178. chksum ^= message[6 + idx];
  179. message[6 + parameterLength] = chksum;
  180. _serialPort?.WriteData(message);
  181. //_serialPort?.WriteData(message);
  182. return true;
  183. }
  184. private void _serialPort_OnDataReceived(object sender, byte[] e)
  185. {
  186. receivedBufferLock.Wait();
  187. {
  188. var tmp = new byte[e.Length + receivedBuffer.Length];
  189. Array.Copy(receivedBuffer, 0, tmp, 0, receivedBuffer.Length);
  190. Array.Copy(e, 0, tmp, receivedBuffer.Length, e.Length);
  191. //receivedBuffer = tmp;
  192. receivedBuffer = ParseReceive(tmp, out List<EvseSerialResponseModel> reponseModels);
  193. foreach (EvseSerialResponseModel responseModel in reponseModels)
  194. {
  195. OnMsgReceived?.Invoke(this, responseModel);
  196. }
  197. }
  198. receivedBufferLock.Release();
  199. }
  200. private bool SimpleResultParser(byte[] parameter)
  201. {
  202. if (parameter == null || parameter.Length != 1)
  203. return false;
  204. var resultByte = parameter[0];
  205. return resultByte == 0x01;
  206. }
  207. private string SimpleHexStringParser(byte[] parameter)
  208. {
  209. if (parameter == null)
  210. {
  211. return default;
  212. }
  213. return BitConverter.ToString(parameter).Replace("-", " ");
  214. }
  215. private string SimpleStringParser(byte[] parameter)
  216. {
  217. if(parameter == null)
  218. {
  219. LatestErrorMessage = "parameter null exception";
  220. return string.Empty;
  221. }
  222. if (parameter.Length <= 1)
  223. {
  224. LatestErrorMessage = $"parameter legnth {parameter.Length} error";
  225. return string.Empty;
  226. }
  227. if(parameter.ToList().Contains(0x00))
  228. {
  229. int endIndex = Array.FindIndex(parameter, (x) => { return x == 0x00; });
  230. //int endIndex = parameter.FindIndex((x) => { return x == 0x00; });
  231. if (endIndex != default)
  232. {
  233. parameter = parameter.Take(endIndex).ToArray();
  234. }
  235. }
  236. while (parameter.Length != 0 && parameter[parameter.Length - 1] < 32)
  237. {
  238. parameter = parameter.Take(parameter.Length - 1).ToArray();
  239. }
  240. try
  241. {
  242. var result = Encoding.ASCII.GetString(parameter);
  243. return result;
  244. }
  245. catch(Exception e)
  246. {
  247. LatestErrorMessage = $"string parse exception : {e.Message}";
  248. return string.Empty;
  249. }
  250. }
  251. private byte[] ParseReceive(byte[] parseData, out List<EvseSerialResponseModel> reponseModels)
  252. {
  253. reponseModels = new List<EvseSerialResponseModel>();
  254. while (true)
  255. {
  256. int stIndex = -1;
  257. //find first 0xff 0xff
  258. for (int index = 0; index < parseData.Length - 1; index++)
  259. {
  260. if (parseData[index] == 0xAA)
  261. {
  262. stIndex = index;
  263. break;
  264. }
  265. }
  266. //int index = Array.IndexOf(receivedBuffer, startChar);
  267. if (stIndex < 0)
  268. break;
  269. //discard data before 0xaa
  270. parseData = parseData.Skip(stIndex).ToArray();
  271. //response msg is at leat 6 bytes
  272. if (parseData.Length < 6)
  273. break;
  274. var msgLength = parseData[5] * 256 + parseData[4];
  275. if (parseData.Length < msgLength + 6)
  276. break;
  277. //Add handle data
  278. reponseModels.Add(new EvseSerialResponseModel() {
  279. Source = parseData[1],
  280. Destination = parseData[2],
  281. Command = parseData[3],
  282. Parameter = parseData.Skip(6).Take(msgLength).ToArray()
  283. });
  284. parseData = parseData.Skip(msgLength + 6).ToArray();
  285. }
  286. return parseData;
  287. }
  288. }
  289. }