MotionDebugView.xaml.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System;
  2. using System.Linq;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Controls.Primitives;
  6. using TeamAAS.Global.Devices;
  7. namespace TeamAAS.Motion
  8. {
  9. /// <summary>
  10. /// 运动/IO 通用调试页面:轴状态表 + 定位/回零/使能/停止 + IO 输出点翻转。
  11. /// 所有运动卡与 IO 卡(仿真/雷赛/固高/IMC60G/GR20T…)共用此页面(设备内核·统一调试页要求);
  12. /// 品牌特有调试能力可通过 IDeviceDebugPageFactory 提供专用页面替换本页。
  13. /// </summary>
  14. public partial class MotionDebugView : UserControl
  15. {
  16. private IMotionCard _motion;
  17. private IIOCard _io;
  18. private readonly System.Windows.Threading.DispatcherTimer _refreshTimer;
  19. public MotionDebugView()
  20. {
  21. InitializeComponent();
  22. _refreshTimer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromMilliseconds(300) };
  23. _refreshTimer.Tick += (s, e) => RefreshStatus();
  24. }
  25. /// <summary>绑定设备(运动卡或 IO 卡,二选一或同时实现)。</summary>
  26. public void Bind(object device)
  27. {
  28. _motion = device as IMotionCard;
  29. _io = device as IIOCard;
  30. TxtTitle.Text = (_motion as TeamAAS.Global.Devices.INamedDevice)?.Name
  31. ?? (_io as TeamAAS.Global.Devices.INamedDevice)?.Name
  32. ?? "运动/IO 调试";
  33. if (_motion != null)
  34. {
  35. AxisGrid.ItemsSource = _motion.GetAllAxisStatus();
  36. }
  37. else
  38. {
  39. AxisGrid.Visibility = Visibility.Collapsed;
  40. }
  41. BuildIoPanel();
  42. _refreshTimer.Start();
  43. RefreshStatus();
  44. }
  45. private IMotionCard Motion => _motion;
  46. private IIOCard Io => _io;
  47. private void BuildIoPanel()
  48. {
  49. IoPanel.Children.Clear();
  50. if (_io == null)
  51. {
  52. IoPanel.Visibility = Visibility.Collapsed;
  53. return;
  54. }
  55. IoPanel.Visibility = Visibility.Visible;
  56. for (int i = 0; i < _io.OutputCount; i++)
  57. {
  58. int index = i;
  59. var btn = new ToggleButton
  60. {
  61. Content = $"Y{index}",
  62. Width = 44,
  63. Margin = new Thickness(2),
  64. };
  65. btn.Checked += (s, e) => _io.WriteOutput(index, true);
  66. btn.Unchecked += (s, e) => _io.WriteOutput(index, false);
  67. IoPanel.Children.Add(btn);
  68. }
  69. }
  70. private void RefreshStatus()
  71. {
  72. try
  73. {
  74. if (_motion != null && _motion.IsConnected)
  75. AxisGrid.ItemsSource = _motion.GetAllAxisStatus();
  76. if (_io != null && _io.IsConnected)
  77. {
  78. var outs = _io.ReadAllOutputs();
  79. var ins = _io.ReadAllInputs();
  80. for (int i = 0; i < IoPanel.Children.Count && i < outs.Length; i++)
  81. {
  82. if (IoPanel.Children[i] is ToggleButton tb && tb.IsChecked != outs[i])
  83. {
  84. _suppressIo = true;
  85. tb.IsChecked = outs[i];
  86. _suppressIo = false;
  87. }
  88. }
  89. TxtStatus.Text = $"已连接 · 输入:{ToMask(ins)} 输出:{ToMask(outs)}";
  90. }
  91. else
  92. {
  93. TxtStatus.Text = _motion != null && _motion.IsConnected ? "已连接" : "未连接";
  94. }
  95. }
  96. catch { }
  97. }
  98. private bool _suppressIo;
  99. private static string ToMask(bool[] bits)
  100. => bits == null ? "" : new string(bits.Select(b => b ? '1' : '0').ToArray());
  101. private bool TryGetAxis(out int axis, out double vel, out double pos)
  102. {
  103. axis = 0; vel = 100; pos = 0;
  104. if (_motion == null) return false;
  105. return int.TryParse(TxtAxis.Text, out axis)
  106. && double.TryParse(TxtVel.Text, out vel)
  107. && double.TryParse(TxtPos.Text, out pos);
  108. }
  109. private void BtnOpen_Click(object sender, RoutedEventArgs e)
  110. {
  111. try
  112. {
  113. bool ok = (_motion as IConnectableDevice)?.Open()
  114. ?? (_io as IConnectableDevice)?.Open() ?? false;
  115. TxtStatus.Text = ok ? "已连接" : "连接失败";
  116. }
  117. catch (Exception ex) { TxtStatus.Text = "连接失败: " + ex.Message; }
  118. }
  119. private void BtnClose_Click(object sender, RoutedEventArgs e)
  120. {
  121. try { (_motion as IConnectableDevice)?.Close(); (_io as IConnectableDevice)?.Close(); } catch { }
  122. TxtStatus.Text = "未连接";
  123. }
  124. private void BtnMoveAbs_Click(object sender, RoutedEventArgs e)
  125. {
  126. if (TryGetAxis(out var axis, out var vel, out var pos))
  127. _motion?.MoveAbsolute(axis, pos, vel);
  128. }
  129. private void BtnEnable_Click(object sender, RoutedEventArgs e)
  130. {
  131. if (int.TryParse(TxtAxis.Text, out var axis)) _motion?.SetEnable(axis, true);
  132. }
  133. private void BtnHome_Click(object sender, RoutedEventArgs e)
  134. {
  135. if (int.TryParse(TxtAxis.Text, out var axis)) _motion?.Home(axis);
  136. }
  137. private void BtnStop_Click(object sender, RoutedEventArgs e)
  138. {
  139. _motion?.Stop(-1);
  140. }
  141. private void BtnRefresh_Click(object sender, RoutedEventArgs e) => RefreshStatus();
  142. }
  143. /// <summary>
  144. /// 运动/IO 设备通用调试页工厂:注册到设备调试页体系后,所有运动卡/IO 卡自动获得调试页面。
  145. /// </summary>
  146. public class MotionDebugPageFactory : TeamAAS.Global.Devices.IDeviceDebugPageFactory
  147. {
  148. public string DeviceCategory => "运动卡";
  149. public object CreatePage(object device)
  150. {
  151. var view = new MotionDebugView();
  152. view.Bind(device);
  153. return view;
  154. }
  155. }
  156. }