using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Ports; using System.Configuration; using System.Threading; using BWP.WebSocket; using System.Diagnostics; using System.IO; using Utils; namespace SerialPortWebSocketAdapter { public class SerialPortAdapter { const string Version = "20160408"; 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; } } static _Config Config { get { return _Config.Instance; } } private static readonly string[] Source = { "XK3190-D2+", "DDI200", "XK3124", "XK3190A9", "XK3139", "XK3190A1" }; public static void Main() { try { _Main(); } catch (Exception ex) { LogUtil.LogError(ex); throw; } } private static void _Main() { 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.ServiceType = settting["ServiceType"]; Config.ServicePort = int.Parse(settting["ServicePort"]); Config.DataSource = settting["DataSource"]; if (!Source.Contains(Config.DataSource)) { LogUtil.LogError(string.Format("DataSource配置错误,必须是这些可选项之一:{0}", string.Join(" ", Source))); return; } if (Config.ServiceType == "WebSocket") { try { SimpleWebSocketServer.Start(Config.ServicePort); } catch (Exception) { LogUtil.LogError(string.Format("服务启动失败,可能多次启动该程序或者端口{0}被占用", Config.ServicePort)); return; } } else if (Config.ServiceType == "Comet") { try { CometServer.Start(Config.ServicePort); } catch (Exception) { LogUtil.LogError(string.Format("服务启动失败,可能多次启动该程序或者端口{0}被占用", Config.ServicePort)); return; } } else { LogUtil.LogError("ServeType配置错误,WebSocket ort Comet?"); return; } ReadSerialPort(); var newThread = new Thread(ClearMsgTask) { }; newThread.Start(); var input = Console.ReadLine(); //while (input != "exit") //{ // if (input == "Open") // { // OpenSerialPort(); // } // else if (input == "Close") // { // CloseSerialPort(); // } // else // { // SendMessage(input); // } // input = Console.ReadLine(); //} } static void ClearMsgTask() { while (true) { Thread.Sleep(1000); if (lastSendTime.HasValue && (DateTime.Now - lastSendTime).Value.TotalSeconds >= 5 && lastMsg != "") SendMessage(""); } } class ReceiverManager { static readonly List readBuffer = new List(); static bool _enableReceiveData; static void RestartReceive(bool enableReceiveData) { readBuffer.Clear(); _enableReceiveData = enableReceiveData; } public static void Append(byte data) { lock (readBuffer) { _AppendData(data); } } private static void _AppendData(byte data) { 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, out message) && !string.IsNullOrEmpty(message)) { SendMessage(message); } } private static bool TryParseMessage(byte[] buffer, out string message) { try { switch (Config.DataSource) { case "XK3139": case "XK3124": message = FormatBaseXk3124(buffer); break; case "DDI200": case "XK3190A9": message = FormatBaseXk3190A9(buffer); break; case "XK3190-D2+": message = FormatBaseXk3190D2(buffer); break; case "XK3190A1": message = FormatBaseXk3190A1(buffer); break; default: { message = ""; //throw new Exception(string.Format("未知的数据来源:{0}", Config.DataSource)); 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 FormatBaseXk3190D2(byte[] buffer) { 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) { 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); 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) { 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 FormatBaseXk3190A1(byte[] buffer) { var str = Encoding.ASCII.GetString(buffer); var result = string.Empty; if (!string.IsNullOrEmpty(str)) { str = str.Substring(1, str.Length - 2); var num = str.Substring(0, 6); var num2 = str.Substring(6); str = long.Parse(num + "." + num2).ToString(); } return str; } private static string FormatBaseXk3190A9(byte[] buffer) { 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; } } static SerialPort port = null; private static DateTime? lastSendTime = null; private static string lastMsg = null; private static void SendMessage(string message) { try { if (Config.ServiceType == "WebSocket") { SimpleWebSocketServer.Send(message); lastSendTime = DateTime.Now; lastMsg = message; } else if (Config.ServiceType == "Comet") { if (lastSendTime==null||( (DateTime.Now - lastSendTime.Value) .TotalMilliseconds >= 250) ) { CometServer.Send(message); lastSendTime = DateTime.Now; lastMsg = message; } } } catch (Exception ex) { LogUtil.LogError("发送消息时出现错误:" + ex.ToString()); } } static 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()))); }; port.DataReceived += delegate { while (port.BytesToRead > 0) { var data = Convert.ToByte(port.ReadByte()); ReceiverManager.Append(data); } }; OpenSerialPort(); } static void CloseSerialPort() { try { port.Close(); LogUtil.LogLine(string.Format("关闭串口{0}成功", Config.PortName)); } catch (Exception ex) { LogUtil.LogError(string.Format("关闭串口{0}失败:{1}", Config.PortName, ex.Message)); } } private static void OpenSerialPort() { try { port.Open(); LogUtil.LogLine(string.Format("连接串口{0}成功", Config.PortName)); } catch (Exception ex) { LogUtil.LogError(string.Format("连接串口{0}失败:{1}", Config.PortName, ex.Message)); } } } }