QueryInTankInventoryReportResponse.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. using Edge.Core.Parser.BinaryParser.Util;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Text;
  7. namespace VeederRoot_ATG_Console.MessageEntity.Incoming
  8. {
  9. /// <summary>
  10. /// i|I201
  11. /// </summary>
  12. public class QueryInTankInventoryReportResponse : IncomingMessageBase
  13. {
  14. public DateTime? CurrentDateAndTime
  15. {
  16. get
  17. {
  18. if (base.FunctionCode.Item1 == MessageFormat.Display)
  19. return null;
  20. return DateTime.ParseExact(
  21. Encoding.ASCII.GetString(base.DataFieldAndOptionalCheckSumAndETX.Take(10).ToArray()),
  22. "yyMMddHHmm", CultureInfo.InvariantCulture);
  23. }
  24. }
  25. public int? TankNumberInFunctionCode
  26. {
  27. get
  28. {
  29. if (base.FunctionCode.Item1 == MessageFormat.Display)
  30. return null;
  31. var r = int.Parse(base.FunctionCode.Item3);
  32. return r;
  33. }
  34. }
  35. public List<InventoryData> InventoryDatas
  36. {
  37. get
  38. {
  39. // skip 10 bytes of current date and time
  40. var rawDataBody = base.DataFieldAndOptionalCheckSumAndETX.Skip(10)
  41. //and exclude tail of -> && + 4 bytes check sum + ETX <- which is total 7 bytes.
  42. .Take(base.DataFieldAndOptionalCheckSumAndETX.Count - 10 - 7);
  43. /*
  44. * TT - Tank Number (Decimal, 00=all) - 2 bytes
  45. * p - Product Code (one ASCII character [20h-7Eh]) - 1 bytes
  46. * ssss - Tank Status Bits - 4 bytes
  47. * NN - Number of eight character Data Fields to follow (Hex) - 2 bytes
  48. *
  49. * ABOVE TOTAL LEN IS 9
  50. */
  51. var datas = new List<InventoryData>();
  52. int previousTotalDataCount = 0;
  53. while (true)
  54. {
  55. var buffer = rawDataBody.Skip(previousTotalDataCount);
  56. if (buffer.Count() < 7)
  57. throw new ArgumentException("Min bytes count for describe an i201 tank report is 7, but now is " + buffer.Count());
  58. var numberOfEightCharDataFieldsValue
  59. = int.Parse(Encoding.ASCII.GetString(buffer.Skip(7).Take(2).ToArray()));
  60. if (numberOfEightCharDataFieldsValue < 1 || numberOfEightCharDataFieldsValue > 99)
  61. throw new ArgumentException("number Of Eight Char DataFields to follow must range from 1 to 99, but now is: " + numberOfEightCharDataFieldsValue);
  62. datas.Add(new InventoryData(
  63. buffer.Take(7 + 2 + 8 * numberOfEightCharDataFieldsValue).ToArray()));
  64. previousTotalDataCount += 7 + 2 + 8 * numberOfEightCharDataFieldsValue;
  65. if (previousTotalDataCount == rawDataBody.Count()) break;
  66. }
  67. return datas;
  68. }
  69. }
  70. public override string ToLogString()
  71. {
  72. if (base.FunctionCode.Item1 == MessageFormat.Display)
  73. return Encoding.ASCII.GetString(base.DataFieldAndOptionalCheckSumAndETX.ToArray());
  74. return this.GetType().Name + " Current DateTime: " + this.CurrentDateAndTime.Value.ToString("yyyy-MM-dd HH:mm")
  75. + ", TankNumber_InFunctionCode: " + this.TankNumberInFunctionCode
  76. + ", data: " + this.InventoryDatas.Select(d => d.ToFullLogString())
  77. .Aggregate((acc, n) => acc + " || " + n);
  78. }
  79. public class InventoryData
  80. {
  81. private byte[] bytes;
  82. public enum TankState
  83. {
  84. DeliveryInProgress_LSB,
  85. LeakTestInProgress,
  86. InvalidFuelHeighAlarm_MagProbesOnly,
  87. Unknown,
  88. }
  89. public enum TankReadingDataName
  90. {
  91. Volume = 1,
  92. TC_Volume = 2,
  93. Ullage = 3,
  94. Height = 4,
  95. Water = 5,
  96. Temperature = 6,
  97. WaterVolume = 7,
  98. }
  99. public InventoryData(byte[] bytes)
  100. {
  101. this.bytes = bytes;
  102. }
  103. public int? TankNumber
  104. {
  105. get
  106. {
  107. var r = int.Parse(Encoding.ASCII.GetString(this.bytes.Take(2).ToArray()));
  108. return r;
  109. }
  110. }
  111. public char? ProductCode
  112. {
  113. get
  114. {
  115. return
  116. Encoding.ASCII.GetString(
  117. this.bytes.Skip(2).Take(1).ToArray())[0];
  118. }
  119. }
  120. public List<TankState> States
  121. {
  122. get
  123. {
  124. /* 4 ascii encoded bytes,
  125. * check 16 bits to get the states
  126. * say now the raw data here is: 0x30,0x30,0x30,0x39
  127. * then target byte here is the last byte of value 9 which binary format is 0000 1001.
  128. * so is bit 0 is 1, indicates the TankState.DeliveryInProgress_LSB
  129. */
  130. var states = new List<TankState>();
  131. var tankStateBit = Util.ConvertHexBcdStrToBytes(this.bytes.Skip(3).Take(4).ToArray());
  132. if (tankStateBit.Last().GetBit(0) == 1)
  133. states.Add(TankState.DeliveryInProgress_LSB);
  134. if (tankStateBit.Last().GetBit(1) == 1)
  135. states.Add(TankState.LeakTestInProgress);
  136. if (tankStateBit.Last().GetBit(2) == 1)
  137. states.Add(TankState.InvalidFuelHeighAlarm_MagProbesOnly);
  138. return states;
  139. }
  140. }
  141. public int? NumberOfEightCharDataFieldsToFollow
  142. {
  143. get
  144. {
  145. var nn = int.Parse(Encoding.ASCII.GetString(this.bytes.Skip(7).Take(2).ToArray()));
  146. //this.QueryInTankInventoryReportDatas = new List<QueryInTankInventoryReportDataField>(nn);
  147. return nn;
  148. }
  149. }
  150. public Dictionary<TankReadingDataName, double> TankReadingDatas
  151. {
  152. get
  153. {
  154. var datas = new Dictionary<TankReadingDataName, double>();
  155. for (int i = 0; i < this.NumberOfEightCharDataFieldsToFollow.Value; i++)
  156. {
  157. var asciiEncodedBytes = Util.ConvertHexBcdStrToBytes(this.bytes.Skip(9 + 8 * i).Take(8).ToArray());
  158. var dataValue =
  159. Util.ConvertIEEEWith4BytesToDouble(asciiEncodedBytes.ToArray());
  160. switch (i + 1)
  161. {
  162. case 1: // VOLUME
  163. datas.Add(TankReadingDataName.Volume, dataValue);
  164. break;
  165. case 2: // TC VOLUME
  166. datas.Add(TankReadingDataName.TC_Volume, dataValue);
  167. break;
  168. case 3: // ULLAGE
  169. datas.Add(TankReadingDataName.Ullage, dataValue);
  170. break;
  171. case 4: // HEIGHT
  172. datas.Add(TankReadingDataName.Height, dataValue);
  173. break;
  174. case 5: // WATER HEIGHT
  175. datas.Add(TankReadingDataName.Water, dataValue);
  176. break;
  177. case 6: // TEMPERATURE
  178. datas.Add(TankReadingDataName.Temperature, dataValue);
  179. break;
  180. case 7: // WATER VOLUME
  181. datas.Add(TankReadingDataName.WaterVolume, dataValue);
  182. break;
  183. }
  184. }
  185. return datas;
  186. }
  187. }
  188. public string ToFullLogString()
  189. {
  190. return "Tank with Number: " + (this.TankNumber ?? -1) + " with ProductCode: " + (this.ProductCode ?? ' ')
  191. + " with States: " +
  192. (this.States != null && this.States.Any() ? this.States.Select(s => s.ToString()).Aggregate((acc, n) => acc + "-" + n) : "")
  193. + ", data read: "
  194. + this.TankReadingDatas.Select(s => s.Key.ToString() + "-" + s.Value).Aggregate((acc, n) => acc + " | " + n);
  195. }
  196. public string ToSimpleLogString()
  197. {
  198. return "Tank with Number: " + (this.TankNumber ?? -1) + " has ProductCode: " + (this.ProductCode ?? ' ');
  199. }
  200. }
  201. }
  202. }