StateMachineMessageCutter.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
  2. using Edge.Core.Processor.Communicator;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. namespace Dfs.WayneChina.HengshanPayTerminal
  7. {
  8. public class StateMachineMessageCutter : IMessageCutter<byte[]>
  9. {
  10. #region Internal State enum
  11. private enum State
  12. {
  13. Uninitialized,
  14. LengthReady,
  15. BodyReady,
  16. EtxReady,
  17. CrcReady
  18. }
  19. #endregion
  20. #region Fields
  21. public byte[] Message { get; private set; }
  22. public event EventHandler OnMessageCut;
  23. public event EventHandler<MessageCutterInvalidMessageReadEventArg> OnInvalidMessageRead;
  24. private string loggerAppendix = "HengshanPay Terminal";
  25. private readonly SizableWindow<byte> window;
  26. private State nextState = State.Uninitialized;
  27. private const int STX = 0xFA;
  28. #endregion
  29. #region Logger
  30. static NLog.Logger innerLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("Communicator");
  31. #endregion
  32. public StateMachineMessageCutter()
  33. {
  34. window = new SizableWindow<byte>();
  35. window.OnWindowFull += (data) =>
  36. {
  37. switch (nextState)
  38. {
  39. case State.Uninitialized:
  40. if (data.First() == STX)
  41. {
  42. window.NewSize = 6;
  43. nextState = State.LengthReady;
  44. }
  45. else
  46. {
  47. OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
  48. {
  49. Message = "invalid byte[0]: 0x" + data.First().ToString("x2") + ", will skip"
  50. });
  51. window.Clear();
  52. }
  53. break;
  54. case State.LengthReady:
  55. var countSTX = window.Count(b => b == STX);
  56. if (countSTX > 1)
  57. {
  58. //Console.WriteLine($"0xFA count: {countSTX}");
  59. innerLogger.Info($"0xFA count: {countSTX}");
  60. int index = window.ToList().LastIndexOf(STX);
  61. var tempArray = window.Skip(index).ToArray();
  62. window.Clear();
  63. nextState = State.Uninitialized;
  64. Feed(tempArray);
  65. return;
  66. }
  67. int bodyLen = window[4] * 10 + window[5];
  68. if (bodyLen > 256 || bodyLen < 2)
  69. {
  70. var safe8 = this.OnInvalidMessageRead;
  71. safe8?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
  72. {
  73. Message = "Message body length is not valid, len is: " + bodyLen
  74. });
  75. nextState = State.Uninitialized;
  76. window.Clear();
  77. window.NewSize = 1;
  78. return;
  79. }
  80. window.NewSize += bodyLen;
  81. nextState = State.BodyReady;
  82. break;
  83. case State.BodyReady:
  84. window.NewSize = window.Skip(4).Take(2).ToArray().ToInt32() + 6 + 3;
  85. nextState = State.CrcReady;
  86. break;
  87. case State.CrcReady:
  88. var stxCount = window.Count(b => b == STX);
  89. if (stxCount > 1)
  90. {
  91. //Console.WriteLine($"0xFA count: {stxCount}");
  92. innerLogger.Info($"0xFA count: {stxCount}");
  93. int length = window.Count;
  94. if (window[length - 3] == 0xFF)
  95. {
  96. //Console.WriteLine("ETX exists, consider it a complete message");
  97. innerLogger.Info("ETX exists, consider it a complete message");
  98. }
  99. else
  100. {
  101. int index = window.ToList().LastIndexOf(STX);
  102. if (index + 2 <= window.Count - 1)
  103. {
  104. byte trailingByte1 = window[index + 1];
  105. byte trailingByte2 = window[index + 2];
  106. if (trailingByte1 == trailingByte2 && trailingByte1 <= 6 && trailingByte1 > 0)
  107. {
  108. //Console.WriteLine("Possible mix of incompleted messages");
  109. innerLogger.Info("Possible mix of incompleted messages");
  110. var tempArray = window.Skip(index).ToArray();
  111. window.Clear();
  112. nextState = State.Uninitialized;
  113. Feed(tempArray);
  114. return;
  115. }
  116. }
  117. }
  118. }
  119. Message = window.ToArray();
  120. var safe = OnMessageCut;
  121. safe?.Invoke(this, null);
  122. nextState = State.Uninitialized;
  123. window.Clear();
  124. break;
  125. default:
  126. throw new ArgumentOutOfRangeException();
  127. }
  128. };
  129. }
  130. public void Feed(byte[] data)
  131. {
  132. for (int i = 0; i < data.Length; i++)
  133. {
  134. window.Add(data[i]);
  135. }
  136. }
  137. private int Get0xFAPairCountInWindow(IEnumerable<byte> data)
  138. {
  139. return (int)Math.Round(((double)(data.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero);
  140. }
  141. public int Reduce0xFAPair(IList<byte> target, int startIndex)
  142. {
  143. int reducedCount = 0;
  144. var faAppearedPositions = new List<int>();
  145. for (int i = startIndex; i < target.Count; i++)
  146. {
  147. if (target[i] == 0xFA)
  148. {
  149. if (i <= (target.Count - 2))
  150. {
  151. if (target[i + 1] == 0xFA)
  152. {
  153. faAppearedPositions.Add(i);
  154. i++;
  155. }
  156. }
  157. }
  158. }
  159. for (int i = 0; i < faAppearedPositions.Count; i++)
  160. {
  161. target.RemoveAt(faAppearedPositions[i] - i);
  162. reducedCount++;
  163. }
  164. return reducedCount;
  165. }
  166. }
  167. }