Commit 709ec17e 顾剑亮

coding

1 个父辈 9a7eb2f5
此文件类型无法预览
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Collections.Generic;
namespace Asa.IOModule namespace Asa.IOModule
{ {
/// <summary> /// <summary>
/// AIOBOX操作类 /// 零点IO模块操作类
/// </summary> /// </summary>
public class AIOBOX public class AIOBOX
{ {
private Socket _client; //客户端
private bool _quit;
private bool _loop;
private string _logPath; //日志的文件夹路径
private LogFile _log; //日志的类
private LogType _logType; //日志输出类型
private bool _frontInputOutput; //True:Input False:Output
private int countInput; //输入总数
private int countOutput; //输出总数
private int sleepInput; //自动读取DI间隔
private int sleepOutput; //自动读取DO间隔
private Box_Type _typeInput; //输入类型
private Box_Type _typeOutput; //输出类型
private byte[] _addressInput; //输入地址
private byte[] _addressOutput; //输出地址
private bool _autoReadInput; //自动读取DI
private bool _autoReadOutput; //自动读取DO
private bool _manualReadOutput; //手动读取DO
private bool _changeDI; //DI收到数据触发事件
private bool _changeDO; //DO收到数据触发事件
private bool _changeAI; //AI收到数据触发事件
private bool _changeAO; //AO收到数据触发事件
private Box_Sta[] _stateDI; //状态
private Box_Sta[] _stateDO; //状态
private int[] _valueAI; //模拟量
private int[] _valueAO; //模拟量
private System.Collections.Concurrent.ConcurrentQueue<ushort> _flag;
private System.Collections.Concurrent.ConcurrentQueue<byte[]> _send;
private System.Collections.Concurrent.ConcurrentQueue<byte[]> _receive;
private Thread tRecon;
private Thread tSend; //发送命令处理
private Thread tReceive; //接收信息处理
private Thread tListen; //监听网络
private Thread tTrigger; //触发DI、DO改变事件
private Thread tReadInput; //自动读取DI线程
private Thread tReadOutput; //自动读取DO线程
private Thread tFlag; //ModBusTCP标识
private UdpClient broadcastClient; //广播客户端
private IPEndPoint broadcastEndPoint; //广播远程节点
private byte[] broadcastBuffer; //远程返回数据
/// <summary>
/// 每条命令发送的间隔
/// 不能小于15,会出现IO接收不到的情况
/// 小于30时,会出现接收数据连包的情况
/// </summary>
private const int SEND_SLEEP = 30;
/// <summary>
/// ModBus端口
/// </summary>
public const int PORT = 502;
/// <summary> /// <summary>
/// 自动读取DI委托 /// 自动读取DI委托
/// </summary> /// </summary>
...@@ -82,179 +25,98 @@ namespace Asa.IOModule ...@@ -82,179 +25,98 @@ namespace Asa.IOModule
/// 自动读取DO事件触发 /// 自动读取DO事件触发
/// </summary> /// </summary>
public event DIO_Changed DO_Changed_Event; public event DIO_Changed DO_Changed_Event;
/// <summary>
/// 自动读取AI委托
/// </summary>
/// <param name="box">AIOBOX</param>
/// <param name="val">所有AI的值</param>
public delegate void AIO_Changed(AIOBOX box, int[] val);
/// <summary>
/// 自动读取AI事件触发
/// </summary>
public event AIO_Changed AI_Changed_Event;
/// <summary>
/// 自动读取AO事件触发
/// </summary>
public event AIO_Changed AO_Changed_Event;
/// <summary>
/// AIOBOX
/// </summary>
public AIOBOX()
{
_log = null;
_logPath = null;
_autoReadInput = false;
_autoReadOutput = false;
_manualReadOutput = false;
sleepInput = 100;
sleepOutput = 100;
}
/// <summary> private Socket _client; //客户端
/// IP地址 private bool _loop;
/// </summary> private ushort _uid;
public string IP { set; get; } = "192.168.1.100"; private Box_Sta[] _stateDI; //DI状态
private Box_Sta[] _stateDO; //DO状态
private int[] _valueAI; //AI模拟量
private int[] _valueAO; //AO模拟量
private List<byte> _receive;
private System.Collections.Concurrent.ConcurrentQueue<byte[]> _writeDO;
private readonly Box_Type _typeInput; //输入类型
private readonly Box_Type _typeOutput; //输出类型
private readonly byte[] _addressInput; //输入地址
private readonly byte[] _addressOutput; //输出地址
private const int SEND_SLEEP = 50; //每条命令发送的间隔,不能小于15,会出现IO接收不到的情况,小于30时,会出现接收数据连包的情况
private const int PORT = 502; //端口
private const int UPLOAD_TIME = 8000; //8秒
private Thread tRecon; //重连线程
private Thread tSend; //发送命令处理
private Thread tListen; //监听网络
/// <summary> private UdpClient broadcastClient; //广播客户端
/// 是否连接 private IPEndPoint broadcastEndPoint; //广播远程节点
/// </summary> private byte[] broadcastBuffer; //远程返回数据
public bool IsConn { get; private set; } = false;
/// <summary> /// <summary>
/// 错误信息 /// 零点IO模块操作类
/// </summary> /// </summary>
public string ErrInfo { get; private set; } = ""; /// <param name="input">输入类型</param>
/// <param name="inputCount">输入数量</param>
/// <param name="output">输出类型</param>
/// <param name="outputCount">输出数量</param>
public AIOBOX(Box_Type input, int inputCount, Box_Type output, int outputCount)
{
_typeInput = input;
_typeOutput = output;
byte n = 0;
_addressInput = new byte[inputCount];
for (int i = 0; i < inputCount; i++)
_addressInput[i] = n++;
_addressOutput = new byte[outputCount];
for (int i = 0; i < outputCount; i++)
_addressOutput[i] = n++;
_stateDI = new Box_Sta[inputCount];
_stateDO = new Box_Sta[outputCount];
_valueAI = new int[inputCount];
_valueAO = new int[outputCount];
}
/// <summary>
/// 日志路径,连接前设置路径会自动保存日志
/// </summary>
/// <param name="path">文件夹路径</param>
/// <param name="type">输出类型</param>
public void LogPath(string path, LogType type)
{
_logPath = path;
_logType = type;
}
/// <summary> /// <summary>
/// 设置输入端 /// IP地址
/// </summary> /// </summary>
/// <param name="type">类型</param> public string IP { set; get; } = "192.168.1.100";
/// <param name="count">数量</param>
public void SetInput(Box_Type type, int count)
{
_typeInput = type;
countInput = count;
_frontInputOutput = false;
}
/// <summary> /// <summary>
/// 设置输出端 /// 输入主动上传
/// </summary> /// </summary>
/// <param name="type">类型</param> public bool Upload { set; get; } = false;
/// <param name="count">数量</param>
public void SetOutput(Box_Type type, int count)
{
_typeOutput = type;
countOutput = count;
_frontInputOutput = true;
}
/// <summary> /// <summary>
/// 自动获取IP地址,未连接前使用,必须在同一网段 /// 是否连接
/// </summary> /// </summary>
/// <param name="localIP">本地IP地址</param> public bool IsConn { get; private set; } = false;
/// <returns></returns>
public bool AutoIP(string localIP)
{
try
{
IPEndPoint local = new IPEndPoint(IPAddress.Parse(localIP), 55654);
broadcastClient = new UdpClient(local);
broadcastBuffer = null;
Thread tTemp = new Thread(new ThreadStart(GetIP));
tTemp.Start();
broadcastEndPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1024);
byte[] dgram = new byte[] { 0x05, 0x00, 0x07, 0x00, 0x00, 0xC1, 0x59 };
broadcastClient.Send(dgram, dgram.Length, broadcastEndPoint);
Thread.Sleep(1000);
tTemp.Abort();
broadcastClient.Close();
ErrInfo = "无法访问";
if (broadcastBuffer == null) return false;
if (broadcastBuffer[0] != 0x3B) return false;
byte[] buff = new byte[broadcastBuffer[7]];
Array.Copy(broadcastBuffer, 9, buff, 0, buff.Length);
IP = buff[buff.Length - 12] + "." + buff[buff.Length - 11] + "." + buff[buff.Length - 10] + "." + buff[buff.Length - 9];
ErrInfo = "OK";
return true;
}
catch (Exception ex)
{
ErrInfo = ex.Message;
return false;
}
}
/// <summary> /// <summary>
/// 检查IP地址 /// 错误信息
/// </summary> /// </summary>
/// <param name="ip"></param> public string ErrInfo { get; private set; } = "";
/// <returns></returns>
public bool CheckIP(string ip)
{
//IP合法
string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";
bool rtn = System.Text.RegularExpressions.Regex.IsMatch(ip, pattern);
if (!rtn)
{
ErrInfo = "非法的IP地址";
return false;
}
//Ping服务端
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply result = ping.Send(ip, 1000);
ping.Dispose();
if (result.Status != System.Net.NetworkInformation.IPStatus.Success)
{
ErrInfo = "Ping " + ip + " 请求没有响应";
return false;
}
return true;
}
/// <summary> /// <summary>
/// 连接 /// 连接
/// </summary> /// </summary>
public void Connect() public void Connect()
{ {
if (_logPath == null) _loop = true;
_log = null; _uid = 0;
else IsConn = false;
_log = new LogFile(_logPath, IP); _receive = new List<byte>();
_writeDO = new System.Collections.Concurrent.ConcurrentQueue<byte[]>();
_quit = false;
tRecon = new Thread(new ThreadStart(Reconn)); tRecon = new Thread(new ThreadStart(Reconn));
tSend = new Thread(new ThreadStart(Send));
tListen = new Thread(new ThreadStart(Listen));
tRecon.Start(); tRecon.Start();
tSend.Start();
int time = 0; tListen.Start();
while (time < 3000)
{
if (IsConn) break;
else time += 50;
Thread.Sleep(50);
}
} }
...@@ -263,82 +125,26 @@ namespace Asa.IOModule ...@@ -263,82 +125,26 @@ namespace Asa.IOModule
/// </summary> /// </summary>
public void Close() public void Close()
{ {
_quit = true; _loop = false;
Exit(); IsConn = false;
if (_log != null)
{
_log.OutData("Close OK");
_log.Close();
_log = null;
}
}
/// <summary>
/// 自动读取输入端并触发事件(主动上传数据 = 禁止)
/// </summary>
/// <param name="read">是否自动读取</param>
/// <param name="sleep">间隔,必须大于等于15ms</param>
public void AutoReadInput(bool read, int sleep)
{
if (countInput < 1)
_autoReadInput = false;
else if (sleep < 15)
_autoReadInput = false;
else if (read)
{
_autoReadInput = true;
sleepInput = sleep;
}
else
_autoReadInput = false;
}
/// <summary>
/// 自动读取输入端并触发事件(主动上传数据 = 使能)
/// </summary>
/// <param name="read">是否自动读取</param>
public void AutoReadInput(bool read)
{
if (countInput < 1)
_autoReadInput = false;
else if (read)
{
_autoReadInput = true;
sleepInput = 8000; //IO模块最大10s,避免超过时间,每8秒发送一次心跳包
}
else
_autoReadInput = false;
}
/// <summary> try
/// 自动读取输出端,触发事件
/// </summary>
/// <param name="read">是否自动读取</param>
/// <param name="sleep">间隔,必须大于等于15ms</param>
public void AutoReadOutput(bool read, int sleep)
{ {
if (countOutput < 1) if (_client != null)
{ {
_autoReadOutput = false; _client.Shutdown(SocketShutdown.Both);
sleepOutput = 100; _client.Close();
} }
else if (sleep < 15)
{
_autoReadOutput = false;
sleepOutput = 100;
} }
else if (read) catch (Exception ex)
{ {
_autoReadOutput = true; ErrInfo = ex.Message;
sleepOutput = sleep;
} }
else finally
{ {
_autoReadOutput = false; _client = null;
_manualReadOutput = true; //用于第一次连接的时候读取一次状态
sleepOutput = sleep;
} }
} }
/// <summary> /// <summary>
...@@ -471,9 +277,7 @@ namespace Asa.IOModule ...@@ -471,9 +277,7 @@ namespace Asa.IOModule
buff[7] = 5; //功能码 buff[7] = 5; //功能码
buff[9] = _addressOutput[add]; //地址 buff[9] = _addressOutput[add]; //地址
buff[10] = (byte)sta; //写入值 buff[10] = (byte)sta; //写入值
_send.Enqueue(buff); _writeDO.Enqueue(buff);
if (!_autoReadOutput)
_manualReadOutput = true;
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
...@@ -483,523 +287,274 @@ namespace Asa.IOModule ...@@ -483,523 +287,274 @@ namespace Asa.IOModule
} }
} }
/// <summary>
/// 获取本地IPv4地址
/// </summary>
/// <returns></returns>
public string[] GetLocalIP()
{
List<string> str = new List<string>();
IPAddress[] add = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
foreach (IPAddress ip in add)
{
if (ip.AddressFamily.ToString() == "InterNetwork")
str.Add(ip.ToString());
}
return str.ToArray();
}
/// <summary> /// <summary>
/// 发送命令 /// 发送命令线程
/// </summary> /// </summary>
private void Send() private void Send()
{ {
bool shift = true; //切换
int time = 0; //上传时间
int writeTimer = 0; //写入DO次数
bool writeStop = false; //写入命令停止
while (_loop) while (_loop)
{ {
bool rtn = _send.TryDequeue(out byte[] result); Thread.Sleep(SEND_SLEEP);
if (rtn) if (!IsConn) continue;
byte[] buff;
if (Upload) //主动上传
{
if (time >= UPLOAD_TIME)
{ {
try buff = GetReadDI_Command();
time = 0;
}
else
{ {
_client.Send(result); if (writeTimer >= 3) //连续发送WriteDO3次,强制发送DO
if (_log != null)
{ {
if (_logType == LogType.All) buff = GetReadDO_Command();
_log.OutData("Send ", result); writeTimer = 0;
} }
else
{
if (_writeDO.TryDequeue(out buff))
{
writeTimer++;
} }
catch (Exception ex) else
{ {
IsConn = false; buff = GetReadDO_Command();
_loop = false; writeTimer = 0;
if (_log != null)
_log.OutError(ex.Message);
} }
} }
Thread.Sleep(SEND_SLEEP);
} }
time += SEND_SLEEP;
} }
else
/// <summary>
/// 接收命令
/// </summary>
private void Receive()
{
while (_loop)
{ {
if (_receive.TryDequeue(out byte[] buff)) if (writeTimer >= 3) //连续发送WriteDO3次,强制发送DI和DO
{ {
try if (shift)
buff = GetReadDI_Command();
else
buff = GetReadDO_Command();
shift = !shift;
if (writeStop)
writeTimer = 0;
else
writeStop = true;
}
else
{ {
if (_log != null) if (_writeDO.TryDequeue(out buff))
{ {
if (_logType == LogType.All) writeTimer++;
_log.OutData("Receive ", buff); writeStop = false;
} }
if (buff.Length < 7) else
continue;
if (buff[7] == 1)
{ {
ReadDO(buff); if (shift)
_changeDO = true; buff = GetReadDI_Command();
else
buff = GetReadDO_Command();
shift = !shift;
writeTimer = 0;
} }
else if (buff[7] == 2)
{
ReadDI(buff);
_changeDI = true;
} }
else if (buff[7] == 4)
{
ReadAI(buff);
_changeAI = true;
} }
else if (buff[7] == 5)
try
{ {
//ReadSingle(buff); _client.Send(buff);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
if (_log != null) ErrInfo = ex.Message;
_log.OutError(ex.Message); IsConn = false;
} }
} }
Thread.Sleep(10);
} }
/// <summary>
/// 获取ReadDI的命令
/// </summary>
/// <returns></returns>
private byte[] GetReadDI_Command()
{
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[5] = 6; //后面字节数
//功能码
if (_typeInput == Box_Type.DI)
buff[7] = 2;
else if (_typeInput == Box_Type.AI)
buff[7] = 4;
buff[9] = _addressInput[0]; //地址
buff[11] = (byte)_addressInput.Length; //个数
return buff;
} }
/// <summary> /// <summary>
/// 读取写入单个DO,功能码5 /// 获取ReadDO的命令
/// </summary> /// </summary>
/// <param name="buff"></param> /// <returns></returns>
private void ReadSingle(byte[] buff) private byte[] GetReadDO_Command()
{ {
string s; byte[] data = Command();
byte[] buff = new byte[12];
//if (LogOut) Array.Copy(data, 0, buff, 0, data.Length);
//{ buff[5] = 6; //后面字节数
// byte[] bb = new byte[2]; buff[7] = 1; //功能码
// bb[0] = buff[1]; buff[9] = _addressOutput[0]; //地址
// bb[1] = buff[0]; buff[11] = (byte)_addressOutput.Length; //个数
// ushort flag = BitConverter.ToUInt16(bb, 0); return buff;
// s = string.Format("{0:HH:mm:ss:fff} WriteDO {1} fun={2} len={3}", DateTime.Now, flag, buff[7], buff.Length);
// _log.Add(s);
//}
// int n = 0;
// int move = 0;
// byte val = _receive[0][9];
// for (int i = 0; i < 8; i++)
// {
// n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
// _sta[i + 16] = n == 1 ? Box_Sta.On : Box_Sta.Off;
// move++;
// }
// if (_receive[0][8] == 2)
// {
// move = 0;
// val = _receive[0][10];
// for (int i = 8; i < 16; i++)
// {
// n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
// _sta[i + 16] = n == 1 ? Box_Sta.On : Box_Sta.Off;
// move++;
// }
// }
// ErrInfo = "OK";
//}
//catch (Exception ex)
//{
// ErrInfo = ex.Message;
//}
} }
/// <summary> /// <summary>
/// 读取所有DO状态,功能码1 /// 监听网络线程
/// </summary> /// </summary>
/// <param name="buff"></param> private void Listen()
private void ReadDO(byte[] buff)
{ {
while (_loop)
{
Thread.Sleep(10);
if (!IsConn) continue;
if (_client == null) continue;
try try
{ {
int idx = 0; if (_client.Available > 0)
int count = buff[8];
for (int i = 1; i <= count; i++)
{ {
int n = 0; byte[] buff = new byte[_client.ReceiveBufferSize];
int move = 0; int count = _client.Receive(buff);
byte val = buff[8 + i]; byte[] temp = new byte[count];
for (int j = 0; j < 8; j++) Array.Copy(buff, 0, temp, 0, count);
{
n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
_stateDO[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
move++;
}
}
if (_log != null)
{
if (_logType == LogType.All)
_log.OutData("Read All DO");
}
}
catch (Exception ex)
{
if (_log != null)
_log.OutError(ex.Message);
}
lock (_receive)
}
/// <summary>
/// 读取所有DI状态,功能码2
/// </summary>
private void ReadDI(byte[] buff)
{
try
{ {
int idx = 0; _receive.AddRange(temp);
int count = buff[8]; while (_receive.Count > 6) //分解连包
for (int i = 1; i <= count; i++)
{
int n = 0;
int move = 0;
byte val = buff[8 + i];
for (int j = 0; j < 8; j++)
{ {
n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move; int len = _receive[5] + 6;
_stateDI[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off; if (len > _receive.Count) break;
move++; byte[] cmd = new byte[len];
_receive.CopyTo(0, cmd, 0, len);
_receive.RemoveRange(0, len);
System.Threading.Tasks.Task.Run(() => CommandProcess(cmd));
} }
} }
if (_log != null)
{
if (_logType == LogType.All)
_log.OutData("Read All DI");
} }
//Test 方法锁
TestMethod();
} }
catch (Exception ex) catch (Exception ex)
{ {
if (_log != null) ErrInfo = ex.Message;
_log.OutError(ex.Message); IsConn = false;
}
}
/// <summary>
/// 读取所有AI的值,功能码4
/// </summary>
/// <param name="buff"></param>
private void ReadAI(byte[] buff)
{
try
{
if (countInput * 2 == buff[8])
{
_valueAI[0] = buff[9] * 256 + buff[10];
_valueAI[1] = buff[11] * 256 + buff[12];
_valueAI[2] = buff[13] * 256 + buff[14];
_valueAI[3] = buff[15] * 256 + buff[16];
}
if (_log != null)
{
if (_logType == LogType.All)
_log.OutData("Read All AI");
}
} }
catch (Exception ex)
{
if (_log != null)
_log.OutError(ex.Message);
} }
} }
/// <summary> /// <summary>
/// 命令,前7个字节 /// 接收到的命令处理方法,(task多线程)
/// </summary> /// </summary>
/// <returns></returns> /// <param name="cmd"></param>
private byte[] Command() private void CommandProcess(byte[] cmd)
{ {
_flag.TryDequeue(out ushort result); int idx = 0;
byte[] flag = BitConverter.GetBytes(result); int count = cmd[8];
byte[] data = new byte[7];
data[0] = flag[1];
data[1] = flag[0];
data[2] = 0;
data[3] = 0;
data[4] = 0;
data[5] = 0;
data[6] = 255;
return data;
}
/// <summary> try
/// 触发DIO改变事件
/// </summary>
private void TriggerDIO()
{
while (_loop)
{ {
if (_typeInput == Box_Type.DI && DI_Changed_Event != null) if (cmd[7] == 1) //ReadDO
{ {
//if (_changeDI) Box_Sta[] staDO = new Box_Sta[_stateDO.Length];
//{ lock (_stateDO)
// _changeDI = false;
// Box_Sta[] staDI = new Box_Sta[countInput];
// Array.Copy(_stateDI, 0, staDI, 0, staDI.Length);
// if (_log != null)
// {
// if (_logType == LogType.All)
// _log.OutData("Trigger DI Event");
// }
// lock (staDI)
// System.Threading.Tasks.Task.Run(() => DI_Changed_Event.Invoke(this, staDI));
//}
}
else if (_typeInput == Box_Type.AI && AI_Changed_Event != null)
{ {
if (_changeAI) for (int i = 1; i <= count; i++)
{ {
_changeAI = false; int move = 0;
int[] valAI = new int[countInput]; byte val = cmd[8 + i];
Array.Copy(_valueAI, 0, valAI, 0, valAI.Length); for (int j = 0; j < 8; j++) //字节的0-7位
if (_log != null)
{ {
if (_logType == LogType.All) int n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
_log.OutData("Trigger AI Event"); _stateDO[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
} move++;
lock (valAI)
System.Threading.Tasks.Task.Run(() => AI_Changed_Event.Invoke(this, valAI));
} }
} }
if (_typeOutput == Box_Type.DO && DO_Changed_Event != null)
{
if (_changeDO)
{
_changeDO = false;
Box_Sta[] staDO = new Box_Sta[countOutput];
Array.Copy(_stateDO, 0, staDO, 0, staDO.Length); Array.Copy(_stateDO, 0, staDO, 0, staDO.Length);
if (_log != null)
{
if (_logType == LogType.All)
_log.OutData("Trigger DO Event");
} }
lock (staDO) System.Threading.Tasks.Task.Run(() => DO_Changed_Event?.Invoke(this, staDO));
System.Threading.Tasks.Task.Run(() => DO_Changed_Event.Invoke(this, staDO));
} }
} else if (cmd[7] == 2) //ReadDI
else if (_typeOutput == Box_Type.AO && AO_Changed_Event != null)
{ {
if (_changeAO) Box_Sta[] staDI = new Box_Sta[_stateDI.Length];
lock (_stateDI)
{ {
_changeAO = false; for (int i = 1; i <= count; i++)
int[] valAO = new int[countOutput];
Array.Copy(_valueAO, 0, valAO, 0, valAO.Length);
if (_log != null)
{ {
if (_logType == LogType.All) int move = 0;
_log.OutData("Trigger AO Event"); byte val = cmd[8 + i];
} for (int j = 0; j < 8; j++) //字节的0-7位
lock (valAO) {
System.Threading.Tasks.Task.Run(() => AO_Changed_Event.Invoke(this, valAO)); int n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
_stateDI[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
move++;
} }
} }
Array.Copy(_stateDI, 0, staDI, 0, staDI.Length);
Thread.Sleep(10);
} }
System.Threading.Tasks.Task.Run(() => DI_Changed_Event?.Invoke(this, staDI));
} }
else if (cmd[7] == 5)
/// <summary>
/// 自动读取输入端线程
/// </summary>
private void AutoReadInput()
{
while (_loop)
{ {
if (IsConn && _autoReadInput)
{
//if (suspendDI && suspend > 0)
//{
// suspendDI = false;
// suspend--;
//}
//else
//{
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[5] = 6; //后面字节数
//功能码
if (_typeInput == Box_Type.DI)
buff[7] = 2;
else if (_typeInput == Box_Type.AI)
buff[7] = 4;
buff[9] = _addressInput[0]; //地址
buff[11] = (byte)countInput; //个数
_send.Enqueue(buff);
//suspendDI = true;
//}
}
Thread.Sleep(sleepInput);
} }
} }
catch (Exception ex)
/// <summary>
/// 自动读取输出端线程
/// </summary>
private void AutoReadOutput()
{
while (_loop)
{
Thread.Sleep(sleepOutput);
if (!IsConn) continue;
if (!_autoReadOutput)
{ {
if (_manualReadOutput) ErrInfo = ex.Message;
_manualReadOutput = false;
else
continue;
}
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[5] = 6; //后面字节数
buff[7] = 1; //功能码
buff[9] = _addressOutput[0]; //地址
buff[11] = (byte)countOutput; //个数
_send.Enqueue(buff);
} }
} }
/// <summary> /// <summary>
/// 监听结果线程 /// 重连线程
/// </summary> /// </summary>
private void Listen() private void Reconn()
{ {
byte[] temp = new byte[200];
int start, len;
while (_loop) while (_loop)
{ {
try if (IsConn)
{
if (_client == null) break;
if (_client.Available > 0)
{
start = 0;
int count = _client.Receive(temp);
while (count - start > 6)
{
len = temp[start + 5];
len += 6;
if (start + len > count) break;
byte[] aa = new byte[len];
Array.Copy(temp, start, aa, 0, len);
_receive.Enqueue(aa);
start += len;
}
}
}
catch (Exception ex)
{
IsConn = false;
_loop = false;
if (_log != null)
_log.OutError(ex.Message);
}
Thread.Sleep(10);
}
}
private void InitAddr()
{
byte n = 0;
if (_frontInputOutput)
{ {
_addressInput = new byte[countInput]; Thread.Sleep(1000);
for (int i = 0; i < countInput; i++)
_addressInput[i] = n++;
_addressOutput = new byte[countOutput];
for (int i = 0; i < countOutput; i++)
_addressOutput[i] = n++;
} }
else else
{ {
_addressOutput = new byte[countOutput]; Thread.Sleep(100);
for (int i = 0; i < countOutput; i++) if (_loop) Open();
_addressOutput[i] = n++;
_addressInput = new byte[countInput];
for (int i = 0; i < countInput; i++)
_addressInput[i] = n++;
}
_stateDI = new Box_Sta[countInput];
_stateDO = new Box_Sta[countOutput];
_valueAI = new int[countInput];
_valueAO = new int[countOutput];
}
private void GetIP()
{
broadcastBuffer = broadcastClient.Receive(ref broadcastEndPoint);
}
private void Flag()
{
ushort n = 0;
while (_loop)
{
if (_flag.Count < 10)
{
_flag.Enqueue(++n);
if (n == ushort.MaxValue) n = 0;
} }
Thread.Sleep(5);
} }
} }
/// <summary>
/// 打开socket建立连接
/// </summary>
private void Open() private void Open()
{ {
try try
{ {
//初始化地址
IsConn = false; IsConn = false;
InitAddr();
//检查IP地址
bool rtn = CheckIP(IP); bool rtn = CheckIP(IP);
if (!rtn) return; if (!rtn) return;
_send = new System.Collections.Concurrent.ConcurrentQueue<byte[]>();
_receive = new System.Collections.Concurrent.ConcurrentQueue<byte[]>();
_flag = new System.Collections.Concurrent.ConcurrentQueue<ushort>();
//建立连接 //建立连接
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 500); _client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 500);
...@@ -1007,108 +562,118 @@ namespace Asa.IOModule ...@@ -1007,108 +562,118 @@ namespace Asa.IOModule
_client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1); _client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);
_client.Connect(IPAddress.Parse(IP), PORT); _client.Connect(IPAddress.Parse(IP), PORT);
Thread.Sleep(100); //需要等待一会才能获取连接状态 Thread.Sleep(100); //需要等待一会才能获取连接状态
tFlag = new Thread(new ThreadStart(Flag));
tFlag.Start();
Thread.Sleep(10);
tSend = new Thread(new ThreadStart(Send));
tReceive = new Thread(new ThreadStart(Receive));
tListen = new Thread(new ThreadStart(Listen));
tTrigger = new Thread(new ThreadStart(TriggerDIO));
tReadInput = new Thread(new ThreadStart(AutoReadInput));
tReadOutput = new Thread(new ThreadStart(AutoReadOutput));
IsConn = true; IsConn = true;
_loop = true;
tListen.Start();
tTrigger.Start();
tSend.Start();
tReceive.Start();
tReadInput.Start();
tReadOutput.Start();
ErrInfo = ""; ErrInfo = "";
if (_log != null) _log.OutData("Connect OK");
return; return;
} }
catch (Exception ex) catch (Exception ex)
{ {
IsConn = false; IsConn = false;
ErrInfo = ex.Message; ErrInfo = ex.Message;
if (_log != null) _log.OutError(ex.Message);
return; return;
} }
} }
private void Exit() /// <summary>
{ /// 检查IP地址
IsConn = false; /// </summary>
_loop = false; /// <param name="ip"></param>
tListen = null; /// <returns></returns>
tReadInput = null; private bool CheckIP(string ip)
tReadOutput = null;
tTrigger = null;
tSend = null;
tReceive = null;
tFlag = null;
try
{
if (_client != null)
{ {
_client.Shutdown(SocketShutdown.Both); //IP合法
_client.Close(); string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";
} bool rtn = System.Text.RegularExpressions.Regex.IsMatch(ip, pattern);
} if (!rtn)
catch (Exception ex)
{ {
if (_log != null) ErrInfo = "非法的IP地址";
_log.OutError(ex.Message); return false;
} }
finally
//Ping服务端
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply result = ping.Send(ip, 1000);
ping.Dispose();
if (result.Status != System.Net.NetworkInformation.IPStatus.Success)
{ {
_client = null; ErrInfo = "Ping " + ip + " 请求没有响应";
return false;
} }
return true;
} }
/// <summary> /// <summary>
/// 测试方法锁 /// 自动获取IP地址,未连接前使用,必须在同一网段
/// </summary> /// </summary>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] /// <param name="localIP">本地IP地址</param>
private void TestMethod() /// <returns></returns>
private bool AutoIP(string localIP)
{ {
Box_Sta[] staDI = new Box_Sta[countInput]; try
Array.Copy(_stateDI, 0, staDI, 0, staDI.Length);
if (_log != null)
{ {
if (_logType == LogType.All) IPEndPoint local = new IPEndPoint(IPAddress.Parse(localIP), 55654);
_log.OutData("Trigger DI Event"); broadcastClient = new UdpClient(local);
} broadcastBuffer = null;
lock (staDI)
System.Threading.Tasks.Task.Run(() => DI_Changed_Event.Invoke(this, staDI));
}
Thread tTemp = new Thread(new ThreadStart(GetIP));
tTemp.Start();
broadcastEndPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1024);
byte[] dgram = new byte[] { 0x05, 0x00, 0x07, 0x00, 0x00, 0xC1, 0x59 };
broadcastClient.Send(dgram, dgram.Length, broadcastEndPoint);
Thread.Sleep(1000);
tTemp.Abort();
broadcastClient.Close();
ErrInfo = "无法访问";
if (broadcastBuffer == null) return false;
if (broadcastBuffer[0] != 0x3B) return false;
private void Reconn() byte[] buff = new byte[broadcastBuffer[7]];
{ Array.Copy(broadcastBuffer, 9, buff, 0, buff.Length);
while (!_quit) IP = buff[buff.Length - 12] + "." + buff[buff.Length - 11] + "." + buff[buff.Length - 10] + "." + buff[buff.Length - 9];
{ ErrInfo = "OK";
if (IsConn) return true;
{
Thread.Sleep(1000);
} }
else catch (Exception ex)
{ {
Exit(); ErrInfo = ex.Message;
Thread.Sleep(100); return false;
if (!_quit) Open();
} }
} }
/// <summary>
/// 获取IO模块IP地址
/// </summary>
private void GetIP()
{
broadcastBuffer = broadcastClient.Receive(ref broadcastEndPoint);
}
/// <summary>
/// 命令,前7个字节
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
private byte[] Command()
{
byte[] flag = BitConverter.GetBytes(++_uid);
if (_uid == ushort.MaxValue) _uid = 0;
byte[] data = new byte[7];
data[0] = flag[1];
data[1] = flag[0];
data[2] = 0;
data[3] = 0;
data[4] = 0;
data[5] = 0;
data[6] = 255;
return data;
} }
} }
/// <summary> /// <summary>
/// IO模块类型 /// IO模块类型
/// </summary> /// </summary>
...@@ -1147,23 +712,5 @@ namespace Asa.IOModule ...@@ -1147,23 +712,5 @@ namespace Asa.IOModule
On = 255 On = 255
} }
/// <summary>
/// 日志类型
/// </summary>
public enum LogType : int
{
/// <summary>
/// 仅错误信息
/// </summary>
OnlyError,
/// <summary>
/// 所有
/// </summary>
All
}
} }
...@@ -64,7 +64,6 @@ ...@@ -64,7 +64,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AIOBOX.cs" /> <Compile Include="AIOBOX.cs" />
<Compile Include="Log.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
......
using System;
using System.Reflection;
using System.Diagnostics;
namespace Asa.IOModule
{
/// <summary>
/// 日志操作类
/// </summary>
internal class LogFile
{
//private string args;
private bool loop;
private System.IO.FileStream fs;
private StackTrace trace;
private StackFrame frame;
private MethodBase method;
private System.Threading.Thread tSave;
private System.Collections.Concurrent.ConcurrentQueue<string> info;
private readonly string PATH;
/// <summary>
/// 日志
/// </summary>
/// <param name="path">文件夹路径</param>
/// <param name="ip"></param>
internal LogFile(string path, string ip)
{
if (path == null) return;
//this.args = ip;
PATH = path.EndsWith("\\") ? path : path + "\\";
if (!System.IO.Directory.Exists(PATH))
System.IO.Directory.CreateDirectory(PATH);
loop = true;
tSave = new System.Threading.Thread(new System.Threading.ThreadStart(SaveLog));
info = new System.Collections.Concurrent.ConcurrentQueue<string>();
tSave.Start();
string file = string.Format("{0}{1:yyyy-MM-dd}_({2}).log", PATH, DateTime.Now, ip);
fs = System.IO.File.OpenWrite(file);
fs.Position = fs.Length;
}
/// <summary>
/// 关闭文件
/// </summary>
internal void Close()
{
loop = false;
System.Threading.Thread.Sleep(5);
if (fs != null)
fs.Close();
}
/// <summary>
/// 输出错误
/// </summary>
/// <param name="s"></param>
internal void OutError(string s)
{
if (string.IsNullOrWhiteSpace(s)) return;
trace = new StackTrace(true);
frame = trace.GetFrame(1);
string name = frame.GetFileName();
name = System.IO.Path.GetFileName(name);
string log = string.Format("[{0:HH:mm:ss.fff}] ERROR {1}({2},{3})\r\n",
DateTime.Now, name, frame.GetFileLineNumber(), frame.GetFileColumnNumber());
string[] arr = new string[trace.FrameCount - 1];
for (int i = 1; i < trace.FrameCount; i++) //0是本身Out
{
method = trace.GetFrame(i).GetMethod();
arr[arr.Length - i] = " " + method.DeclaringType.FullName + " -> " + method.ToString();
}
log += string.Join("\r\n", arr) + string.Format("\r\n {0}\r\n", s);
//byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
//fs.Write(array, 0, array.Length);
info.Enqueue(log);
}
/// <summary>
/// 输出信息
/// </summary>
/// <param name="s"></param>
internal void OutInfo(string s)
{
if (string.IsNullOrWhiteSpace(s)) return;
trace = new StackTrace(true);
frame = trace.GetFrame(1);
method = trace.GetFrame(1).GetMethod();
string name = frame.GetFileName();
name = System.IO.Path.GetFileName(name);
string s1 = method.DeclaringType.FullName;
string s2 = method.Name;
string log = string.Format("[{0:HH:mm:ss.fff}] INFO {1}({2},{3}) {4} -> {5}\r\n {6}\r\n",
DateTime.Now, name, frame.GetFileLineNumber(), frame.GetFileColumnNumber(), s1, s2, s);
//byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
//fs.Write(array, 0, array.Length);
info.Enqueue(log);
}
/// <summary>
/// 输出数据
/// </summary>
/// <param name="tr"></param>
/// <param name="buff"></param>
internal void OutData(string tr, byte[] buff)
{
string log = string.Format("{0:HH:mm:ss.fff} {1} ", DateTime.Now, tr);
for (int i = 0; i < buff.Length; i++)
log += buff[i].ToString("X2") + " ";
log += "\r\n";
//byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
//fs.Write(array, 0, array.Length);
info.Enqueue(log);
}
/// <summary>
/// 输出数据
/// </summary>
/// <param name="s"></param>
internal void OutData(string s)
{
string log = string.Format("{0:HH:mm:ss.fff} {1}\r\n", DateTime.Now, s);
//byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
//fs.Write(array, 0, array.Length);
info.Enqueue(log);
}
internal void SaveLog()
{
while (loop)
{
try
{
if (info.TryDequeue(out string result))
{
byte[] array = System.Text.Encoding.UTF8.GetBytes(result);
fs.Write(array, 0, array.Length);
}
}
catch (Exception)
{ }
System.Threading.Thread.Sleep(2);
}
}
}
}
...@@ -32,5 +32,5 @@ using System.Runtime.InteropServices; ...@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//通过使用 "*",如下所示: //通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.3.0.4")] [assembly: AssemblyVersion("2.3.0.6")]
[assembly: AssemblyFileVersion("2.3.0.4")] [assembly: AssemblyFileVersion("2.3.0.6")]
...@@ -6,19 +6,7 @@ ...@@ -6,19 +6,7 @@
<members> <members>
<member name="T:Asa.IOModule.AIOBOX"> <member name="T:Asa.IOModule.AIOBOX">
<summary> <summary>
AIOBOX操作类 零点IO模块操作类
</summary>
</member>
<member name="F:Asa.IOModule.AIOBOX.SEND_SLEEP">
<summary>
每条命令发送的间隔
不能小于15,会出现IO接收不到的情况
小于30时,会出现接收数据连包的情况
</summary>
</member>
<member name="F:Asa.IOModule.AIOBOX.PORT">
<summary>
ModBus端口
</summary> </summary>
</member> </member>
<member name="T:Asa.IOModule.AIOBOX.DIO_Changed"> <member name="T:Asa.IOModule.AIOBOX.DIO_Changed">
...@@ -38,31 +26,23 @@ ...@@ -38,31 +26,23 @@
自动读取DO事件触发 自动读取DO事件触发
</summary> </summary>
</member> </member>
<member name="T:Asa.IOModule.AIOBOX.AIO_Changed"> <member name="M:Asa.IOModule.AIOBOX.#ctor(Asa.IOModule.Box_Type,System.Int32,Asa.IOModule.Box_Type,System.Int32)">
<summary>
自动读取AI委托
</summary>
<param name="box">AIOBOX</param>
<param name="val">所有AI的值</param>
</member>
<member name="E:Asa.IOModule.AIOBOX.AI_Changed_Event">
<summary> <summary>
自动读取AI事件触发 零点IO模块操作类
</summary> </summary>
<param name="input">输入类型</param>
<param name="inputCount">输入数量</param>
<param name="output">输出类型</param>
<param name="outputCount">输出数量</param>
</member> </member>
<member name="E:Asa.IOModule.AIOBOX.AO_Changed_Event"> <member name="P:Asa.IOModule.AIOBOX.IP">
<summary>
自动读取AO事件触发
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.#ctor">
<summary> <summary>
AIOBOX IP地址
</summary> </summary>
</member> </member>
<member name="P:Asa.IOModule.AIOBOX.IP"> <member name="P:Asa.IOModule.AIOBOX.Upload">
<summary> <summary>
IP地址 输入主动上传
</summary> </summary>
</member> </member>
<member name="P:Asa.IOModule.AIOBOX.IsConn"> <member name="P:Asa.IOModule.AIOBOX.IsConn">
...@@ -75,41 +55,6 @@ ...@@ -75,41 +55,6 @@
错误信息 错误信息
</summary> </summary>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.LogPath(System.String,Asa.IOModule.LogType)">
<summary>
日志路径,连接前设置路径会自动保存日志
</summary>
<param name="path">文件夹路径</param>
<param name="type">输出类型</param>
</member>
<member name="M:Asa.IOModule.AIOBOX.SetInput(Asa.IOModule.Box_Type,System.Int32)">
<summary>
设置输入端
</summary>
<param name="type">类型</param>
<param name="count">数量</param>
</member>
<member name="M:Asa.IOModule.AIOBOX.SetOutput(Asa.IOModule.Box_Type,System.Int32)">
<summary>
设置输出端
</summary>
<param name="type">类型</param>
<param name="count">数量</param>
</member>
<member name="M:Asa.IOModule.AIOBOX.AutoIP(System.String)">
<summary>
自动获取IP地址,未连接前使用,必须在同一网段
</summary>
<param name="localIP">本地IP地址</param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.CheckIP(System.String)">
<summary>
检查IP地址
</summary>
<param name="ip"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.Connect"> <member name="M:Asa.IOModule.AIOBOX.Connect">
<summary> <summary>
连接 连接
...@@ -120,26 +65,6 @@ ...@@ -120,26 +65,6 @@
关闭连接 关闭连接
</summary> </summary>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.AutoReadInput(System.Boolean,System.Int32)">
<summary>
自动读取输入端并触发事件(主动上传数据 = 禁止)
</summary>
<param name="read">是否自动读取</param>
<param name="sleep">间隔,必须大于等于15ms</param>
</member>
<member name="M:Asa.IOModule.AIOBOX.AutoReadInput(System.Boolean)">
<summary>
自动读取输入端并触发事件(主动上传数据 = 使能)
</summary>
<param name="read">是否自动读取</param>
</member>
<member name="M:Asa.IOModule.AIOBOX.AutoReadOutput(System.Boolean,System.Int32)">
<summary>
自动读取输出端,触发事件
</summary>
<param name="read">是否自动读取</param>
<param name="sleep">间隔,必须大于等于15ms</param>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReverseStatus(Asa.IOModule.Box_Sta)"> <member name="M:Asa.IOModule.AIOBOX.ReverseStatus(Asa.IOModule.Box_Sta)">
<summary> <summary>
相反状态(ON/OFF) 相反状态(ON/OFF)
...@@ -221,75 +146,68 @@ ...@@ -221,75 +146,68 @@
<param name="sta"></param> <param name="sta"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.GetLocalIP">
<summary>
获取本地IPv4地址
</summary>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.Send"> <member name="M:Asa.IOModule.AIOBOX.Send">
<summary> <summary>
发送命令 发送命令线程
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.Receive">
<summary>
接收命令
</summary> </summary>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.ReadSingle(System.Byte[])"> <member name="M:Asa.IOModule.AIOBOX.GetReadDI_Command">
<summary> <summary>
读取写入单个DO,功能码5 获取ReadDI的命令
</summary> </summary>
<param name="buff"></param> <returns></returns>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.ReadDO(System.Byte[])"> <member name="M:Asa.IOModule.AIOBOX.GetReadDO_Command">
<summary> <summary>
读取所有DO状态,功能码1 获取ReadDO的命令
</summary> </summary>
<param name="buff"></param> <returns></returns>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.ReadDI(System.Byte[])"> <member name="M:Asa.IOModule.AIOBOX.Listen">
<summary> <summary>
读取所有DI状态,功能码2 监听网络线程
</summary> </summary>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.ReadAI(System.Byte[])"> <member name="M:Asa.IOModule.AIOBOX.CommandProcess(System.Byte[])">
<summary> <summary>
读取所有AI的值,功能码4 接收到的命令处理方法,(task多线程)
</summary> </summary>
<param name="buff"></param> <param name="cmd"></param>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.Command"> <member name="M:Asa.IOModule.AIOBOX.Reconn">
<summary> <summary>
命令,前7个字节 重连线程
</summary> </summary>
<returns></returns>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.TriggerDIO"> <member name="M:Asa.IOModule.AIOBOX.Open">
<summary> <summary>
触发DIO改变事件 打开socket建立连接
</summary> </summary>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.AutoReadInput"> <member name="M:Asa.IOModule.AIOBOX.CheckIP(System.String)">
<summary> <summary>
自动读取输入端线程 检查IP地址
</summary> </summary>
<param name="ip"></param>
<returns></returns>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.AutoReadOutput"> <member name="M:Asa.IOModule.AIOBOX.AutoIP(System.String)">
<summary> <summary>
自动读取输出端线程 自动获取IP地址,未连接前使用,必须在同一网段
</summary> </summary>
<param name="localIP">本地IP地址</param>
<returns></returns>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.Listen"> <member name="M:Asa.IOModule.AIOBOX.GetIP">
<summary> <summary>
监听结果线程 获取IO模块IP地址
</summary> </summary>
</member> </member>
<member name="M:Asa.IOModule.AIOBOX.TestMethod"> <member name="M:Asa.IOModule.AIOBOX.Command">
<summary> <summary>
测试方法锁 命令,前7个字节
</summary> </summary>
<returns></returns>
</member> </member>
<member name="T:Asa.IOModule.Box_Type"> <member name="T:Asa.IOModule.Box_Type">
<summary> <summary>
...@@ -331,62 +249,5 @@ ...@@ -331,62 +249,5 @@
闭合,打开,高电平 闭合,打开,高电平
</summary> </summary>
</member> </member>
<member name="T:Asa.IOModule.LogType">
<summary>
日志类型
</summary>
</member>
<member name="F:Asa.IOModule.LogType.OnlyError">
<summary>
仅错误信息
</summary>
</member>
<member name="F:Asa.IOModule.LogType.All">
<summary>
所有
</summary>
</member>
<member name="T:Asa.IOModule.LogFile">
<summary>
日志操作类
</summary>
</member>
<member name="M:Asa.IOModule.LogFile.#ctor(System.String,System.String)">
<summary>
日志
</summary>
<param name="path">文件夹路径</param>
<param name="ip"></param>
</member>
<member name="M:Asa.IOModule.LogFile.Close">
<summary>
关闭文件
</summary>
</member>
<member name="M:Asa.IOModule.LogFile.OutError(System.String)">
<summary>
输出错误
</summary>
<param name="s"></param>
</member>
<member name="M:Asa.IOModule.LogFile.OutInfo(System.String)">
<summary>
输出信息
</summary>
<param name="s"></param>
</member>
<member name="M:Asa.IOModule.LogFile.OutData(System.String,System.Byte[])">
<summary>
输出数据
</summary>
<param name="tr"></param>
<param name="buff"></param>
</member>
<member name="M:Asa.IOModule.LogFile.OutData(System.String)">
<summary>
输出数据
</summary>
<param name="s"></param>
</member>
</members> </members>
</doc> </doc>
9428b515b65d7e804ec8e058ca7770707ab7571d 6b9117074f0ff97736a34c4c150b6b18b33edbb4
...@@ -39,3 +39,10 @@ D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\AIOBOX.csp ...@@ -39,3 +39,10 @@ D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\AIOBOX.csp
D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\AIOBOX.csproj.CoreCompileInputs.cache D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\AIOBOX.csproj.CoreCompileInputs.cache
D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\Asa.IOModule.AIOBOX.dll D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\Asa.IOModule.AIOBOX.dll
D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\Asa.IOModule.AIOBOX.pdb D:\OneDrive - 上海挚锦科技有限公司\SMD\DLL\AIOBOX\obj\Debug\Asa.IOModule.AIOBOX.pdb
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\bin\Debug\Asa.IOModule.AIOBOX.xml
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\bin\Debug\Asa.IOModule.AIOBOX.dll
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\bin\Debug\Asa.IOModule.AIOBOX.pdb
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\obj\Debug\AIOBOX.csproj.CoreCompileInputs.cache
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\obj\Debug\Asa.IOModule.AIOBOX.dll
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\obj\Debug\Asa.IOModule.AIOBOX.pdb
D:\OneDrive - 上海挚锦科技有限公司\SMD\AIOBOX\AIOBOX\obj\Debug\AIOBOX.csprojAssemblyReference.cache
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!