StateMachineMessageCutter.cs 7.5 KB

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