You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

574 lines
19 KiB

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));
}
}
}
}