| | |
| | | using HMI.Base; |
| | | using HMI.Core.Setting; |
| | | using HMI.Core.Util; |
| | | using HMI.ParameterManage.Entity; |
| | | using HMI.ParameterManage.Util; |
| | | using HMI.UI.Util; |
| | | using Plugin.ServoManage.Entity; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Collections.ObjectModel; |
| | | using System.IO; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using System.Reflection; |
| | | using System.Threading; |
| | | using System.Timers; |
| | | using System.Windows; |
| | | using System.Windows.Controls; |
| | | using System.Windows.Data; |
| | | using System.Windows.Documents; |
| | | using System.Windows.Input; |
| | | using System.Windows.Media; |
| | | using System.Windows.Media.Imaging; |
| | | using System.Windows.Navigation; |
| | | using System.Windows.Shapes; |
| | | |
| | | namespace Plugin.ServoManage |
| | | { |
| | | [AttributeUsage(AttributeTargets.Property)] |
| | | public class IsStatusAttribute : Attribute |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// UserControl1.xaml 的交互逻辑 |
| | | /// </summary> |
| | | public partial class ServoManage: UserControl |
| | | public partial class ServoManage : PluginControl |
| | | { |
| | | public static string FilePath { get; private set; } |
| | | public static string ProductFilePath { get; private set; } |
| | | |
| | | private ObservableCollection<ServoData> servos; |
| | | public ObservableCollection<ServoData> Servos |
| | | { |
| | | get => servos; |
| | | set |
| | | { |
| | | Set(ref servos, value); |
| | | } |
| | | } |
| | | |
| | | private ServoData selectedServo; |
| | | public ServoData SelectedServo |
| | | { |
| | | get => selectedServo; |
| | | set |
| | | { |
| | | Set(ref selectedServo, value); |
| | | Set("HasSelectedServo"); |
| | | RefreshServoStatus(); |
| | | } |
| | | } |
| | | |
| | | public bool HasSelectedServo |
| | | { |
| | | get => SelectedServo != null; |
| | | } |
| | | |
| | | private string selectedProduct; |
| | | [IsStatus] |
| | | public string SelectedProduct |
| | | { |
| | | get => selectedProduct; |
| | | set |
| | | { |
| | | if (value != selectedProduct) |
| | | { |
| | | Set(ref selectedProduct, value); |
| | | if (SelectedServo != null) |
| | | { |
| | | SetBitValue($"{SelectedServo.Name}_sRecipeCode", value); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private ObservableCollection<ServoProductData> servoProducts; |
| | | public ObservableCollection<ServoProductData> ServoProducts |
| | | { |
| | | get => servoProducts; |
| | | set |
| | | { |
| | | Set(ref servoProducts, value); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 实例化服务器接口函数 |
| | | /// </summary> |
| | | private OpcInterface.OpcInterface lTSCADAApi = new OpcInterface.OpcInterface(); |
| | | private bool isActived = false; |
| | | private System.Timers.Timer motorMonitorTimer; |
| | | |
| | | private string enable; |
| | | [IsStatus] |
| | | public string Enable |
| | | { |
| | | get => enable; |
| | | set |
| | | { |
| | | Set(ref enable, value); |
| | | } |
| | | } |
| | | |
| | | private string currentPosition; |
| | | [IsStatus] |
| | | public string CurrentPosition |
| | | { |
| | | get => $"{currentPosition}{SelectedServo?.Unit}"; |
| | | set |
| | | { |
| | | Set(ref currentPosition, value); |
| | | } |
| | | } |
| | | |
| | | private string currentSpeed; |
| | | [IsStatus] |
| | | public string CurrentSpeed |
| | | { |
| | | get => $"{currentSpeed}{SelectedServo?.Unit}/s"; |
| | | set |
| | | { |
| | | Set(ref currentSpeed, value); |
| | | } |
| | | } |
| | | |
| | | private string overAcc; |
| | | [IsStatus] |
| | | public string OverAcc |
| | | { |
| | | get => $"{overAcc}{SelectedServo?.Unit}/s²"; |
| | | set |
| | | { |
| | | Set(ref overAcc, value); |
| | | } |
| | | } |
| | | |
| | | private string overDec; |
| | | [IsStatus] |
| | | public string OverDec |
| | | { |
| | | get => $"{overDec}{SelectedServo?.Unit}/s²"; |
| | | set |
| | | { |
| | | Set(ref overDec, value); |
| | | } |
| | | } |
| | | |
| | | private string hmiPosition; |
| | | [IsStatus] |
| | | public string HMIPosition |
| | | { |
| | | get => $"{hmiPosition}{SelectedServo?.Unit}"; |
| | | set |
| | | { |
| | | Set(ref hmiPosition, value); |
| | | } |
| | | } |
| | | |
| | | private string hmiSpeed; |
| | | [IsStatus] |
| | | public string HMISpeed |
| | | { |
| | | get => $"{hmiSpeed}{SelectedServo?.Unit}/s"; |
| | | set |
| | | { |
| | | Set(ref hmiSpeed, value); |
| | | } |
| | | } |
| | | |
| | | private string jogVelocity; |
| | | [IsStatus] |
| | | public string JogVelocity |
| | | { |
| | | get => $"{jogVelocity}%"; |
| | | set |
| | | { |
| | | Set(ref jogVelocity, value); |
| | | } |
| | | } |
| | | |
| | | private string inchDistance; |
| | | [IsStatus] |
| | | public string InchDistance |
| | | { |
| | | get => $"{inchDistance}{SelectedServo?.Unit}"; |
| | | set |
| | | { |
| | | Set(ref inchDistance, value); |
| | | } |
| | | } |
| | | |
| | | private string dir; |
| | | [IsStatus] |
| | | public string Dir |
| | | { |
| | | get => dir; |
| | | set |
| | | { |
| | | Set(ref dir, value); |
| | | } |
| | | } |
| | | |
| | | private string alarmCode = "0"; |
| | | [IsStatus] |
| | | public string AlarmCode |
| | | { |
| | | get => alarmCode; |
| | | set |
| | | { |
| | | Set(ref alarmCode, value); |
| | | } |
| | | } |
| | | |
| | | private string warnCode = "0"; |
| | | [IsStatus] |
| | | public string WarnCode |
| | | { |
| | | get => warnCode; |
| | | set |
| | | { |
| | | Set(ref warnCode, value); |
| | | } |
| | | } |
| | | |
| | | private string faultCode = "0"; |
| | | [IsStatus] |
| | | public string FaultCode |
| | | { |
| | | get => faultCode; |
| | | set |
| | | { |
| | | Set(ref faultCode, value); |
| | | } |
| | | } |
| | | |
| | | private string positiveLimit; |
| | | [IsStatus] |
| | | public string PositiveLimit |
| | | { |
| | | get => positiveLimit; |
| | | set |
| | | { |
| | | Set(ref positiveLimit, value); |
| | | } |
| | | } |
| | | |
| | | private string homeSwitch; |
| | | [IsStatus] |
| | | public string HomeSwitch |
| | | { |
| | | get => homeSwitch; |
| | | set |
| | | { |
| | | Set(ref homeSwitch, value); |
| | | } |
| | | } |
| | | |
| | | private string negativeLimit; |
| | | [IsStatus] |
| | | public string NegativeLimit |
| | | { |
| | | get => negativeLimit; |
| | | set |
| | | { |
| | | Set(ref negativeLimit, value); |
| | | } |
| | | } |
| | | |
| | | private string axisEnabled; |
| | | [IsStatus] |
| | | public string AxisEnabled |
| | | { |
| | | get => axisEnabled; |
| | | set |
| | | { |
| | | Set(ref axisEnabled, value); |
| | | } |
| | | } |
| | | |
| | | private string readyOK; |
| | | [IsStatus] |
| | | public string ReadyOK |
| | | { |
| | | get => readyOK; |
| | | set |
| | | { |
| | | Set(ref readyOK, value); |
| | | } |
| | | } |
| | | |
| | | private string running; |
| | | [IsStatus] |
| | | public string Running |
| | | { |
| | | get => running; |
| | | set |
| | | { |
| | | Set(ref running, value); |
| | | } |
| | | } |
| | | |
| | | private string homed; |
| | | [IsStatus] |
| | | public string Homed |
| | | { |
| | | get => homed; |
| | | set |
| | | { |
| | | Set(ref homed, value); |
| | | } |
| | | } |
| | | |
| | | private string axisError; |
| | | [IsStatus] |
| | | public string AxisError |
| | | { |
| | | get => axisError; |
| | | set |
| | | { |
| | | Set(ref axisError, value); |
| | | } |
| | | } |
| | | |
| | | private string axisWarn; |
| | | [IsStatus] |
| | | public string AxisWarn |
| | | { |
| | | get => axisWarn; |
| | | set |
| | | { |
| | | Set(ref axisWarn, value); |
| | | } |
| | | } |
| | | |
| | | private string posCode = "0"; |
| | | [IsStatus] |
| | | public string PosCode |
| | | { |
| | | get => posCode; |
| | | set |
| | | { |
| | | Set(ref posCode, value); |
| | | } |
| | | } |
| | | |
| | | public ServoManage() |
| | | { |
| | | DataContext = this; |
| | | motorMonitorTimer = new System.Timers.Timer(); |
| | | motorMonitorTimer.Elapsed += MotorMonitorTimer_Elapsed; |
| | | InitializeComponent(); |
| | | } |
| | | |
| | | private void MotorMonitorTimer_Elapsed(object sender, ElapsedEventArgs e) |
| | | { |
| | | this.motorMonitorTimer.Enabled = false; |
| | | try |
| | | { |
| | | RefreshServoStatus(); |
| | | this.motorMonitorTimer.Enabled = true; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | this.motorMonitorTimer.Enabled = true; |
| | | return; |
| | | } |
| | | } |
| | | |
| | | public override void SetBaseFolder(string folder) |
| | | { |
| | | FilePath = Path.Combine(folder, "Servo.data"); |
| | | ProductFilePath = Path.Combine(folder, "ServoProduct.data"); |
| | | base.SetBaseFolder(folder); |
| | | } |
| | | |
| | | public override void Active() |
| | | { |
| | | base.Active(); |
| | | if (!isActived) |
| | | { |
| | | try |
| | | { |
| | | if (SystemSetting.Instance.PlcEnabled) |
| | | { |
| | | if (lTSCADAApi.Connect2("127.0.0.1", 6543, 18888, out string errMsg)) |
| | | { |
| | | this.motorMonitorTimer.Interval = 100; |
| | | this.motorMonitorTimer.Start(); |
| | | isActived = true; |
| | | } |
| | | else |
| | | { |
| | | MsgBoxHelper2.Error(errMsg); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | |
| | | isActived = true; |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error("Active Failed.", ex); |
| | | MsgBoxHelper2.Error(ex.Message); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void UserControl_Loaded(object sender, RoutedEventArgs e) |
| | | { |
| | | |
| | | LoadData(); |
| | | LoadProductData(); |
| | | this.Loaded -= UserControl_Loaded; |
| | | } |
| | | |
| | | private void Button_Click(object sender, RoutedEventArgs e) |
| | | { |
| | | Button btn = sender as Button; |
| | | ServoData data = btn.DataContext as ServoData; |
| | | switch (btn.Name) |
| | | { |
| | | case "addServoBtn": |
| | | OpenServoModal(null); |
| | | break; |
| | | case "editServoBtn": |
| | | OpenServoModal(data); |
| | | break; |
| | | case "delServoBtn": |
| | | TryDeleteServo(data); |
| | | break; |
| | | case "rfhServoBtn": |
| | | LoadData(); |
| | | break; |
| | | |
| | | case "addProductBtn": |
| | | OpenProductModal(null); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | #region Servo |
| | | private void LoadData() |
| | | { |
| | | try |
| | | { |
| | | ObservableCollection<ServoData> data = new ObservableCollection<ServoData>(); |
| | | if (File.Exists(FilePath)) |
| | | { |
| | | data = XmlHelper.DeserializeFromXml<ObservableCollection<ServoData>>(FilePath); |
| | | } |
| | | Servos = data; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error("Load Servo Data Failed.", ex); |
| | | ToastHelper.Error(this.lang("App.LoadFailed")); |
| | | } |
| | | } |
| | | |
| | | private void OpenServoModal(ServoData data) |
| | | { |
| | | bool isUpdate = data != null; |
| | | try |
| | | { |
| | | |
| | | ServoModal modal = new ServoModal |
| | | { |
| | | Title = isUpdate ? this.lang("App.Edit") : this.lang("App.Add"), |
| | | Owner = Window.GetWindow(this) |
| | | }; |
| | | if (modal.Open(data ?? new ServoData(), Servos) == true) |
| | | { |
| | | LoadData(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error($"Add Or Edit Data Failed.", ex); |
| | | var title = isUpdate ? this.lang("App.EditFailed") : this.lang("App.AddFailed"); |
| | | MsgBoxHelper2.Error($"{title}: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | private void TryDeleteServo(ServoData data) |
| | | { |
| | | try |
| | | { |
| | | if (MsgBoxHelper2.WarnChoose(this.lang("HMI.MakeSureDeleteSingle", data.Name)) == MessageBoxResult.OK) |
| | | { |
| | | int index = Servos.IndexOf(data); |
| | | if (index > 0) |
| | | { |
| | | var temp = XmlHelper.DeepClone(Servos); |
| | | temp.RemoveAt(index); |
| | | XmlHelper.SerializeToXml(FilePath, temp); |
| | | } |
| | | LoadData(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error($"Delete Servo Failed.", ex); |
| | | MsgBoxHelper2.Error($"{this.lang("App.DeleteFailed")}: {ex.Message}"); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region product |
| | | public ObservableCollection<ServoProductData> ReadCommonProducts() |
| | | { |
| | | ObservableCollection<ServoProductData> datas = new ObservableCollection<ServoProductData>(); |
| | | List<ProductData> products = ParameterManager.GetProducts<List<ProductData>>(); |
| | | if (products != null && products.Count > 0) |
| | | { |
| | | foreach (var product in products) |
| | | { |
| | | var parameter = ParameterManager.GetParametersByProductName(product.Name) |
| | | ?.FirstOrDefault(p => p.Name == "ProgramCode"); |
| | | if (parameter != null) |
| | | { |
| | | datas.Add(new ServoProductData |
| | | { |
| | | Model = product.Name, |
| | | ProgramCode = parameter.Value, |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | return datas; |
| | | } |
| | | |
| | | private void LoadProductData() |
| | | { |
| | | try |
| | | { |
| | | //ObservableCollection<ServoProductData> datas = new ObservableCollection<ServoProductData>(); |
| | | //if (File.Exists(FilePath)) |
| | | //{ |
| | | // datas = XmlHelper.DeserializeFromXml<ObservableCollection<ServoProductData>>(ProductFilePath); |
| | | //} |
| | | ServoProducts = ReadCommonProducts(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error("Load Servo Product Data Failed.", ex); |
| | | ToastHelper.Error(this.lang("App.LoadFailed")); |
| | | } |
| | | } |
| | | |
| | | private void OpenProductModal(ServoProductData data) |
| | | { |
| | | bool isUpdate = data != null; |
| | | try |
| | | { |
| | | |
| | | ServoProductModal modal = new ServoProductModal |
| | | { |
| | | Title = isUpdate ? this.lang("App.Edit") : this.lang("App.Add"), |
| | | Owner = Window.GetWindow(this) |
| | | }; |
| | | if (modal.Open(data ?? new ServoProductData(), ServoProducts) == true) |
| | | { |
| | | LoadProductData(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error($"Add Or Edit Product Data Failed.", ex); |
| | | var title = isUpdate ? this.lang("App.EditFailed") : this.lang("App.AddFailed"); |
| | | MsgBoxHelper2.Error($"{title}: {ex.Message}"); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | private void RefreshServoStatus() |
| | | { |
| | | Dispatcher.Invoke(() => |
| | | { |
| | | if (SelectedServo == null) return; |
| | | PropertyInfo[] properties = this.GetType().GetProperties(); |
| | | foreach (var prop in properties) |
| | | { |
| | | if (!Attribute.IsDefined(prop, typeof(IsStatusAttribute))) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (prop.Name == "SelectedProduct") |
| | | { |
| | | var data = GetBitValue($"{SelectedServo.Name}_sRecipeCode"); |
| | | SelectedProduct = data; |
| | | } |
| | | else |
| | | { |
| | | var data = GetBitValue($"{SelectedServo.Name}_{prop.Name}"); |
| | | prop.SetValue(this, data); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置DB地址bool值 |
| | | /// </summary> |
| | | /// <param name="subbuttonX">子按钮</param> |
| | | /// <param name="address">地址</param> |
| | | /// <param name="bol">值</param> |
| | | private void SetBitValue(string tag, string val) |
| | | { |
| | | if (!lTSCADAApi.DoFctWriteSingle(tag, val, out string errMsg)) |
| | | { |
| | | log.Error($"Set Bit Value Failed.{errMsg}"); |
| | | MsgBoxHelper2.Error(errMsg); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 通过当前标签读取值 |
| | | /// </summary> |
| | | /// <param name="tag">标签</param> |
| | | /// <returns>返回值</returns> |
| | | private string GetBitValue(string tag) |
| | | { |
| | | if (lTSCADAApi.DoFctReadSingle(tag, out string res, out string err)) |
| | | { |
| | | return res; |
| | | } |
| | | else |
| | | { |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | private void Servo_Click(object sender, RoutedEventArgs e) |
| | | { |
| | | if (SelectedServo == null) |
| | | { |
| | | ToastHelper.Warning(this.lang("svo.selectAServo")); |
| | | return; |
| | | } |
| | | Button btn = sender as Button; |
| | | try |
| | | { |
| | | motorMonitorTimer.Enabled = false; |
| | | switch (btn.Tag) |
| | | { |
| | | case "Enable": |
| | | EnableDoClick(btn.Tag.ToString()); |
| | | break; |
| | | case "Dir": |
| | | EnableDoClick(btn.Tag.ToString()); |
| | | break; |
| | | default: |
| | | DoSignClick(btn.Tag?.ToString()); |
| | | break; |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error($"Servo Opt Failed, BtnName is {btn.Name}", ex); |
| | | MsgBoxHelper2.Error(ex.Message); |
| | | } |
| | | finally |
| | | { |
| | | motorMonitorTimer.Enabled = true; |
| | | } |
| | | } |
| | | |
| | | private void DoSignClick(string tag) |
| | | { |
| | | if (!string.IsNullOrEmpty(tag)) |
| | | { |
| | | SetBitValue($"{SelectedServo?.Name}_{tag}", "true"); |
| | | Thread.Sleep(50); |
| | | SetBitValue($"{SelectedServo?.Name}_{tag}", "false"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 使能/断使能 按钮 |
| | | /// </summary> |
| | | /// <param name="btnName"></param> |
| | | private void EnableDoClick(string btnName) |
| | | { |
| | | bool val = GetBitValue($"{SelectedServo?.Name}_{btnName}") == "1"; |
| | | SetBitValue($"{SelectedServo?.Name}_{btnName}", $"{(!val ? 1 : 0)}"); |
| | | } |
| | | |
| | | private void Label_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) |
| | | { |
| | | if (SelectedServo == null) |
| | | { |
| | | ToastHelper.Warning(this.lang("svo.selectAServo")); |
| | | return; |
| | | } |
| | | Label label = sender as Label; |
| | | var tag = label.Tag.ToString(); |
| | | NumberPanel np = new NumberPanel() |
| | | { |
| | | Title = this.lang($"svo.{tag}"), |
| | | Owner = Window.GetWindow(this) |
| | | }; |
| | | string value = label.Content.ToString(); |
| | | if (value.Contains("%")) |
| | | { |
| | | value = value.Replace("%", ""); |
| | | } |
| | | else if (SelectedServo != null) |
| | | { |
| | | value = value.Split(new string[] { SelectedServo.Unit }, StringSplitOptions.None)[0]; |
| | | } |
| | | if (np.Open(value) == true) |
| | | { |
| | | SetBitValue($"{SelectedServo?.Name}_{tag}", np.Data?.ToString()); |
| | | } |
| | | } |
| | | } |
| | | } |