using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using DocumentFormat.OpenXml.InkML;
using MECF.Framework.Common.CommonData.PowerSupplier;
using MECF.Framework.Common.Communications;
using MECF.Framework.Common.Net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MECF.Framework.Common.Device.PowerSupplier
{
public class PowerSupplierSerialPortModbusDevice
{
#region 常量
private const short CURRENT_SETTING_ADDRESS = 0x0101;
private const short OUTPUT_CONTROL_ADDRESS = 0x0110;
private const short STEP_PERIOD_ADDRESS = 0x1400;
private const short STEP_PERIOD_START_ADDRESS = 0x1640;
private const short VOLTAGE_OUTPUT_ADDRESS = 0x0201;
private const short POWER_CONTROL_ADDRESS = 0x0113;
private const short POWER_RUN_MODEL_ADDRESS = 0x0111;
///
/// 电源状态(00-cv输出,01-cc输出)
///
private const short POWER_STATUS_ADDRESS = 0x0200;
private const string SET_POINT = "SetPoint";
private const string CURRENT = "Current";
private const string VOLTAGE = "Voltage";
private const string ENABLED = "Enabled";
private const string POWER_STATUS = "PowerStatus";
private const string POWER_CONTROL = "PowerControl";
private const string POWER_RUN_MODEL = "PowerRunModel";
///
/// 步阶数据数量
///
private const int STEP_PERIOD_LENGTH = 6;
#endregion
#region 内部变量
private string _name;
private ConcurrentQueue _commandQueue=new ConcurrentQueue();
private SerialPort _serialPort;
private bool _connected;
private object _locker = new object();
private int _lockTimeout = 1000;
private PowerSupplierMessage _netMessage = new PowerSupplierMessage();
private object _sendLocker = new object();
private object _receiveLocker = new object();
private int _receiveTimeout = 1000;
private int _sendTimeout = 1000;
///
/// 错误
///
private string _errmsg;
///
/// 离线时间
///
private DateTime _offlineDateTime = DateTime.Now;
///
/// 是否重连
///
private bool _reconnect = false;
///
/// 首次连接成功
///
private bool _isFirstConnected = false;
#endregion
#region 属性
public bool Connected { get { return _connected; } }
#endregion
///
/// 构造函数
///
///
///
public PowerSupplierSerialPortModbusDevice(string name, string portName, int baudRate = 9600, StopBits stopBits = StopBits.One, int dataBits = 8, Parity parity = Parity.None, bool reconnect = false)
{
_name = name;
_serialPort = new SerialPort();
_serialPort.BaudRate = baudRate;
_serialPort.StopBits = stopBits;
_serialPort.DataBits = dataBits;
_serialPort.Parity = parity;
_serialPort.PortName = portName;
_serialPort.ReadTimeout = _receiveTimeout;
_serialPort.WriteTimeout = _sendTimeout;
_serialPort.ErrorReceived += SerialPort_ErrorReceived;
_reconnect = reconnect;
PeriodicJob periodicJob = new PeriodicJob(20, OnTimer, $"{name}.ModbusDevice.Thread", true);
}
///
/// 出现错误
///
///
///
private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, e.EventType.ToString());
}
///
/// 定时器
///
///
private bool OnTimer()
{
if (!_connected)
{
if (DateTime.Now.Subtract(_offlineDateTime).TotalSeconds >= 5 && _commandQueue.Count != 0)
{
ClearSendQueue();
}
if (_reconnect&&_isFirstConnected)
{
Start();
}
return true;
}
if (_commandQueue.Count!=0)
{
if(_commandQueue.TryDequeue(out PowerSupplierCommand command))
{
if (_connected)
{
if (command.CommandCode == 0x03)
{
ApplyDataOperation(command);
}
}
}
}
return true;
}
///
/// 清空发送队列
///
private void ClearSendQueue()
{
try
{
while (_commandQueue.Count != 0)
{
_commandQueue.TryDequeue(out var result);
}
}
catch
{
}
}
///
/// 连接
///
///
public bool Start()
{
if (!_connected)
{
try
{
_serialPort.Open();
LOG.WriteLog(eEvent.INFO_LINMOT, _name, $"connect port[{_serialPort.PortName}] success");
_connected = true;
if(!_isFirstConnected)
{
_isFirstConnected = true;
}
return true;
}
catch (Exception ex)
{
return false;
}
}
return true;
}
///
/// 设置通道输出开关控制
///
///
///
///
public void SetChannelOutputSwitchControl(byte channel, bool enabled)
{
if (Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x06;
command.Address = (ushort)(OUTPUT_CONTROL_ADDRESS);
command.Datas = new ushort[] { enabled ? (ushort)01 : (ushort)00 };
SetOperation(command);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 设置电源控制
///
///
///
///
public void SetChannelPowerControl(byte channel,byte remoteControl)
{
if (Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x06;
command.Address = (ushort)(POWER_CONTROL_ADDRESS);
command.Datas = new ushort[] { remoteControl };
SetOperation(command);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 设置电源运行模式
///
///
///
///
public void SetChannelPowerRunmodelControl(byte channel,byte model)
{
if (Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x06;
command.Address = (ushort)(POWER_RUN_MODEL_ADDRESS);
command.Datas = new ushort[] { model };
SetOperation(command);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 设置步阶数据
///
///
///
public bool SetStepPeriod(byte channel,List stepDatas,int scale)
{
if(Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x10;
command.Address = (ushort)STEP_PERIOD_ADDRESS;
command.RegisterCount =(ushort)(STEP_PERIOD_LENGTH * stepDatas.Count);
command.Datas = new ushort[STEP_PERIOD_LENGTH * stepDatas.Count];
for(int i = 0;i
/// 启动步阶
///
///
///
///
///
public bool StartStepPeriod(byte channel,ushort startStep,ushort endStep,ushort cycle)
{
if (Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x10;
command.Address = (ushort)STEP_PERIOD_START_ADDRESS;
command.RegisterCount = 3;
command.Datas = new ushort[3] { startStep,endStep,cycle };
return SetOperation(command);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
return false;
}
///
/// 设置电流
///
///
///
///
public void SetCurrentValue(byte channel,ushort currentValue)
{
if (Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x06;
command.Address = (ushort)(CURRENT_SETTING_ADDRESS);
command.Datas = new ushort[] { currentValue };
SetOperation(command);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 设置电源状态
///
///
///
///
public void SetChannelPowerStatus(byte channel, byte powerStatus)
{
if (Connected)
{
PowerSupplierCommand command = new PowerSupplierCommand();
command.Channel = channel;
command.CommandCode = 0x06;
command.Address = (ushort)(POWER_STATUS_ADDRESS);
command.Datas = new ushort[] { powerStatus };
SetOperation(command);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 获取通道输出开关控制
///
///
///
public void GetChannelOutput(byte channel)
{
if (Connected)
{
PowerSupplierCommand applyCommand = new PowerSupplierCommand();
applyCommand.Channel = channel;
applyCommand.CommandCode = 0x03;
applyCommand.Address = (ushort)(OUTPUT_CONTROL_ADDRESS);
applyCommand.RegisterCount = 1;
applyCommand.Variables.Add(ENABLED,(0,1));
_commandQueue.Enqueue(applyCommand);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 获取通道电源控制
///
///
///
public void GetChannelPowerControl(byte channel)
{
if (Connected)
{
PowerSupplierCommand applyCommand = new PowerSupplierCommand();
applyCommand.Channel = channel;
applyCommand.CommandCode = 0x03;
applyCommand.Address = (ushort)(POWER_CONTROL_ADDRESS);
applyCommand.RegisterCount = 1;
applyCommand.Variables.Add(POWER_CONTROL, (0, 1));
_commandQueue.Enqueue(applyCommand);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 获取通道电流设置数值
///
///
///
public void GetChannelCurrentSetting(byte channel)
{
if (Connected)
{
PowerSupplierCommand applyCommand = new PowerSupplierCommand();
applyCommand.Channel = channel;
applyCommand.CommandCode = 0x03;
applyCommand.Address = (ushort)(CURRENT_SETTING_ADDRESS);
applyCommand.RegisterCount = 1;
applyCommand.Variables.Add(SET_POINT,(0,1));
_commandQueue.Enqueue(applyCommand);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 获取电源状态设置数值
///
///
///
public void GetChannelPowerStatus(byte channel)
{
if (Connected)
{
PowerSupplierCommand applyCommand = new PowerSupplierCommand();
applyCommand.Channel = channel;
applyCommand.CommandCode = 0x03;
applyCommand.Address = (ushort)(POWER_STATUS_ADDRESS);
applyCommand.RegisterCount = 1;
applyCommand.Variables.Add(POWER_STATUS, (0,1));
_commandQueue.Enqueue(applyCommand);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 获取电源运行模式
///
///
///
public void GetChannelPowerRunModel(byte channel)
{
if (Connected)
{
PowerSupplierCommand applyCommand = new PowerSupplierCommand();
applyCommand.Channel = channel;
applyCommand.CommandCode = 0x03;
applyCommand.Address = (ushort)(POWER_RUN_MODEL_ADDRESS);
applyCommand.RegisterCount = 1;
applyCommand.Variables.Add(POWER_RUN_MODEL, (0, 1));
_commandQueue.Enqueue(applyCommand);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 申请电压和电流数值
///
///
///
public void GetChannelVoltageAndCurrent(byte channel)
{
if (Connected)
{
PowerSupplierCommand applyCommand = new PowerSupplierCommand();
applyCommand.Channel = channel;
applyCommand.CommandCode = 0x03;
applyCommand.Address = (ushort)(VOLTAGE_OUTPUT_ADDRESS);
applyCommand.RegisterCount = 4;
applyCommand.Variables.Add(VOLTAGE,(0,2));
applyCommand.Variables.Add(CURRENT,(2,2));
_commandQueue.Enqueue(applyCommand);
}
else
{
WriteErrorMsg($"{_name} is not connected");
}
}
///
/// 设置操作
///
///
///
private bool SetOperation(PowerSupplierCommand command)
{
NetResult netResult = SetData(command);
if (!netResult.IsSuccess)
{
LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, $"write value {command.Datas[0]} failed,{netResult.Message}");
return false;
}
return true;
}
///
/// 设置数据
///
///
///
///
public NetResult SetData(PowerSupplierCommand data)
{
if (Monitor.TryEnter(_locker, _lockTimeout))
{
NetResult result = ReadFromServer(data);
if (!result.IsSuccess)
{
Monitor.Exit(_locker);
return NetResult.CreateFailedResult(result.ErrorCode, result.Message);
}
bool confirmResult = _netMessage.ConfirmResponseResult();
if (!confirmResult)
{
Monitor.Exit(_locker);
return NetResult.CreateFailedResult(_netMessage.ErrorCode, _netMessage.ErrorMsg);
}
Monitor.Exit(_locker);
return NetResult.CreateSuccessResult();
}
else
{
return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
}
}
///
/// 从服务端读取数据
///
///
///
///
private NetResult ReadFromServer(PowerSupplierCommand data)
{
byte[] buffer = _netMessage.Code(data);
NetResult sendResult = Send(buffer);
if (!sendResult.IsSuccess)
{
return NetResult.CreateFailedResult(sendResult.ErrorCode, sendResult.Message);
}
_netMessage.SendBytes = buffer;
_netMessage.SetProtocolHeadBytesLength();
NetResult headerResult = Receive(_netMessage.ProtocolHeadBytesLength);
if (!headerResult.IsSuccess)
{
return NetResult.CreateFailedResult(headerResult.ErrorCode, headerResult.Message);
}
_netMessage.HeadBytes = headerResult.Data;
if (!_netMessage.CheckHeadBytesLegal())
{
return NetResult.CreateFailedResult(NetErrorCode.InvalidHeader);
}
NetResult contentResult = Receive(_netMessage.GetContentLengthByHeadBytes());
if (!contentResult.IsSuccess)
{
return NetResult.CreateFailedResult(contentResult.ErrorCode, contentResult.Message);
}
_netMessage.ContentBytes = contentResult.Data;
bool dataValid = _netMessage.CheckDataLegal();
if (!dataValid)
{
return NetResult.CreateFailedResult(_netMessage.ErrorCode, _netMessage.ErrorMsg);
}
return NetResult.CreateSuccessResult();
}
///
/// 申请数据操作
///
///
private void ApplyDataOperation(PowerSupplierCommand command)
{
NetResult netResult = ApplyData(command);
if (!netResult.IsSuccess)
{
List keys = command.Variables.Keys.ToList();
string str = String.Join(" ", keys);
WriteErrorMsg($"apply {str} error");
return;
}
if(netResult.Data.Datas!=null)
{
Dictionary dictionary = command.Variables;
List keys = dictionary.Keys.ToList();
foreach(string item in keys)
{
var result = dictionary[item];
if(item==ENABLED)
{
PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, ENABLED, netResult.Data.Datas[result.Item1] == 0x01);
}
else
{
if(result.Item2==1)
{
PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, item, netResult.Data.Datas[result.Item1]);
}
else if(result.Item2==2)
{
int value = netResult.Data.Datas[result.Item1] * 255 + netResult.Data.Datas[result.Item1+1];
PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, item, value);
}
}
}
}
}
///
/// 申请数据
///
/// 申请指令类型
/// 指令对象
/// 返回数据对象
public NetResult ApplyData(PowerSupplierCommand data)
{
if (Monitor.TryEnter(_locker, _lockTimeout))
{
NetResult result = ReadFromServer(data);
if (!result.IsSuccess)
{
Monitor.Exit(_locker);
return NetResult.CreateFailedResult(result.ErrorCode, result.Message);
}
Monitor.Exit(_locker);
return NetResult.CreateSuccessResult(_netMessage.Decode());
}
else
{
return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
}
}
///
/// 发送数据
///
///
///
public NetResult Send(byte[] data)
{
if (!Connected)
{
return NetResult.CreateFailedResult(NetErrorCode.NetOffline);
}
//清除缓存数据
ClearPreData();
//进入发送
if (Monitor.TryEnter(_sendLocker, _sendTimeout))
{
if (_serialPort == null)
{
return NetResult.CreateFailedResult(NetErrorCode.NullSocketObject);
}
try
{
_serialPort.Write(data,0,data.Length);
Monitor.Exit(_sendLocker);
return NetResult.CreateSuccessResult();
}
catch (Exception ex)
{
Monitor.Exit(_sendLocker);
WriteErrorMsg(ex.Message);
return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
}
}
else
{
return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
}
}
///
/// 接收数据
///
///
///
public NetResult Receive(int length)
{
if (!Connected)
{
return NetResult.CreateFailedResult(NetErrorCode.NetOffline);
}
if (Monitor.TryEnter(_receiveLocker, _receiveTimeout))
{
if (_serialPort == null)
{
return NetResult.CreateFailedResult(NetErrorCode.NullSocketObject);
}
try
{
byte[] buffer = new byte[length];
DateTime dt = DateTime.Now;
while(true)
{
if(_serialPort.BytesToRead>=length)
{
_serialPort.Read(buffer, 0, length);
break;
}
if(DateTime.Now.Subtract(dt).TotalMilliseconds>=_receiveTimeout)
{
Monitor.Exit(_receiveLocker);
return NetResult.CreateFailedResult(NetErrorCode.ReceiveTimeout);
}
}
Monitor.Exit(_receiveLocker);
return NetResult.CreateSuccessResult(buffer);
}
catch (SocketException ex)
{
Monitor.Exit(_receiveLocker);
return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
}
catch (Exception ex)
{
Monitor.Exit(_receiveLocker);
return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
}
}
else
{
return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
}
}
///
/// 清除先前的数据
///
public void ClearPreData()
{
if (!Connected)
{
return;
}
if (Monitor.TryEnter(_receiveLocker, _receiveTimeout))
{
try
{
while (_serialPort.BytesToRead != 0)
{
byte[] buffer = new byte[_serialPort.BytesToRead];
_serialPort.Read(buffer,0, buffer.Length);
}
Monitor.Exit(_receiveLocker);
}
catch (SocketException ex)
{
Monitor.Exit(_receiveLocker);
}
catch (Exception ex)
{
Monitor.Exit(_receiveLocker);
}
}
}
///
/// 记录错误信息
///
///
private void WriteErrorMsg(string msg, bool disConnected = true)
{
if (disConnected)
{
_connected = false;
_offlineDateTime = DateTime.Now;
}
if (_errmsg != msg)
{
_errmsg = msg;
LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, msg);
}
}
}
}