StateMachineMessageCutter.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
  2. using Edge.Core.Parser.BinaryParser.Util;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using Edge.Core.Processor.Communicator;
  10. namespace Wayne_Pump_Dart
  11. {
  12. public class StateMachineMessageCutter : IMessageCutter<byte[]>
  13. {
  14. public byte[] Message { get; private set; }
  15. public event EventHandler OnMessageCut;
  16. public event EventHandler<MessageCutterInvalidMessageReadEventArg> OnInvalidMessageRead;
  17. //static ILog innerLogger = log4net.LogManager.GetLogger("StateMachine");
  18. static NLog.Logger innerLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("Communicator");
  19. private string loggerAppendix = "Wayne_Pump_Dart msgCutter ";
  20. private readonly List<byte> buffer = new List<byte>();
  21. /// <summary>
  22. /// if the 0xFA count is odd, will use round up for count/2.
  23. /// e.g.: 0xFA appeared 2 times, return 1.
  24. /// 0xFA appeared 3 times, return 2, this is considered as window is not big enough to include further 0xFA since they're always even.
  25. /// </summary>
  26. /// <returns></returns>
  27. private int Get0xFAPairCountInWindow(IList<byte> target)
  28. {
  29. return (int)Math.Round(((double)(target.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero);
  30. }
  31. /// <summary>
  32. /// found all pair(one besides one) of 0xFA in a list, and reduce the pair to a single 0xFA.
  33. /// </summary>
  34. /// <param name="target"></param>
  35. private int Reduce0xFAPair(IList<byte> target, int from)
  36. {
  37. var faAppearedPositions = new List<int>();
  38. for (int i = from; i < target.Count - 1; i++)
  39. {
  40. if (target[i] == 0x10 && target[i + 1] == 0xFA)
  41. {
  42. faAppearedPositions.Add(i);
  43. i++;
  44. }
  45. }
  46. for (int i = 0; i < faAppearedPositions.Count; i++)
  47. {
  48. target.RemoveAt(faAppearedPositions[i] - i);
  49. }
  50. return faAppearedPositions.Count;
  51. }
  52. /// <summary>
  53. /// Code Transparency
  54. /// Code transparency for 8 bit data is achieved by Data Link escape(DLE) inser-tion.
  55. /// DLE insertion is needed when any data byte or CRC has the value SF(stop flag).
  56. /// Transmitting device transmit DLE before SF is transmitted in the data field.
  57. /// Receiving device checks when receiving SF,
  58. /// if previous received character was DLE.If so DLE is over written by the received SF
  59. /// in the line buffer.Inserted DLE:s are not included in the CRC-calculation.
  60. ///
  61. /// ETX 03H End of text
  62. /// DLE 10H Data link escape
  63. /// SF FAH Stop flag
  64. ///
  65. /// Message format:
  66. /// ADR CTRL trans_Number trans_Length trans_data CRC-1 CRC-2 ETX(0x03) SF(0xFA)
  67. /// </summary>
  68. public StateMachineMessageCutter()
  69. {
  70. }
  71. public void Feed(byte[] next)
  72. {
  73. try
  74. {
  75. //innerLogger.Debug(this.loggerAppendix + " " + next.ToHexLogString() + " is feed in Window in state: " + nextState);
  76. for (int i = 0; i < next.Length; i++)
  77. {
  78. this.buffer.Add(next[i]);
  79. if (this.buffer[0] < 0x50 || this.buffer[0] > 0x6F)
  80. {
  81. this.buffer.Clear();
  82. }
  83. //0x30 is data
  84. if (this.buffer.Count >= 2 &&
  85. ((this.buffer[1] & 0xF0) != 0x30)
  86. //ack
  87. && ((this.buffer[1] & 0xF0) != 0xC0)
  88. //nak
  89. && ((this.buffer[1] & 0xF0) != 0x50)
  90. //eot
  91. && ((this.buffer[1] & 0xF0) != 0x70)
  92. //ackpoll
  93. && ((this.buffer[1] & 0xF0) != 0xe0))
  94. {
  95. this.OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
  96. {
  97. Message = "invalid byte[1]: 0x" + this.buffer[1].ToString("X2") + ", clear buf(valid byte[0]: 0x" + this.buffer[0].ToString("X2") + ") anyway"
  98. });
  99. this.buffer.Clear();
  100. }
  101. if (this.buffer.Count >= 3
  102. && this.buffer[this.buffer.Count - 2] != 0x10
  103. && this.buffer[this.buffer.Count - 1] == 0xFA)
  104. {
  105. Reduce0xFAPair(this.buffer, 0);
  106. if (this.buffer.Count >= 44)
  107. innerLogger.Info("Long length(len: " + this.buffer.Count + ") message was cut from MsgCutter: 0x" + this.buffer.ToHexLogString());
  108. this.Message = this.buffer.ToArray();
  109. var safe = this.OnMessageCut;
  110. safe?.Invoke(this, null);
  111. this.buffer.Clear();
  112. }
  113. if (this.buffer.Count >= 45)
  114. innerLogger.Info("Long length(len: " + this.buffer.Count + ") message is still constructing in MsgCutter: 0x" + this.buffer.ToHexLogString());
  115. }
  116. }
  117. catch (Exception exx)
  118. {
  119. innerLogger.Error($"Wayne_Pump_Dart.StateMachineMessageCutter, " +
  120. $"next: 0x{next?.ToHexLogString() ?? "null"}, " +
  121. $"this.buffer: 0x{this.buffer?.ToHexLogString() ?? "null"}" +
  122. $"{Environment.NewLine}exception detail: {exx}");
  123. throw;
  124. }
  125. }
  126. }
  127. }