using StageController.M3H; using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace StageController { public delegate void VoltageEvent(CommandBase command, Result result, string msg); public class VoltageController { //定义接收数据事件 public event VoltageEvent VoltageReceived; private SerialPort m_serialPort; private Queue m_commandQueue; private MsgMgr m_msgMgr = new MsgMgr(); private Thread m_waitingThread; private static VoltageController m_instance = null; private VoltageController() { m_commandQueue = new Queue(100); } public static VoltageController GetInstance() { if (m_instance == null) { m_instance = new VoltageController(); } return m_instance; } private bool m_running = false; public string[] GetSerialPorts() { return SerialPort.GetPortNames(); } // 正式环境中的处理流程: // Step 1 : 枚举所有串口 // Step 2 : Open(comName) // Step 3 : AddCommand(ConnectCheckCommand) // Step 4 : callback // Step 5 : Close // 重复Step 2 ~ Step 5 public void Open(string portName, int baudRate) { if (!m_running) { m_serialPort = new SerialPort(portName, baudRate); m_serialPort.Encoding = Encoding.ASCII; m_serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived); m_serialPort.Open(); m_commandQueue.Clear(); m_waitingThread = new Thread(new ThreadStart(MessageThreadEntry)); m_waitingThread.Start(); m_running = true; } } public void Close() { if (m_running) { m_msgMgr.EndLoop(); if ((m_serialPort != null) && m_serialPort.IsOpen) { m_serialPort.Close(); } m_running = false; } m_commandQueue.Clear(); } public void AddCommand(CommandBase command) { m_commandQueue.Enqueue(command); m_msgMgr.SendMsg(MSG_TOSEND, null, null); } private string m_responseCommand; private string parseCmdPkg(string response) { string retStr = null; int stopPosi = response.IndexOf("#"); if (stopPosi > 0) //第0个字符不可能为 "!" { int startPosi = response.IndexOf("*"); // response.LastIndexOf("@"); if (startPosi >= 0) { retStr = response.Substring(startPosi, stopPosi - startPosi + 1); } } return retStr; } // 接收串口返回数据 private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string recvData = sp.ReadExisting(); if (string.IsNullOrWhiteSpace(recvData)) { Logs.Write("Err: Received null or white or space!"); return; } Logs.Write("Recv Data: " + recvData); m_responseCommand += recvData; // 拆包 string resPkg = parseCmdPkg(m_responseCommand); if (resPkg != null) { Logs.Write("Recv Pack: " + resPkg); // 解析 if (m_curCommand.Parse(resPkg)) { m_msgMgr.SendMsg(MSG_RECVED, resPkg, m_curCommand); } else { Logs.Write("Err: command parse faild!"); m_msgMgr.SendMsg(MSG_ERR, resPkg, m_curCommand); } // m_responseCommand = ""; // edit by maxb 20200807 连续两个命令同时执行时,可能会出现接收到的数据包含第二条命令返回数据的一部分 int stopPosi = m_responseCommand.IndexOf("#"); m_responseCommand = m_responseCommand.Substring(stopPosi + 1); } // 接收字符串长度超过200,说明出错误了。 if (m_responseCommand.Length > 200) { Logs.Write("Err: m_responseCommand.Length is : " + m_responseCommand.Length); m_responseCommand = ""; //TODO } } private const int MSG_TOSEND = 0; //parm1: 0, parm2:0 private const int MSG_RECVED = 1; //parm1:address, parm2: data private const int MSG_TIMEOUT = 2; //parm1: 0, parm2:0 private const int MSG_ERR = 3; //parm1: errType, parm2:errCode //errType : Checksum, Response private const int STS_IDLE = 0; private const int STS_WAITRES = 1; private int m_curSts = STS_IDLE; private CommandBase m_curCommand = null; private const int RETRY_TIME = 2; private int m_retryCnt = 0; private void callCallback(CommandBase command, Result result, string msg) { if (VoltageReceived != null) { VoltageReceived(command, result, msg); } } private void MsgProcess(int msg, object parm1, object parm2) { // 状态机模型 switch (msg) { case MSG_TOSEND: if (STS_IDLE == m_curSts) { if (m_commandQueue.Count > 0) { m_curCommand = m_commandQueue.Dequeue(); m_retryCnt = 0; SendCommandBySerial(m_curCommand); StartSendTimer(); m_curSts = STS_WAITRES; } } break; case MSG_RECVED: if (STS_WAITRES == m_curSts) { StopSendTimer(); //Logs.Write("callCallback"); //收到回复数据包,而且解析正常 callCallback(m_curCommand, Result.OK, (string)parm1); //parm1中记录了收到的数据包 m_curSts = STS_IDLE; m_msgMgr.SendMsg(MSG_TOSEND, 0, null); } break; case MSG_TIMEOUT: if (STS_WAITRES == m_curSts) { StopSendTimer(); if (m_retryCnt >= RETRY_TIME) { // 没收到回复的数据包 callCallback(m_curCommand, Result.ERR_TIMEOUT, "超时"); m_curSts = STS_IDLE; } else { SendCommandBySerial(m_curCommand); StartSendTimer(); m_retryCnt++; } } break; case MSG_ERR: if (STS_WAITRES == m_curSts) { StopSendTimer(); // 收到回复数据包,解析时发现错误 if (m_retryCnt >= RETRY_TIME) { callCallback(m_curCommand, Result.ERR_PARSE, (string)parm1); //parm1中记录了收到的数据包 m_curSts = STS_IDLE; } else { SendCommandBySerial(m_curCommand); StartSendTimer(); m_retryCnt++; } } break; } } private void MessageThreadEntry() { m_msgMgr.MessageProcess = MsgProcess; m_msgMgr.MsgLoop(); } #region serial port private void SendCommandBySerial(CommandBase cmd) { string sendData = cmd.Make(); Logs.Write("send : " + sendData); if ((m_serialPort != null) && m_serialPort.IsOpen) { m_serialPort.Write(sendData); } } #endregion #region timer private System.Timers.Timer m_sendTimer = null; private void SendTimerTimeout(object sender, System.Timers.ElapsedEventArgs e) { m_msgMgr.SendMsg(MSG_TIMEOUT, null, null); } private void StartSendTimer() { if (m_sendTimer == null) { m_sendTimer = new System.Timers.Timer(1000.0); m_sendTimer.Elapsed += SendTimerTimeout; m_sendTimer.AutoReset = false; //one short timer. } m_sendTimer.Start(); } private void StopSendTimer() { if (m_sendTimer != null) { m_sendTimer.Stop(); } } #endregion } }