ComAgent.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using GUI.DataProvider;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.IO.Ports;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace GUI
  11. {
  12. public interface IComAgentDelegate
  13. {
  14. void ReceiveError(string msg);
  15. void ReceiveSuccess();
  16. }
  17. public class ComAgent : SerialPort, IGUIDataSource
  18. {
  19. public float Yaw { get; set; } = 0f;
  20. public float Roll { get; set; } = 0f;
  21. public float Pitch { get; set; } = 0f;
  22. public bool Q, W, E, A, S, D, L, R;
  23. public sbyte dx, dy;
  24. readonly Thread sendThread;
  25. readonly ConcurrentQueue<Action> ioTasks;
  26. public void Move(int dx, int dy)
  27. {
  28. this.dx = (sbyte)(this.dx + dx);
  29. this.dy = (sbyte)(this.dy + dy);
  30. }
  31. public void ResetMove()
  32. {
  33. dx = dy = 0;
  34. }
  35. public IComAgentDelegate agentDelegate;
  36. public ComAgent() : base()
  37. {
  38. DataReceived += receive;
  39. ioTasks = new();
  40. (sendThread = new(() =>
  41. {
  42. while (true)
  43. {
  44. try
  45. {
  46. if (ioTasks.TryDequeue(out Action act)) act();
  47. }
  48. catch (Exception e)
  49. {
  50. Console.WriteLine($"{DateTime.Now} {e.Message}");
  51. }
  52. Thread.Sleep(10);
  53. }
  54. }) { IsBackground = true }).Start();
  55. }
  56. void EnqueueDiscardableIOTask(Action task)
  57. {
  58. int discarded = 0;
  59. while (ioTasks.Count > 10)
  60. {
  61. ioTasks.TryDequeue(out Action _);
  62. discarded++;
  63. }
  64. if (discarded > 0) Console.WriteLine($"{DateTime.Now} Discard {discarded} old io job due too much jobs blocking.");
  65. ioTasks.Enqueue(task);
  66. }
  67. public void ThrowError(string reason, bool shutdown = false)
  68. {
  69. Console.WriteLine($"{DateTime.Now} Connection {(shutdown ? "breaked" : "warned")} due {reason}");
  70. if (shutdown)
  71. {
  72. agentDelegate?.ReceiveError(reason);
  73. Close();
  74. }
  75. }
  76. public new void Close()
  77. {
  78. try { base.Close(); }
  79. catch { }
  80. }
  81. public void SendFrame()
  82. {
  83. byte[] data = new byte[4];
  84. data[0] = 0x0A;
  85. data[1] = (byte)(Q.t() + W.t() * 2 + E.t() * 4 + A.t() * 8 + S.t() * 16 + D.t() * 32 + L.t() * 64 + R.t() * 128);
  86. data[2] = (byte)dx;
  87. data[3] = (byte)dy;
  88. data = data.PackData();
  89. dx = dy = 0;
  90. EnqueueDiscardableIOTask(() => Write(data, 0, data.Length));
  91. }
  92. void receive(object sender, SerialDataReceivedEventArgs e)
  93. {
  94. byte[] buff = new byte[10];
  95. int cursor = 0;
  96. while (ReadByte() != 0x0A) ;
  97. buff[cursor++] = 0x0A;
  98. while ((cursor += Read(buff, cursor, buff.Length - cursor)) < buff.Length) ;
  99. //Read(buff, 0, buff.Length);
  100. if (buff[0] != 0x0A)
  101. {
  102. ThrowError($"Expect meta 0x0A, but got {buff[0]}", true);
  103. return;
  104. }
  105. if (!buff.CheckData())
  106. {
  107. ThrowError($"Check fail, source data is {buff}");
  108. return;
  109. }
  110. ushort yaw100 = BitConverter.ToUInt16(buff, 1),
  111. roll100 = BitConverter.ToUInt16(buff, 3),
  112. pitch100 = BitConverter.ToUInt16(buff, 5);
  113. Yaw = yaw100 * 0.01f;
  114. Roll = roll100 * 0.01f;
  115. Pitch = pitch100 * 0.01f;
  116. agentDelegate?.ReceiveSuccess();
  117. }
  118. }
  119. }