using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Threading; using System.Threading.Tasks; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Communications; namespace EFEM.RT.Devices { public class Ffu : BaseDevice, IDevice, IConnection { private static SerialPort _port; private readonly object _locker = new object(); public Ffu(string module, string name, string station, string port) : base(module, name, name, "") { _port = new SerialPort { PortName = port, BaudRate = 9600, DataBits = 8, Parity = Parity.None, StopBits = StopBits.One, RtsEnable = false, DtrEnable = false, ReadTimeout = 1000, WriteTimeout = 1000, NewLine = "\r", Handshake = Handshake.None }; _port.DataReceived += OnDataChanged; _port.ErrorReceived += OnErrorHandler; Initalized = false; Station = station; Address = port; } public static bool SpeedSet1 { get; private set; } public static bool SpeedSet2 { get; private set; } public string Station { get; } public bool Initalized { get; set; } public string Address { get; } public bool IsConnected => _port.IsOpen; public bool Connect() { Task.Factory.StartNew(() => { var count = SC.ContainsItem("System.ComPortRetryCount") ? SC.GetValue("System.ComPortRetryCount") : 3; var sleep = SC.ContainsItem("System.ComPortRetryDelayTime") ? SC.GetValue("System.ComPortRetryDelayTime") : 2; if (sleep <= 0 || sleep > 10) sleep = 2; var retry = 0; do { if (Open()) { EV.PostInfoLog(Module, $"Connected with {Module}.{Name} ."); break; } if (count > 0 && retry++ > count) { LOG.Write($"Retry connect {Module}.{Name} stop retry."); EV.PostAlarmLog(Module, $"Can't connect to {Module}.{Name}."); break; } { Thread.Sleep(sleep * 1000); LOG.Write($"Retry connect {Module}.{Name} for the {retry + 1} time."); } } while (true); }); return true; } public bool Disconnect() { return true; } public bool Initialize() { ConnectionManager.Instance.Subscribe($"{Name}", this); Connect(); RegisterOperation(); return true; } public void Monitor() { } public void Terminate() { Close(); } public void Reset() { } private void OnDataChanged(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs) { try { lock (_locker) { if (_port.IsOpen) { var str = _port.ReadExisting(); //字符串方式读 var send = str.Split(' '); switch (send[1]) { case "03": if (send.Length > 14) if (CheckCrc(send)) { var numStr = string.Join("", send.Skip(9).Take(2).ToArray()); var num = Convert.ToInt32(numStr, 16); EV.PostInfoLog(Module, $"{Name} speed query result: {num}"); } break; case "10": if (CheckCrc(send)) { switch (send[0]) { case "01": EV.PostInfoLog(Module, "FFU1 : Command had been executed."); SpeedSet1 = true; break; case "02": EV.PostInfoLog(Module, "FFU2 : Command had been executed."); SpeedSet2 = true; break; } } break; } LOG.Info($"Communication {_port.PortName} Receive {str}."); } } } catch (Exception ex) { LOG.Write($" {Name} has exception:" + ex.Message); } } private void OnErrorHandler(object sender, SerialErrorReceivedEventArgs serialErrorReceivedEventArgs) { Initalized = false; EV.PostAlarmLog(Module, $"{Display} Communication error, {serialErrorReceivedEventArgs}"); } private void RegisterOperation() { OP.Subscribe($"{Name}.SetSpeed", (cmd, param) => { if (!int.TryParse((string) param[0], out var speed)) { EV.PostWarningLog(Module, "invalid speed."); return false; } StartAndSetSpeed(speed); EV.PostInfoLog(Module, $"{Name} speed set to {speed}"); return true; }); OP.Subscribe($"{Name}.CheckSpeed", (cmd, param) => { QuerySpeed(); EV.PostInfoLog(Module, $"Query {Name} speed"); return true; }); } public void StartAndSetSpeed(int speed) { lock (_locker) { switch (Station) { case "01": SpeedSet1 = false; break; case "02": SpeedSet2 = false; break; } var commandList = new List { Station, "10", "00", "01", "00", "02", "04", "00", "09" }; commandList.AddRange(ParseSpeed(speed)); var command = commandList.ToArray(); var add = ModRTU_CRC(command); _port.Write(string.Join(" ", command) + " " + string.Join(" ", add) + "\r"); } } public void QuerySpeed() { lock (_locker) { var commandList = new List { Station, "03", "00", "20", "00", "05" }; var command = commandList.ToArray(); var add = ModRTU_CRC(command); _port.Write(string.Join(" ", command) + " " + string.Join(" ", add) + "\r"); } } public static string[] ParseSpeed(int speed) { var x = BitConverter.GetBytes(speed); var c = new string[2]; c[0] = x[1].ToString("X").Length < 2 ? $"0{x[1]:X}" : $"{x[1]:X}"; c[1] = x[0].ToString("X").Length < 2 ? $"0{x[0]:X}" : $"{x[0]:X}"; return c; } private bool Open() { lock (_locker) { if (_port.IsOpen) Close(); try { _port.Open(); _port.DiscardInBuffer(); _port.DiscardOutBuffer(); } catch (Exception e) { // LOG.Write($"Port open failed, {e.Message}"); var reason = _port.PortName + " port open failed,please check configuration。" + e.Message; //OnErrorHappened(new ErrorEventArgs(reason)); LOG.Write(reason); return false; } } return true; } private bool Close() { lock (_locker) { if (_port.IsOpen) try { _port.Close(); } catch (Exception e) { var reason = _port.PortName + " port close failed。" + e.Message; EV.PostInfoLog(Module, reason); return false; } } return true; } private static bool CheckCrc(string[] buffer) { return string.Join("", ModRTU_CRC(buffer.Take(buffer.Length - 2).ToArray())) == string.Join("", buffer.Skip(buffer.Length - 2).ToArray()); } private static string[] ModRTU_CRC(string[] buffer) { ushort crc = 0xFFFF; // var buf = System.Text.Encoding.UTF8.GetBytes(String.Join(Environment.NewLine, buffer)); var buf = Array.ConvertAll(buffer.ToArray(), input => Convert.ToByte(input, 16)); var len = buffer.Length; for (var pos = 0; pos < len; pos++) { crc ^= buf[pos]; // XOR byte into least sig. byte of crc for (var i = 8; i != 0; i--) // Loop over each bit if ((crc & 0x0001) != 0) { // If the LSB is set crc >>= 1; // Shift right and XOR 0xA001 crc ^= 0xA001; } else // Else LSB is not set { crc >>= 1; // Just shift right } } // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes) var array = BitConverter.GetBytes(crc); var retArray = new string[array.Length]; for (var i = 0; i < retArray.Length; i++) retArray[i] = array[i].ToString("X").Length < 2 ? $"0{array[i]:X}" : array[i].ToString("X"); return retArray; } } }