using System; using System.IO.Ports; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; namespace MECF.Framework.Common.Communications { public abstract class SerialPortConnectionBase : IConnection { public string Address { get { return _address; } } public bool IsConnected { get { return _port.IsOpen(); } } public bool Connect() { return _port.Open(); } public bool Disconnect() { _port.Close(); return true; } public bool IsBusy { get { return _activeHandler != null; } } public bool IsCommunicationError { get; private set; } public string LastCommunicationError { get; private set; } private AsyncSerialPort _port; protected HandlerBase _activeHandler; //set, control, private object _lockerActiveHandler = new object(); private string _address; private bool _isAsciiMode; public SerialPortConnectionBase(string port, int baudRate=9600, int dataBits=8, Parity parity = Parity.None, StopBits stopBits = StopBits.One, string newline = "\r", bool isAsciiMode = true) { _address = port; _isAsciiMode = isAsciiMode; _port = new AsyncSerialPort(port, baudRate, dataBits, parity, stopBits, newline, isAsciiMode); _port.OnDataChanged += _port_OnAsciiDataReceived; _port.OnBinaryDataChanged += _port_OnBinaryDataChanged; _port.OnErrorHappened += _port_OnErrorHappened; } public void SetPortAddress(string portName) { _port.PortName = portName; } private void _port_OnErrorHappened(string obj) { //LOG.Error(obj); } public virtual bool SendMessage(string message) { if (_port != null && _port.IsOpen()) return _port.Write(message); //LOG.Error($"No connection writing message {message}"); return false; } public virtual bool SendMessage(byte[] message) { if (_port != null && _port.IsOpen()) return _port.Write(message); //LOG.Error($"No connection writing message {string.Join(" ", Array.ConvertAll(message, x => x.ToString("X2")))}"); return false; } public void Execute(HandlerBase handler) { if (_activeHandler != null) return; if (handler == null) return; if (_port.IsOpen()) { lock (_lockerActiveHandler) { _activeHandler = handler; _activeHandler.SetState(EnumHandlerState.Sent); } bool sendResult = _isAsciiMode ? SendMessage(handler.SendText) : SendMessage(handler.SendBinary); if (!sendResult) { lock (_lockerActiveHandler) { _activeHandler = null; } } } } protected virtual MessageBase ParseResponse(string rawMessage) { return null; } protected virtual MessageBase ParseResponse(byte[] rawMessage) { return null; } protected virtual void OnEventArrived(MessageBase msg) { } protected virtual void ActiveHandlerProceedMessage(MessageBase msg) { lock (_lockerActiveHandler) { if (_activeHandler != null) { if (msg.IsFormatError || (_activeHandler.HandleMessage(msg, out bool transactionComplete) && transactionComplete)) { _activeHandler = null; } } } } private void ProceedTransactionMessage(MessageBase msg) { if (msg == null || msg.IsFormatError) { SetCommunicationError(true, "received invalid response message."); return; } if (msg.IsEvent) { OnEventArrived(msg); return; } //当前活动交互会话,继续执行 ActiveHandlerProceedMessage(msg); } private void _port_OnBinaryDataChanged(byte[] binaryData) { MessageBase msg = ParseResponse(binaryData); ProceedTransactionMessage(msg); } private void _port_OnAsciiDataReceived(string oneLineMessage) { MessageBase msg = ParseResponse(oneLineMessage); ProceedTransactionMessage(msg); } public HandlerBase MonitorTimeout() { HandlerBase result = null; lock (_lockerActiveHandler) { if (_activeHandler!=null && _activeHandler.CheckTimeout()) { result = _activeHandler; _activeHandler = null; SetCommunicationError(true, "receive response timeout"); } } return result; } public void SetCommunicationError(bool isError, string reason) { IsCommunicationError = isError; LastCommunicationError = reason; } } }