using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using Utils; using System.IO.Ports; using System.Configuration; using BWP.WebSocket; using System.Diagnostics; using System.IO; using CutupClient.Utils; namespace SerialPortWebSocketAdapter { public delegate void ReadParamEventHandler(string sParam); public class MyThread { public enum ElectronicScale { 电子称1, 电子称2, } private long received_count = 0;//接收计数 private long send_count = 0;//发送计数 private bool Listening = false;//是否没有执行完发送数据 private bool Closing = false;//是否正在关闭串口 public Thread thread2; ReadParamEventHandler OnReadParamEvent; public MyThread(ElectronicScale es = ElectronicScale.电子称1) { MyRead(es); } public void CloseThread() { try { if (thread1 != null && thread1.IsAlive) { thread1.Abort(); } if (thread2 != null && thread2.IsAlive) { thread2.Abort(); } CloseSerialPort(); } catch (ThreadAbortException e) { LogUtil.LogError("Abort:" + e.ToString()); } } public void Wait() { Closing = true; if (port.IsOpen) { while (Listening) DispatcherHelper.DoEvents(); port.Close(); } Closing = false; } public void Start() { try { if (!port.IsOpen) { port.Open(); } Closing = false; } catch (Exception ex) { ReadSerialPort(); } } public event ReadParamEventHandler ReadParam { add { OnReadParamEvent += new ReadParamEventHandler(value); } remove { OnReadParamEvent -= new ReadParamEventHandler(value); } } public void MyRead(ElectronicScale es = ElectronicScale.电子称1) { try { _Main(es); } catch (Exception ex) { LogUtil.LogError(ex); } } const string Version = "20160408"; public class _Config { public static _Config Instance = new _Config(); public string PortName { get; set; } public int BaudRate { get; set; } public int? DataBits { get; set; } public int DataLength { get; set; } public byte BeginByte { get; set; } public int ServicePort { get; set; } public string Format { get; set; } public string DataSource { get; set; } public string DataType { get; set; } public string ServiceType { get; set; } public string Parity { get; set; } public int? Delay { get; set; } public int? OnlySteady { get; set; } public bool NoBeginChar { get; set; } } _Config _config; _Config Config { get { if (_config == null) _config = new _Config(); return _config; } } private static readonly string[] Source = { "XK3190-D2+", "DDI200", "XK3124", "XK3190A9", "XK3139", "XK3190-A1+", "ACS-30B", "XK3190-A12+E","AWH-SA"}; public void _Main(ElectronicScale es = ElectronicScale.电子称1) { if (es == ElectronicScale.电子称1) { LogUtil.LogLine(string.Format("欢迎使用串口通信服务{0}", Version)); var settting = System.Configuration.ConfigurationManager.AppSettings; Config.PortName = settting["PortName"]; Config.BaudRate = int.Parse(settting["BaudRate"]); Config.DataLength = int.Parse(settting["DataLength"]); Config.DataType = settting["DataType"]; int dataBits; if (int.TryParse(settting["DataBits"], out dataBits)) Config.DataBits = dataBits; int delay; if (int.TryParse(settting["Delay"], out delay)) Config.Delay = delay; int onlySteady; if (int.TryParse(settting["OnlySteady"], out onlySteady)) Config.OnlySteady = onlySteady; Config.Parity = settting["Parity"]; Config.Format = settting["Format"]; Config.BeginByte = byte.Parse(settting["BeginHexNumber"], System.Globalization.NumberStyles.HexNumber); Config.DataSource = settting["DataSource"]; Config.NoBeginChar = bool.Parse(settting["NoBeginChar"]); if (!Source.Contains(Config.DataSource)) { LogUtil.LogError(string.Format("DataSource配置错误,必须是这些可选项之一:{0}", string.Join(" ", Source))); return; } } else if (es == ElectronicScale.电子称2) { LogUtil.LogLine(string.Format("欢迎使用串口通信服务{0}", Version)); var settting = System.Configuration.ConfigurationManager.AppSettings; Config.PortName = settting["PortName2"]; Config.BaudRate = int.Parse(settting["BaudRate2"]); Config.DataLength = int.Parse(settting["DataLength2"]); Config.DataType = settting["DataType2"]; int dataBits; if (int.TryParse(settting["DataBits2"], out dataBits)) Config.DataBits = dataBits; int delay; if (int.TryParse(settting["Delay2"], out delay)) Config.Delay = delay; int onlySteady; if (int.TryParse(settting["OnlySteady2"], out onlySteady)) Config.OnlySteady = onlySteady; Config.Parity = settting["Parity2"]; Config.Format = settting["Format2"]; Config.BeginByte = byte.Parse(settting["BeginHexNumber2"], System.Globalization.NumberStyles.HexNumber); Config.DataSource = settting["DataSource2"]; Config.NoBeginChar = bool.Parse(settting["NoBeginChar2"]); if (!Source.Contains(Config.DataSource)) { LogUtil.LogError(string.Format("DataSource配置错误,必须是这些可选项之一:{0}", string.Join(" ", Source))); return; } } ReadSerialPort(); thread2 = new Thread(new ThreadStart(ClearMsgTask)); thread2.Start(); } void ClearMsgTask() { var milisec = 500; var milliseconds = ConfigurationManager.AppSettings["TotalMilliseconds"]; if (!string.IsNullOrEmpty(milliseconds)) { milisec = int.Parse(milliseconds); } while (true) { Thread.Sleep(milisec); if (!port.IsOpen) continue; if (lastSendTime.HasValue && (DateTime.Now - lastSendTime).Value.TotalMilliseconds >= milisec && lastMsg != "") OnReadParamEvent("0"); } } class ReceiverManager { readonly List readBuffer = new List(); bool _enableReceiveData; void RestartReceive(bool enableReceiveData) { readBuffer.Clear(); _enableReceiveData = enableReceiveData; } public void Append(byte data, _Config config, ReadParamEventHandler even) { lock (readBuffer) { if (config.NoBeginChar) { _NoBeginCharAppendData(data, config, even); } else { _AppendData(data, config, even); } } } private void _NoBeginCharAppendData(byte data, _Config config, ReadParamEventHandler even) { readBuffer.Add(data); if (readBuffer.Count < config.DataLength) return; var buffer = readBuffer.ToArray(); readBuffer.Clear(); string message; if (TryParseMessage(buffer, config, out message) && !string.IsNullOrEmpty(message)) { even(message); } } private void _AppendData(byte data, _Config config, ReadParamEventHandler even) { if (data == config.BeginByte) { RestartReceive(true); return; } if (!_enableReceiveData) { return; } readBuffer.Add(data); if (readBuffer.Count < config.DataLength) return; var buffer = readBuffer.ToArray(); _enableReceiveData = false; readBuffer.Clear(); string message; if (TryParseMessage(buffer, config, out message) && !string.IsNullOrEmpty(message)) { even(message); lastSendTime = DateTime.Now; lastMsg = message; } } private static bool TryParseMessage(byte[] buffer, _Config config, out string message) { try { switch (config.DataSource) { case "XK3139": case "XK3124": message = FormatBaseXk3124(buffer, config); break; case "DDI200": case "XK3190A9": case "XK3190-A1+": message = FormatBaseXk3190A9(buffer, config); break; case "XK3190-D2+": message = FormatBaseXk3190D2(buffer, config); break; case "ACS-30B": message = FormatBaseACS30B(buffer, config); break; case "XK3190-A12+E": message = FormatBase3190A12(buffer, config); break; case "AWH-SA": case "ACS-W(SA)": message = FormatBaseAWH_SA(buffer, config); break; default: { message = ""; LogUtil.LogError(string.Format("未知的数据来源:{0}", config.DataSource)); return false; } } return true; } catch (Exception ex) { message = string.Empty; LogUtil.LogError(string.Format("使用数据来源{0}解析数据{1}时出现错误:{2}", config.DataSource, Convert.ToBase64String(buffer), ex.ToString())); return false; } } private static string FormatBaseACS30B(byte[] buffer, _Config config) { var output = Encoding.ASCII.GetString(buffer); if (output.Length > 0) { output = Reverse(output); output = output.TrimStart('0'); output = (decimal.Parse(output) / 1000).ToString(); } return output; } private static string FormatBaseACS_W_SA(byte[] buffer, _Config config) { var output = Encoding.ASCII.GetString(buffer); if (output.Length > 0) { //output = Reverse(output); output = output.TrimStart('0'); output = (decimal.Parse(output) / 1000).ToString(); } return output; } private static string FormatBaseAWH_SA(byte[] buffer, _Config config) { var output = Encoding.ASCII.GetString(buffer); output = output.Substring(6, 8).Replace(" ",string.Empty); decimal? result = null; if (config.DataType == "Decimal") { decimal decimalValue; if (decimal.TryParse(output, out decimalValue)) { result = decimalValue; } } if (result == null) { return string.Empty; } if (!string.IsNullOrEmpty(config.Format)) { output = string.Format(config.Format, result); } return output; } private static string FormatBaseXk3190D2(byte[] buffer, _Config config) { var strs = new byte[buffer.Length]; for (int index = 0; index < buffer.Length; index++) { strs[index] = buffer[buffer.Length - index - 1]; } var output = Encoding.ASCII.GetString(strs); // LogLine(string.Format("接收到串口数据:{0}", output)); object result = null; if (config.DataType == "Decimal") { decimal decimalValue; if (decimal.TryParse(output, out decimalValue)) { result = decimalValue; } } if (result == null) { LogUtil.LogError(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", output, config.DataType)); return string.Empty; // throw new Exception(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", output, Config.DataType)); } if (!string.IsNullOrEmpty(config.Format)) { output = string.Format(config.Format, result); } return output; } private static string FormatBaseXk3124(byte[] buffer, _Config config) { var output = Encoding.ASCII.GetString(buffer); //LogLine(string.Format("接收到串口数据:{0}", output)); var str = new StringBuilder(); char swa = output[0]; // 状态字A char swb = output[1]; // 状态字B int dotIndex = (swa & 0x07) - 2; // 小数点位置 bool isPositive = (((swb >> 1) & 0x01) == 0); // 符号:是否为正数 var isStatic = (((swb >> 3) & 0x01) == 0); //是否稳定值 暂时无用 char[] num = new char[6]; for (int i = 0; i < 6; i++) { num[i] = output[i + 3]; } // 不考虑精确到十,百位 if (dotIndex > 0) { for (int i = 0; i < 6 - dotIndex; i++) { str.Append(num[i]); } str.Append('.'); for (int i = 0; i < dotIndex; i++) { str.Append(num[6 - dotIndex + i]); } } else { foreach (var n in num) { str.Append(n); } } var strValue = str.ToString().Trim(); if (strValue.IndexOf('.') == 0) { strValue = strValue.Insert(0, "0"); } if (strValue.IndexOf('.') == strValue.Length - 1) { strValue = strValue.Replace(".", ""); } // 负数 if (!isPositive) { strValue = strValue.Insert(0, "-"); } decimal? result = null; if (config.DataType == "Decimal") { decimal decimalValue; if (decimal.TryParse(strValue, out decimalValue)) { result = decimalValue; } } if (result == null) { LogUtil.LogError(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", strValue, config.DataType)); return string.Empty; // throw new Exception(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", strValue, Config.DataType)); } DelySomeTime(result, config); if (!string.IsNullOrEmpty(config.Format)) { output = string.Format(config.Format, result); LogUtil.LogLine(string.Format("数据:{0} 稳定:{1} 延迟:{2}", output, isStatic, _isDelying)); } if (config.OnlySteady.HasValue && config.OnlySteady == 1 && !isStatic) { output = string.Empty; } return _isDelying ? string.Empty : output; } static bool _isDelying; static bool _waitingZero;//等待归0 private static DateTime? _startDelyTime; private static void DelySomeTime(decimal? result, _Config config) { if (!config.Delay.HasValue) return; if (_waitingZero && result <= 0) { _waitingZero = false; } if (_waitingZero || result <= 0) return; if (!_isDelying) { _isDelying = true; _startDelyTime = DateTime.Now; } else { var diffm = (DateTime.Now - _startDelyTime); if (diffm.HasValue) { if (diffm.Value.Seconds >= config.Delay.Value) { _isDelying = false; _startDelyTime = null; _waitingZero = true; } } else { _isDelying = false; } } } private static string FormatBase3190A12(byte[] buffer, _Config config) { var weight = Encoding.ASCII.GetString(buffer); decimal? result = null; if (config.DataType == "Decimal") { decimal decimalValue; if (decimal.TryParse(weight, out decimalValue)) { result = decimalValue; } } if (result == null) { LogUtil.LogError(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", weight, config.DataType)); return string.Empty; } if (!string.IsNullOrEmpty(config.Format)) { return string.Format(config.Format, result); } return string.Empty; } private static string FormatBaseXk3190A9(byte[] buffer, _Config config) { var output = Encoding.ASCII.GetString(buffer); //LogLine(string.Format("接收到串口数据:{0}", output)); string weight; // 小数位数0-4 int dot = (short)(0x0F & output[7]); weight = output.Substring(1, 6).Trim(); // insert dot weight = InsertDot(weight, dot); // buffer[1] 符号位 if (output[0] == '-') { weight = weight.Insert(0, "-"); } decimal? result = null; if (config.DataType == "Decimal") { decimal decimalValue; if (decimal.TryParse(weight, out decimalValue)) { result = decimalValue; } } if (result == null) { LogUtil.LogError(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", weight, config.DataType)); return string.Empty; //throw new Exception(string.Format("串口接收到的数据{0}不能转换为所期望的类型{1}", weight, Config.DataType)); } if (!string.IsNullOrEmpty(config.Format)) { output = string.Format(config.Format, result); // LogLine(string.Format("串口数据格式化为:{0}", output)); } return output; } private static string InsertDot(string weight, int dotBits) { var str = weight.TrimStart(new[] { '0' }); str = str.Trim(); if (dotBits > 0) { if (string.IsNullOrEmpty(str)) { return "0"; } str = str.Insert(str.Length - dotBits, "."); } if (str.IndexOf(".", StringComparison.Ordinal) == 0) { str = str.Insert(0, "0"); } return str; } } SerialPort port = null; private static DateTime? lastSendTime = null; private static string lastMsg = null; public static Thread thread1; void ReadSerialPort() { if (!string.IsNullOrEmpty(Config.DataSource) && !Source.Contains(Config.DataSource)) { LogUtil.LogError(string.Format("数据来源{0}无效,无法处理数据", Config.DataSource)); return; } port = new SerialPort(Config.PortName, Config.BaudRate); port.ReceivedBytesThreshold = Config.DataLength + 1; if (Config.DataBits.HasValue) port.DataBits = Config.DataBits.Value; //数据位 if (Config.Parity == "Even") port.Parity = Parity.Even; if (Config.Parity == "Odd") port.Parity = Parity.Odd; port.ErrorReceived += (sender, e) => { LogUtil.LogError(new Exception(string.Format("串口接收到一个错误,类型为{0}", e.ToString()))); }; var receiver = new ReceiverManager(); port.DataReceived += delegate { if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环 Listening = true;//设置标记,说明已经开始处理数据, while (port.IsOpen && port.BytesToRead > 0) { try { var data = Convert.ToByte(port.ReadByte()); receiver.Append(data, Config, OnReadParamEvent); } catch (ThreadAbortException e) { LogUtil.LogError("Abort:" + e.ToString()); break; } } Listening = false; }; // OpenSerialPort(); if (Config.DataSource == "ACS-30B") { try { thread1 = new Thread(new ThreadStart(PortWriteA)); //thread1.IsBackground = true; thread1.Start(); //PortWriteA(); } catch (ThreadAbortException e) { LogUtil.LogError("Abort:" + e.ToString()); } } } void PortWriteA() { try { while (true) { if (port.IsOpen) port.Write("a"); Thread.Sleep(500); } } catch (ThreadAbortException e) { LogUtil.LogError(e.ToString()); } } void CloseSerialPort() { try { Closing = true; if (port.IsOpen) { while (Listening) DispatcherHelper.DoEvents(); port.Close(); } port.Dispose(); Closing = false; LogUtil.LogLine(string.Format("关闭串口{0}成功", Config.PortName)); } catch (Exception ex) { LogUtil.LogError(string.Format("关闭串口{0}失败:{1}", Config.PortName, ex.Message)); } } void OpenSerialPort() { try { if (!port.IsOpen) port.Open(); LogUtil.LogLine(string.Format("连接串口{0}成功", Config.PortName)); } catch (Exception ex) { LogUtil.LogError(string.Format("连接串口{0}失败:{1}", Config.PortName, ex.Message)); } } /// /// 反转字符串 /// /// /// static string Reverse(string value) { char[] rs = value.ToCharArray(); Array.Reverse(rs); var ret = new string(rs); return ret; } } }