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<byte> readBuffer = new List<byte>();
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|