Browse Source

add OMRON Udp drvier,fix bugs

pull/17/head
Gavin 9 years ago
parent
commit
73b6b15ed6
  1. 22
      SCADA/Program/DataExchange.sln
  2. 66
      SCADA/Program/ModbusDriver/ModbusTCPDriver.cs
  3. 55
      SCADA/Program/OmronPlcDriver/OmronPlcDriver.csproj
  4. 875
      SCADA/Program/OmronPlcDriver/OmronUdpReader.cs
  5. 36
      SCADA/Program/OmronPlcDriver/Properties/AssemblyInfo.cs
  6. BIN
      SCADA/dll/ModbusDriver.dll
  7. BIN
      SCADA/dll/OmronPlcDriver.dll

22
SCADA/Program/DataExchange.sln

@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagConfig", "TagConfig\TagC
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PanasonicDriver", "PanasonicDriver\PanasonicDriver.csproj", "{0D1C943D-594F-4E07-AA39-90CEC4E37C8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmronPlcDriver", "OmronPlcDriver\OmronPlcDriver.csproj", "{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -299,6 +301,26 @@ Global
{0D1C943D-594F-4E07-AA39-90CEC4E37C8E}.Release|x64.Build.0 = Release|Any CPU
{0D1C943D-594F-4E07-AA39-90CEC4E37C8E}.Release|x86.ActiveCfg = Release|Any CPU
{0D1C943D-594F-4E07-AA39-90CEC4E37C8E}.Release|x86.Build.0 = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|Itanium.ActiveCfg = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|Itanium.Build.0 = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|x64.ActiveCfg = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|x64.Build.0 = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|x86.ActiveCfg = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Debug|x86.Build.0 = Debug|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|Any CPU.Build.0 = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|Itanium.ActiveCfg = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|Itanium.Build.0 = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x64.ActiveCfg = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x64.Build.0 = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x86.ActiveCfg = Release|Any CPU
{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

66
SCADA/Program/ModbusDriver/ModbusTCPDriver.cs

@ -236,49 +236,53 @@ namespace ModbusDriver
return data;
}
object _async = new object();
private byte[] WriteSyncData(byte[] write_data)
{
short id = BitConverter.ToInt16(write_data, 0);
if (IsClosed) CallException(id, write_data[7], Modbus.excExceptionConnectionLost);
else
{
try
lock (_async)
{
tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
try
{
tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
byte function = tcpSynClBuffer[7];
byte[] data;
byte function = tcpSynClBuffer[7];
byte[] data;
if (result == 0) CallException(id, write_data[7], Modbus.excExceptionConnectionLost);
if (result == 0) CallException(id, write_data[7], Modbus.excExceptionConnectionLost);
// ------------------------------------------------------------
// Response data is slave ModbusModbus.exception
if (function > Modbus.excExceptionOffset)
{
function -= Modbus.excExceptionOffset;
CallException(id, function, tcpSynClBuffer[8]);
return null;
}
// ------------------------------------------------------------
// Write response data
else if ((function >= Modbus.fctWriteSingleCoil) && (function != Modbus.fctReadWriteMultipleRegister))
{
data = new byte[2];
Array.Copy(tcpSynClBuffer, 10, data, 0, 2);
// ------------------------------------------------------------
// Response data is slave ModbusModbus.exception
if (function > Modbus.excExceptionOffset)
{
function -= Modbus.excExceptionOffset;
CallException(id, function, tcpSynClBuffer[8]);
return null;
}
// ------------------------------------------------------------
// Write response data
else if ((function >= Modbus.fctWriteSingleCoil) && (function != Modbus.fctReadWriteMultipleRegister))
{
data = new byte[2];
Array.Copy(tcpSynClBuffer, 10, data, 0, 2);
}
// ------------------------------------------------------------
// Read response data
else
{
data = new byte[tcpSynClBuffer[8]];
Array.Copy(tcpSynClBuffer, 9, data, 0, tcpSynClBuffer[8]);
}
return data;
}
// ------------------------------------------------------------
// Read response data
else
catch (SocketException)
{
data = new byte[tcpSynClBuffer[8]];
Array.Copy(tcpSynClBuffer, 9, data, 0, tcpSynClBuffer[8]);
CallException(id, write_data[7], Modbus.excExceptionConnectionLost);
}
return data;
}
catch (SocketException)
{
CallException(id, write_data[7], Modbus.excExceptionConnectionLost);
}
}
return null;
@ -568,7 +572,7 @@ namespace ModbusDriver
byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
if (rcvBytes == null || rcvBytes.Length == 0)
{
offset += area.Len / 2;
//offset += area.Len / 2;
//_plcReader.Connect();
continue;
}

55
SCADA/Program/OmronPlcDriver/OmronPlcDriver.csproj

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OmronPlcDriver</RootNamespace>
<AssemblyName>OmronPlcDriver</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="OmronUdpReader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DataService\DataService.csproj">
<Project>{8965e389-6466-4b30-bd43-83c909044637}</Project>
<Name>DataService</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

875
SCADA/Program/OmronPlcDriver/OmronUdpReader.cs

@ -0,0 +1,875 @@
using DataService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Timers;
namespace OmronPlcDriver
{
[Description("Omron(CS/CJ) UDP协议")]
public sealed class OmronUdpReader : IPLCDriver, IMultiReadWrite
{
#region
/****************************************/
//更新人:新增_pdu,可以根据实际情况进行采集
//更新日期:20171205
//更新原因:根据现场进行参数调整以提供采集响应速度
/***************************************/
/// <summary>
/// PDU的值
/// </summary>
int _pdu;
/// <summary>
/// 获取PDU的值
/// </summary>
public int PDU
{
get { return _pdu; }
}
/// <summary>
/// 获取设备地址
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public DeviceAddress GetDeviceAddress(string address)
{
DeviceAddress dv = DeviceAddress.Empty;
if (string.IsNullOrEmpty(address))
return dv;
dv.Area = _plcNodeId;
switch (address[0])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctCIO;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(0, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address);
}
break;
case 'D'://DM区
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctDM;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(index + 1));
}
break;
case 'H'://HR区
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctHR;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(1));
}
break;
case 'A'://AR区
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctA;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(1));
}
break;
}
return dv;
}
public string GetAddress(DeviceAddress address)
{
return string.Empty;
}
#endregion
private int _timeout;//超时数据
private Socket udpSynCl;
private byte[] udpSynClBuffer = new byte[1024];
short _id;//驱动id
//驱动id
public short ID
{
get
{
return _id;
}
}
string _name;//驱动名称
/// <summary>
/// 驱动名称
/// </summary>
public string Name
{
get
{
return _name;
}
}
string _ip;//服务ip
int _port = 9600; //服务端口
public string ServerName
{
get { return _ip + ":" + _port; }
set
{
if (!string.IsNullOrEmpty(value))
{
int index = value.IndexOf(':');
_ip = value.Substring(0, index - 1);//ip地址
_port = int.Parse(value.Substring(index + 1));//端口号
}
}
}
/// <summary>
/// 是否关闭
/// </summary>
public bool IsClosed
{
get
{
return udpSynCl == null || udpSynCl.Connected == false;
}
}
/// <summary>
/// 超时时间
/// </summary>
public int TimeOut
{
get { return _timeout; }
set { _timeout = value; }
}
byte _plcNodeId;//plc节点号
/// <summary>
/// plc节点号,从para1参数读取
/// </summary>
public byte PlcNodeId
{
get { return _pcNodeId; }
set { _pcNodeId = value; }
}
byte _pcNodeId;//电脑节点号
/// <summary>
/// 电脑节点号,从para2参数读取
/// </summary>
public byte PcNodeId
{
get { return _pcNodeId; }
set { _pcNodeId = value; }
}
List<IGroup> _grps = new List<IGroup>(20);
public IEnumerable<IGroup> Groups
{
get { return _grps; }
}
IDataServer _server;
public IDataServer Parent
{
get { return _server; }
}
public OmronUdpReader(IDataServer server, short id, string name, string servername, int timeOut = 500, string spare1 = null, string spare2 = null)
{
_id = id;
_name = name;
_server = server;
if (!string.IsNullOrEmpty(servername))
{
int index = servername.IndexOf(':');
_ip = servername.Substring(0, index - 1);//ip地址
_port = int.Parse(servername.Substring(index + 1));//端口号
}
_timeout = timeOut;
byte.TryParse(spare1, out _plcNodeId);
byte.TryParse(spare2, out _pcNodeId);
}
/// <summary>
/// 连接
/// </summary>
/// <returns></returns>
public bool Connect()
{
try
{
if (udpSynCl != null)
udpSynCl.Close();
//IPAddress ip = IPAddress.Parse(_ip);
// ----------------------------------------------------------------
// Connect synchronous client
udpSynCl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Udp);
udpSynCl.SendTimeout = _timeout;
udpSynCl.ReceiveTimeout = _timeout;
udpSynCl.NoDelay = true;
udpSynCl.Connect(_ip, _port);
return true;
}
catch (SocketException error)
{
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(error.Message));
return false;
}
}
/// <summary>
/// 生成读命令头
/// </summary>
/// <param name="pcnode">电脑节点号,设置和PLC节点不一致即可</param>
/// <param name="startAddress">读取的起始地址</param>
/// <param name="length">读取长度</param>
/// <param name="function"></param>
/// <param name="plcnode">PLC节点号,可为0</param>
/// <returns></returns>
private byte[] CreateReadHeader(byte pcnode, int startAddress, ushort length, byte function, byte plcnode = 0)
{
byte[] data = new byte[18];
data[0] = 0x80;
data[1] = 0;
data[2] = 0; //80 00 02 固定帧头
data[2] = 0;
data[3] = plcnode;
data[5] = 0; //设备的网络号,节点号,单元号
data[6] = 0;
data[7] = pcnode;
data[8] = 0; //PC的网络号,节点号,单元号
data[9] = 0;
data[10] = 1;
data[11] = 1; //SID+MRC+SRC
data[12] = function; //数据区代码
byte[] _adr = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)startAddress));
data[13] = _adr[0]; // 首地址高字节
data[14] = _adr[1]; // 首地址低字节
data[15] = 0; // 固定0
byte[] _length = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)length));
data[16] = _length[0]; // 读取数量高字节
data[17] = _length[1]; // 读取数量低字节
return data;
}
/// <summary>
/// 生成写命令头
/// </summary>
/// <param name="id"></param>
/// <param name="startAddress"></param>
/// <param name="numData"></param>
/// <param name="length"></param>
/// <param name="function"></param>
/// <returns></returns>
private byte[] CreateWriteHeader(byte pcnode, int startAddress, ushort numData, byte function, byte plcnode = 0)
{
byte[] data = new byte[numData + 18];
data[0] = 0x80;
data[1] = 0;
data[2] = 0; //80 00 02 固定帧头
data[3] = 0;
data[4] = plcnode;
data[5] = 0; //设备的网络号,节点号,单元号
data[6] = 0;
data[7] = pcnode;
data[8] = 0; //PC的网络号,节点号,单元号
data[9] = 0;
data[10] = 1;
data[11] = 2; //SID+MRC+SRC
data[12] = function; //数据区代码
byte[] _adr = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)startAddress));
data[13] = _adr[0]; // 首地址高字节
data[14] = _adr[1]; // 首地址低字节
data[15] = 0; // 固定0
byte[] length = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)numData / 2));
data[16] = length[0]; // 写取数量高字节
data[17] = length[1]; // 写取数量低字节
return data;
}
/// <summary>
/// 同步写数据到udp
/// </summary>
/// <param name="write_data">写的字节数组</param>
/// <returns></returns>
private byte[] WriteSyncData(byte[] write_data)
{
short id = BitConverter.ToInt16(write_data, 4);
if (IsClosed) CallException(id, write_data[12], OmronCSCJ.excExceptionConnectionLost);
else
{
try
{
udpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);//是否存在lock的问题?
int result = udpSynCl.Receive(udpSynClBuffer, 0, 1024, SocketFlags.None);
byte function = udpSynClBuffer[11];//读写功能
byte[] data;
int err = udpSynClBuffer[12] * 256 + udpSynClBuffer[13];
if (result == 0) CallException(id, write_data[12], OmronCSCJ.excExceptionConnectionLost);
// ------------------------------------------------------------
// Response data is slave ModbusModbus.exception
if (err != 0)
{
CallException(id, function, 4);
return null;
}
// ------------------------------------------------------------
// Write response data
else if (function == 0x2)
{
data = new byte[2];
Array.Copy(udpSynClBuffer, 10, data, 0, 2);
}
// ------------------------------------------------------------
// Read response data
else
{
data = new byte[(write_data[16] * 256 + write_data[17]) * 2];
Array.Copy(udpSynClBuffer, 14, data, 0, data.Length);
}
return data;
}
catch (SocketException)
{
CallException(id, write_data[12], OmronCSCJ.excExceptionConnectionLost);
}
}
return null;
}
/// <summary>
/// 写单个寄存器
/// </summary>
/// <param name="pcnode">电脑节点号</param>
/// <param name="startAddress">起始地址</param>
/// <param name="function">内存区功能吗</param>
/// <param name="values">写值数组</param>
/// <param name="plcnode">plc节点号</param>
/// <returns></returns>
public byte[] WriteSingleRegister(byte pcnode, int startAddress, byte function, byte[] values, byte plcnode = 0)
{
byte[] data;
data = CreateWriteHeader(pcnode, startAddress, 2, function, plcnode);
data[19] = values[0];
data[20] = values[1];
return WriteSyncData(data);
}
/// <summary>
/// 写多个寄存器
/// </summary>
/// <param name="pcnode">电脑节点号</param>
/// <param name="startAddress">起始地址</param>
/// <param name="function">内存区功能号</param>
/// <param name="values">写值数组</param>
/// <param name="plcnode">plc节点号</param>
/// <returns></returns>
public byte[] WriteMultipleRegister(byte pcnode, int startAddress, byte function, byte[] values, byte plcnode = 0)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes % 2 > 0) numBytes++;
byte[] data;
data = CreateWriteHeader(pcnode, startAddress, numBytes, function, plcnode);
Array.Copy(values, 0, data, 19, values.Length);
return WriteSyncData(data);
}
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
OmronUdpGroup grp = new OmronUdpGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
public bool RemoveGroup(IGroup grp)
{
grp.IsActive = false;
return _grps.Remove(grp);
}
public void Dispose()
{
if (udpSynCl != null)
{
try { udpSynCl.Shutdown(SocketShutdown.Both); }
catch { }
udpSynCl.Close();
udpSynCl = null;
}
foreach (IGroup grp in _grps)
{
grp.Dispose();
}
_grps.Clear();
}
internal string GetErrorString(byte exception)
{
switch (exception)
{
case OmronCSCJ.excIllegalFunction:
return "Constant for OmronCSCJ.exception illegal function.";
case OmronCSCJ.excIllegalDataAdr:
return "Constant for OmronCSCJ.exception illegal data address.";
case OmronCSCJ.excIllegalDataVal:
return "Constant for OmronCSCJ.exception illegal data value.";
case OmronCSCJ.excSlaveDeviceFailure:
return "Constant for OmronCSCJ.exception slave device failure.";
case OmronCSCJ.excAck:
return "Constant for OmronCSCJ.exception acknowledge.";
case OmronCSCJ.excSlaveIsBusy:
return "Constant for OmronCSCJ.exception slave is busy/booting up.";
case OmronCSCJ.excGatePathUnavailable:
return "Constant for OmronCSCJ.exception gate path unavailable.";
case OmronCSCJ.excExceptionNotConnected:
return "Constant for OmronCSCJ.exception not connected.";
case OmronCSCJ.excExceptionConnectionLost:
return "Constant for OmronCSCJ.exception connection lost.";
case OmronCSCJ.excExceptionTimeout:
return "Constant for OmronCSCJ.exception response timeout.";
case OmronCSCJ.excExceptionOffset:
return "Constant for OmronCSCJ.exception wrong offset.";
case OmronCSCJ.excSendFailt:
return "Constant for OmronCSCJ.exception send failt.";
}
return string.Empty;
}
internal void CallException(int id, byte function, byte exception)
{
if (udpSynCl == null) return;
if (exception == OmronCSCJ.excExceptionConnectionLost && IsClosed == false)
{
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(GetErrorString(exception)));
}
}
/// <summary>
/// 读取字节数组
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <param name="size">长度</param>
/// <returns></returns>
public byte[] ReadBytes(DeviceAddress address, ushort size)
{
ushort len = size;
if (len % 2 != 0)
{
len++;
}
return WriteSyncData(CreateReadHeader(PcNodeId, address.Start, (ushort)(len / 2), (byte)address.DBNumber, (byte)address.Area));
}
/// <summary>
/// 读取32位整数
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <returns></returns>
public ItemData<int> ReadInt32(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 2, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData<int>(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData<int>(IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0)), 0, QUALITIES.QUALITY_GOOD);
}
/// <summary>
/// 读取16位整数
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <returns></returns>
public ItemData<short> ReadInt16(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData<short>(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData<short>(IPAddress.HostToNetworkOrder(BitConverter.ToInt16(data, 0)), 0, QUALITIES.QUALITY_GOOD);
}
/// <summary>
/// 读取1字节
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <returns></returns>
public ItemData<byte> ReadByte(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData<byte>(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData<byte>(data[0], 0, QUALITIES.QUALITY_GOOD);
}
/// <summary>
/// 读取字符串
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <param name="size">长度</param>
/// <returns></returns>
public ItemData<string> ReadString(DeviceAddress address, ushort size)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, size, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData<string>(string.Empty, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData<string>(Encoding.ASCII.GetString(data, 0, data.Length), 0, QUALITIES.QUALITY_GOOD);//是否考虑字节序问题?
}
/// <summary>
/// 读取32位浮点数
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <returns></returns>
public unsafe ItemData<float> ReadFloat(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 2, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData<float>(0.0f, 0, QUALITIES.QUALITY_BAD);
else
{
int value = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0));
return new ItemData<float>(*(((float*)&value)), 0, QUALITIES.QUALITY_GOOD);
}
}
/// <summary>
/// 读取1位
/// </summary>
/// <param name="address">标签变量地址结构体</param>
/// <returns></returns>
public ItemData<bool> ReadBit(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData<bool>(false, 0, QUALITIES.QUALITY_BAD);
if (data.Length == 1) return new ItemData<bool>(data[0] > 0, 0, QUALITIES.QUALITY_GOOD);
unsafe
{
fixed (byte* p = data)
{
short* p1 = (short*)p;
return new ItemData<bool>((*p1 & (1 << address.Bit.BitSwap()))
!= 0, 0, QUALITIES.QUALITY_GOOD);
}
}
}
/// <summary>
/// 读object类型
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public ItemData<object> ReadValue(DeviceAddress address)
{
return this.ReadValueEx(address);
}
/// <summary>
/// 写字节数组到设备
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <param name="bits">需写的字节数组</param>
/// <returns></returns>
public int WriteBytes(DeviceAddress address, byte[] bits)
{
var data = WriteMultipleRegister(PcNodeId, address.Start, (byte)address.DBNumber, bits, (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteBit(DeviceAddress address, bool bit)
{
ItemData<short> item = ReadInt16(address);
short value = (short)((bit ? 1 : 0) << (int)address.Bit);
short result = (short)(item.Value | value);
var data = WriteSingleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(result), (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteBits(DeviceAddress address, byte bits)
{
var data = WriteSingleRegister(PcNodeId, address.Start, (byte)address.DBNumber, new byte[] { bits }, (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteInt16(DeviceAddress address, short value)
{
var data = WriteSingleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(value), (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteInt32(DeviceAddress address, int value)
{
var data = WriteMultipleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(value), (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteFloat(DeviceAddress address, float value)
{
var data = WriteMultipleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(value), (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteString(DeviceAddress address, string str)
{
var data = WriteMultipleRegister(PcNodeId, address.Start, (byte)address.DBNumber, Encoding.ASCII.GetBytes(str), (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteValue(DeviceAddress address, object value)
{
return this.WriteValueEx(address, value);
}
public event ShutdownRequestEventHandler OnClose;
public int Limit
{
get { return 60; }
}
public ItemData<Storage>[] ReadMultiple(DeviceAddress[] addrsArr)
{
return this.PLCReadMultiple(new NetShortCacheReader(), addrsArr);
}
public int WriteMultiple(DeviceAddress[] addrArr, object[] buffer)
{
return this.PLCWriteMultiple(new NetShortCacheReader(), addrArr, buffer, Limit);
}
}
public sealed class OmronUdpGroup : PLCGroup
{
public OmronUdpGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
{
this._id = id;
this._name = name;
this._updateRate = updateRate;
this._isActive = active;
this._plcReader = plcReader;
this._server = _plcReader.Parent;
this._timer = new Timer();
this._changedList = new List<int>();
this._cacheReader = new NetShortCacheReader();
}
protected override unsafe void Poll()
{
short[] cache = (short[])_cacheReader.Cache;
int offset = 0;
foreach (PDUArea area in _rangeList)
{
byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
if (rcvBytes == null || rcvBytes.Length == 0)
{
//_plcReader.Connect();
continue;
}
else
{
int len = rcvBytes.Length / 2;
fixed (byte* p1 = rcvBytes)
{
short* prcv = (short*)p1;
int index = area.StartIndex;//index指向_items中的Tag元数据
int count = index + area.Count;
while (index < count)
{
DeviceAddress addr = _items[index].Address;
int iShort = addr.CacheIndex;
int iShort1 = iShort - offset;
if (addr.VarType == DataType.BOOL)
{
int tmp = prcv[iShort1] ^ cache[iShort];
DeviceAddress next = addr;
if (tmp != 0)
{
while (addr.Start == next.Start)
{
if ((tmp & (1 << next.Bit)) > 0) _changedList.Add(index);
if (++index < count)
next = _items[index].Address;
else
break;
}
}
else
{
while (addr.Start == next.Start && ++index < count)
{
next = _items[index].Address;
}
}
}
else
{
if (addr.DataSize <= 2)
{
if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
}
else
{
int size = addr.DataSize / 2;
for (int i = 0; i < size; i++)
{
if (prcv[iShort1 + i] != cache[iShort + i])
{
_changedList.Add(index);
break;
}
}
}
index++;
}
}
for (int j = 0; j < len; j++)
{
cache[j + offset] = prcv[j];
}//将PLC读取的数据写入到CacheReader中
}
offset += len;
}
}
}
}
/// <summary>
/// 欧姆龙Omron CS/CJ系列PLC数据区功能号和错误代码常数定义类
/// </summary>
public sealed class OmronCSCJ
{
/*****************************************************/
//OMRON PLC CS/CJ系列数据区功能号
/****************************************************/
/// <summary>
/// CIO 0000 to CIO 6143
/// </summary>
public const byte fctCIO = 0xB0;//CIO 0000 to CIO 6143
/// <summary>
/// H000 to H511
/// </summary>
public const byte fctHR = 0xB2;//H000 to H511
/// <summary>
/// A448 to A959
/// </summary>
public const byte fctA = 0xB3;//A448 to A959
/// <summary>
/// //D00000 to D32767
/// </summary>
public const byte fctDM = 0x82;//D00000 to D32767
/// <summary>
/// E0_E00000 to E0_E32765
/// </summary>
public const byte fctE0 = 0xA0;//E0_E00000 to E0_E32765
/// <summary>
/// E1_E00000 to E1_E32765
/// </summary>
public const byte fctE1 = 0xA1;//E1_E00000 to E1_E32765
/// <summary>
/// E2_E00000 to E2_E32765
/// </summary>
public const byte fctE2 = 0xA2;//E2_E00000 to E2_E32765
/// <summary>
/// E3_E00000 to E3_E32765
/// </summary>
public const byte fctE3 = 0xA3;
/// <summary>
/// E4_E00000 to E4_E32765
/// </summary>
public const byte fctE4 = 0xA4;//E4_E00000 to E4_E32765
/// <summary>
/// E5_E00000 to E5_E32765
/// </summary>
public const byte fctE5 = 0xA5;//E5_E00000 to E5_E32765
/// <summary>
/// E6_E00000 to E6_E32765
/// </summary>
public const byte fctE6 = 0xA6;//E6_E00000 to E6_E32765
/// <summary>
/// E7_E00000 to E7_E32765
/// </summary>
public const byte fctE7 = 0xA7;//E7_E00000 to E7_E32765
/// <summary>
/// E8_E00000 to E8_E32765
/// </summary>
public const byte fctE8 = 0xA8;//E8_E00000 to E8_E32765
/// <summary>
/// E9_E00000 to E9_E32765
/// </summary>
public const byte fctE9 = 0xA9;//E9_E00000 to E9_E32765
/// <summary>
/// EA_E00000 to EA_E32765
/// </summary>
public const byte fctEA = 0xAA;//EA_E00000 to EA_E32765
/// <summary>
/// EB_E00000 to EB_E32765
/// </summary>
public const byte fctEB = 0xAB;//EB_E00000 to EB_E32765
/// <summary>
/// EC_E00000 to EC_E32765
/// </summary>
public const byte fctEC = 0xAC;//EC_E00000 to EC_E32765
/// <summary>
/// E00000 to E32765
/// </summary>
public const byte fctCurrentbank = 98;//E00000 to E32765
/// <summary>Constant for exception illegal function.</summary>
public const byte excIllegalFunction = 1;
/// <summary>Constant for exception illegal data address.</summary>
public const byte excIllegalDataAdr = 2;
/// <summary>Constant for exception illegal data value.</summary>
public const byte excIllegalDataVal = 3;
/// <summary>Constant for exception slave device failure.</summary>
public const byte excSlaveDeviceFailure = 4;
/// <summary>Constant for exception acknowledge.</summary>
public const byte excAck = 5;
/// <summary>Constant for exception slave is busy/booting up.</summary>
public const byte excSlaveIsBusy = 6;
/// <summary>Constant for exception gate path unavailable.</summary>
public const byte excGatePathUnavailable = 10;
/// <summary>Constant for exception not connected.</summary>
public const byte excExceptionNotConnected = 253;
/// <summary>Constant for exception connection lost.</summary>
public const byte excExceptionConnectionLost = 254;
/// <summary>Constant for exception response timeout.</summary>
public const byte excExceptionTimeout = 255;
/// <summary>Constant for exception wrong offset.</summary>
public const byte excExceptionOffset = 128;
/// <summary>Constant for exception send failt.</summary>
public const byte excSendFailt = 100;
}
}

36
SCADA/Program/OmronPlcDriver/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OmronPlcDriver")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("OmronPlcDriver")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("baf8082b-8dd8-4e7c-9c5b-d9213e08c3b1")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

BIN
SCADA/dll/ModbusDriver.dll

Binary file not shown.

BIN
SCADA/dll/OmronPlcDriver.dll

Binary file not shown.
Loading…
Cancel
Save