using Hik.Api; using Newtonsoft.Json.Linq; using S7.Net; using System.Threading.Channels; using System.Windows.Forms; namespace xicheji { public partial class MainForm : Form { private readonly Config config; private readonly List washRecords = new(); private DateTime lastReceiveTime = DateTime.MinValue; private byte[] currentDataBlock; private Plc? plc = null; private HikApi? hikApi = null; public MainForm() { InitializeComponent(); config = ConfigHelper.GetConfig(); } private void MainForm_Load(object sender, EventArgs e) { try { //测试数据 washRecords.Add(new WashRecord() { CarNum = "京123456", StartTime = new DateTime(2024, 6, 1, 12, 00, 00), EndTime = new DateTime(2024, 6, 1, 12, 30, 00), WashTime = 15, DryTime = 15, TotalElectricity = 10, TotalWater = 2, WaterPressure = 6, }); dataGridView1.DataSource = washRecords; ConnectPLC(); //ConnectCamera(); receivePLCTimer.Interval = config.PLCReceiveInterval * 1000; receivePLCTimer.Enabled = true; uploadTimer.Enabled = true; } catch (Exception ex) { MessageBox.Show(ex.Message + ex.StackTrace); } } private void btnConnectCamera_Click(object sender, EventArgs e) { try { ConnectCamera(); } catch (Exception ex) { MessageBox.Show(ex.Message + ex.StackTrace); } } private void nowTimer_Tick(object sender, EventArgs e) { try { var now = DateTime.Now; lblTime.Text = $"{now.Month}月 {now.Day}日 {now.Hour}:{now:mm}:{now:ss}"; } catch { } } private void receivePLCTimer_Tick(object sender, EventArgs e) { try { if (plc == null || !plc.IsConnected) { receivePLCTimer.Enabled = false; return; } ReadPLCData(); } catch (Exception ex) { MessageBox.Show(ex.Message + ex.StackTrace); } } private void ReadPLCData() { currentDataBlock = plc!.ReadBytes(DataType.DataBlock, 1, 0, 100); var time = new DateTime( DateTime.Now.Year, ReadPLCInt("当前月"), ReadPLCInt("当前日"), ReadPLCInt("当前时"), ReadPLCInt("当前分"), ReadPLCInt("当前秒")); if (time <= lastReceiveTime) { //已经读过这个时间的了 return; } lastReceiveTime = time; ReadError(); ReadStatus(); lblWashCount.Text = ReadPLCString("洗车次数"); lblTotalWater.Text = ReadPLCString("累计用水量"); lblTotalElectricity.Text = ReadPLCString("累计用电量"); //.Text = ReadPLCStringValue("当前流量"); lblCurrentElectricity.Text = ReadPLCString("当前功率"); lblCurrentWaterP.Text = ReadPLCString("当前压力"); } private void ReadStatus() { lblStatus.Text = string.Empty; var statuses = new List() { "洗车中", "清洗中", "沥水中", "出车中", "风干中"}; foreach (var status in statuses) { if (ReadPLCBool(status)) { lblStatus.Text = status; break; } } } private void ReadError() { lblError.Text = string.Empty; var errors = new List() { "急停", "冲洗泵故障", "反洗泵故障", "清淤泵故障", "伴热故障", "风刀故障" }; foreach (var error in errors) { if (ReadPLCBool(error)) { lblError.Text = error; break; } } } private string ReadPLCString(string name) { var variable = ConfigHelper.FindVariable(name); if (variable == null) return string.Empty; Parse(variable.Key, out _, out _, out var varType, out var address, out var bitNumber); if (varType == VarType.DWord) { var value = S7.Net.Types.DWord.FromByteArray(currentDataBlock.Take(new Range(address, address + 4)).ToArray()); return $"{value} {variable.Desc}"; } else if (varType == VarType.Word) { var value = S7.Net.Types.Word.FromByteArray(currentDataBlock.Take(new Range(address, address + 2)).ToArray()); return $"{value} {variable.Desc}"; } return string.Empty; } private int ReadPLCInt(string name) { var variable = ConfigHelper.FindVariable(name); if (variable == null) return 0; Parse(variable.Key, out var dataType, out var dbNumber, out var varType, out var address, out var bitNumber); if (varType == VarType.DWord) { var value = S7.Net.Types.DWord.FromByteArray(currentDataBlock.Take(new Range(address, address + 4)).ToArray()); return (int)value; } else if (varType == VarType.Word) { var value = S7.Net.Types.Word.FromByteArray(currentDataBlock.Take(new Range(address, address + 2)).ToArray()); return value; } return 0; } private bool ReadPLCBool(string name) { var variable = ConfigHelper.FindVariable(name); if (variable == null) return false; Parse(variable.Key, out _, out _, out _, out var address, out var bitNumber); var value = S7.Net.Types.Boolean.GetValue(currentDataBlock[address], bitNumber); return value; } private void uploadTimer_Tick(object sender, EventArgs e) { } private void btnSetting_Click(object sender, EventArgs e) { try { var settingForm = new SettingForm(); if (settingForm.ShowDialog() == DialogResult.OK) { ConnectPLC(); ConnectCamera(); receivePLCTimer.Enabled = true; uploadTimer.Enabled = true; } } catch { } } private void ConnectPLC() { plc = new Plc(config.PLCType, config.PLCIP, int.Parse(config.PLCPort), 0, 1); plc.Open(); if (!plc.IsConnected) { MessageBox.Show("PLC连接失败!"); return; } } private void ConnectCamera() { try { hikApi = HikApi.Login(config.CameraIP, int.Parse(config.CameraPort), config.CameraUserName, config.CameraPassword) as HikApi; if (hikApi == null || !hikApi.Connected) { MessageBox.Show("摄像头连接失败!"); return; } hikApi.PlaybackService.StartPlayBack(hikApi.DefaultIpChannel, pictureBox1.Handle); } catch (Exception ex) { MessageBox.Show(ex.Message + ex.StackTrace); } } public void UpdateCarInfo(DateTime now) { this.Invoke(() => { this.Text = now.ToString(); }); } public static void Parse(string input, out DataType dataType, out int dbNumber, out VarType varType, out int address, out int bitNumber) { bitNumber = -1; dbNumber = 0; switch (input.Substring(0, 2)) { case "DB": string[] strings = input.Split(new char[] { '.' }); if (strings.Length < 2) throw new InvalidAddressException("To few periods for DB address"); dataType = DataType.DataBlock; dbNumber = int.Parse(strings[0].Substring(2)); address = int.Parse(strings[1].Substring(3)); string dbType = strings[1].Substring(0, 3); switch (dbType) { case "DBB": varType = VarType.Byte; return; case "DBW": varType = VarType.Word; return; case "DBD": varType = VarType.DWord; return; case "DBX": bitNumber = int.Parse(strings[2]); if (bitNumber > 7) throw new InvalidAddressException("Bit can only be 0-7"); varType = VarType.Bit; return; default: throw new InvalidAddressException(); } case "IB": case "EB": // Input byte dataType = DataType.Input; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.Byte; return; case "IW": case "EW": // Input word dataType = DataType.Input; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.Word; return; case "ID": case "ED": // Input double-word dataType = DataType.Input; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.DWord; return; case "QB": case "AB": case "OB": // Output byte dataType = DataType.Output; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.Byte; return; case "QW": case "AW": case "OW": // Output word dataType = DataType.Output; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.Word; return; case "QD": case "AD": case "OD": // Output double-word dataType = DataType.Output; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.DWord; return; case "MB": // Memory byte dataType = DataType.Memory; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.Byte; return; case "MW": // Memory word dataType = DataType.Memory; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.Word; return; case "MD": // Memory double-word dataType = DataType.Memory; dbNumber = 0; address = int.Parse(input.Substring(2)); varType = VarType.DWord; return; default: switch (input.Substring(0, 1)) { case "E": case "I": // Input dataType = DataType.Input; varType = VarType.Bit; break; case "Q": case "A": case "O": // Output dataType = DataType.Output; varType = VarType.Bit; break; case "M": // Memory dataType = DataType.Memory; varType = VarType.Bit; break; case "T": // Timer dataType = DataType.Timer; dbNumber = 0; address = int.Parse(input.Substring(1)); varType = VarType.Timer; return; case "Z": case "C": // Counter dataType = DataType.Counter; dbNumber = 0; address = int.Parse(input.Substring(1)); varType = VarType.Counter; return; default: throw new InvalidAddressException(string.Format("{0} is not a valid address", input.Substring(0, 1))); } string txt2 = input.Substring(1); if (txt2.IndexOf(".") == -1) throw new InvalidAddressException("To few periods for DB address"); address = int.Parse(txt2.Substring(0, txt2.IndexOf("."))); bitNumber = int.Parse(txt2.Substring(txt2.IndexOf(".") + 1)); if (bitNumber > 7) throw new InvalidAddressException("Bit can only be 0-7"); return; } } } }