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

777 lines
33 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using HslCommunication.Core;
using HslCommunication.Serial;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.BasicFramework;
namespace HslCommunication.Profinet.Melsec
{
/// <summary>
/// 三菱的串口通信的对象适用于读取FX系列的串口数据支持的类型参考文档说明
/// </summary>
/// <remarks>
/// 字读写地址支持的列表如下:
/// <list type="table">
/// <listheader>
/// <term>地址名称</term>
/// <term>地址代号</term>
/// <term>示例</term>
/// <term>地址范围</term>
/// <term>地址进制</term>
/// <term>备注</term>
/// </listheader>
/// <item>
/// <term>数据寄存器</term>
/// <term>D</term>
/// <term>D100,D200</term>
/// <term>D0-D511,D8000-D8255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>定时器的值</term>
/// <term>TN</term>
/// <term>TN10,TN20</term>
/// <term>TN0-TN255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>计数器的值</term>
/// <term>CN</term>
/// <term>CN10,CN20</term>
/// <term>CN0-CN199,CN200-CN255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// </list>
/// 位地址支持的列表如下:
/// <list type="table">
/// <listheader>
/// <term>地址名称</term>
/// <term>地址代号</term>
/// <term>示例</term>
/// <term>地址范围</term>
/// <term>地址进制</term>
/// <term>备注</term>
/// </listheader>
/// <item>
/// <term>内部继电器</term>
/// <term>M</term>
/// <term>M100,M200</term>
/// <term>M0-M1023,M8000-M8255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>输入继电器</term>
/// <term>X</term>
/// <term>X1,X20</term>
/// <term>X0-X177</term>
/// <term>8</term>
/// <term></term>
/// </item>
/// <item>
/// <term>输出继电器</term>
/// <term>Y</term>
/// <term>Y10,Y20</term>
/// <term>Y0-Y177</term>
/// <term>8</term>
/// <term></term>
/// </item>
/// <item>
/// <term>步进继电器</term>
/// <term>S</term>
/// <term>S100,S200</term>
/// <term>S0-S999</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>定时器触点</term>
/// <term>TS</term>
/// <term>TS10,TS20</term>
/// <term>TS0-TS255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>定时器线圈</term>
/// <term>TC</term>
/// <term>TC10,TC20</term>
/// <term>TC0-TC255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>计数器触点</term>
/// <term>CS</term>
/// <term>CS10,CS20</term>
/// <term>CS0-CS255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// <item>
/// <term>计数器线圈</term>
/// <term>CC</term>
/// <term>CC10,CC20</term>
/// <term>CC0-CC255</term>
/// <term>10</term>
/// <term></term>
/// </item>
/// </list>
/// </remarks>
/// <example>
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecFxSerial.cs" region="Usage" title="简单的使用" />
/// </example>
public class MelsecFxSerial : SerialDeviceBase<RegularByteTransform>
{
#region Constructor
/// <summary>
/// 实例化三菱的串口协议的通讯对象
/// </summary>
public MelsecFxSerial( )
{
WordLength = 1;
}
#endregion
#region Check Response
private OperateResult CheckPlcReadResponse( byte[] ack )
{
if (ack.Length == 0) return new OperateResult( StringResources.Language.MelsecFxReceiveZore );
if (ack[0] == 0x15) return new OperateResult( StringResources.Language.MelsecFxAckNagative + " Actual: " + SoftBasic.ByteToHexString( ack, ' ' ) );
if (ack[0] != 0x02) return new OperateResult( StringResources.Language.MelsecFxAckWrong + ack[0] + " Actual: " + SoftBasic.ByteToHexString( ack, ' ' ) );
if (!MelsecHelper.CheckCRC( ack )) return new OperateResult( StringResources.Language.MelsecFxCrcCheckFailed );
return OperateResult.CreateSuccessResult( );
}
private OperateResult CheckPlcWriteResponse( byte[] ack )
{
if (ack.Length == 0) return new OperateResult( StringResources.Language.MelsecFxReceiveZore );
if (ack[0] == 0x15) return new OperateResult( StringResources.Language.MelsecFxAckNagative + " Actual: " + SoftBasic.ByteToHexString( ack, ' ' ) );
if (ack[0] != 0x06) return new OperateResult( StringResources.Language.MelsecFxAckWrong + ack[0] + " Actual: " + SoftBasic.ByteToHexString( ack, ' ' ) );
return OperateResult.CreateSuccessResult( );
}
#endregion
#region Read Support
/// <summary>
/// 从三菱PLC中读取想要的数据返回读取结果
/// </summary>
/// <param name="address">读取地址,,支持的类型参考文档说明</param>
/// <param name="length">读取的数据长度</param>
/// <returns>带成功标志的结果数据对象</returns>
/// <example>
/// 假设起始地址为D100D100存储了温度100.6℃值为1006D101存储了压力1.23Mpa值为123D102D103存储了产量计数读取如下
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecFxSerial.cs" region="ReadExample2" title="Read示例" />
/// 以下是读取不同类型数据的示例
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecFxSerial.cs" region="ReadExample1" title="Read示例" />
/// </example>
public override OperateResult<byte[]> Read( string address, ushort length )
{
// 获取指令
OperateResult<byte[]> command = BuildReadWordCommand( address, length );
if (!command.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( command );
// 核心交互
OperateResult<byte[]> read = ReadBase( command.Content );
if (!read.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( read );
// 反馈检查
OperateResult ackResult = CheckPlcReadResponse( read.Content );
if (!ackResult.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( ackResult );
// 数据提炼
return ExtractActualData( read.Content );
}
/// <summary>
/// 从三菱PLC中批量读取位软元件返回读取结果该读取地址最好从01632...等开始读取,这样可以读取比较长得数据数组
/// </summary>
/// <param name="address">起始地址</param>
/// <param name="length">读取的长度</param>
/// <returns>带成功标志的结果数据对象</returns>
/// <example>
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecFxSerial.cs" region="ReadBool" title="Bool类型示例" />
/// </example>
public OperateResult<bool[]> ReadBool( string address, ushort length )
{
//获取指令
OperateResult<byte[], int> command = BuildReadBoolCommand( address, length );
if (!command.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( command );
// 核心交互
OperateResult<byte[]> read = ReadBase( command.Content1 );
if (!read.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( read );
// 反馈检查
OperateResult ackResult = CheckPlcReadResponse( read.Content );
if (!ackResult.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( ackResult );
// 提取真实的数据
return ExtractActualBoolData( read.Content, command.Content2, length );
}
/// <summary>
/// 从三菱PLC中批量读取位软元件返回读取结果
/// </summary>
/// <param name="address">起始地址</param>
/// <returns>带成功标志的结果数据对象</returns>
/// <example>参照 <see cref="ReadBool(string, ushort)"/> 方法 </example>
public OperateResult<bool> ReadBool( string address )
{
OperateResult<bool[]> read = ReadBool( address, 1 );
if (!read.IsSuccess) return OperateResult.CreateFailedResult<bool>( read );
return OperateResult.CreateSuccessResult<bool>( read.Content[0] );
}
#endregion
#region Write Override
/// <summary>
/// 向PLC写入数据数据格式为原始的字节类型
/// </summary>
/// <param name="address">初始地址,支持的类型参考文档说明</param>
/// <param name="value">原始的字节数据</param>
/// <example>
/// 假设起始地址为D100D100存储了温度100.6℃值为1006D101存储了压力1.23Mpa值为123D102D103存储了产量计数写入如下
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecFxSerial.cs" region="WriteExample2" title="Write示例" />
/// 以下是读取不同类型数据的示例
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecFxSerial.cs" region="WriteExample1" title="Write示例" />
/// </example>
/// <returns>是否写入成功的结果对象</returns>
public override OperateResult Write( string address, byte[] value )
{
// 获取写入
OperateResult<byte[]> command = BuildWriteWordCommand( address, value );
if (!command.IsSuccess) return command;
// 核心交互
OperateResult<byte[]> read = ReadBase( command.Content );
if (!read.IsSuccess) return read;
// 结果验证
OperateResult checkResult = CheckPlcWriteResponse( read.Content );
if (!checkResult.IsSuccess) return checkResult;
return OperateResult.CreateSuccessResult( );
}
#endregion
#region Write Bool
/// <summary>
/// 强制写入位数据的通断,支持的类型参考文档说明
/// </summary>
/// <param name="address">地址信息</param>
/// <param name="value">是否为通</param>
/// <returns>是否写入成功的结果对象</returns>
public OperateResult Write( string address, bool value )
{
// 先获取指令
OperateResult<byte[]> command = BuildWriteBoolPacket( address, value );
if (!command.IsSuccess) return command;
// 和串口进行核心的数据交互
OperateResult<byte[]> read = ReadBase( command.Content );
if (!read.IsSuccess) return read;
// 检查结果是否正确
OperateResult checkResult = CheckPlcWriteResponse( read.Content );
if (!checkResult.IsSuccess) return checkResult;
return OperateResult.CreateSuccessResult( );
}
#endregion
#region Object Override
/// <summary>
/// 获取当前对象的字符串标识形式
/// </summary>
/// <returns>字符串信息</returns>
public override string ToString( )
{
return "MelsecFxSerial";
}
#endregion
#region Static Method Helper
/// <summary>
/// 生成位写入的数据报文信息该报文可直接用于发送串口给PLC
/// </summary>
/// <param name="address">地址信息每个地址存在一定的范围需要谨慎传入数据。举例M10,S10,X5,Y10,C10,T10</param>
/// <param name="value"><c>True</c>或是<c>False</c></param>
/// <returns>带报文信息的结果对象</returns>
public static OperateResult<byte[]> BuildWriteBoolPacket( string address, bool value )
{
var analysis = FxAnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( analysis );
// 二次运算起始地址偏移量,根据类型的不同,地址的计算方式不同
ushort startAddress = analysis.Content2;
if (analysis.Content1 == MelsecMcDataType.M)
{
if (startAddress >= 8000)
{
startAddress = (ushort)(startAddress - 8000 + 0x0F00);
}
else
{
startAddress = (ushort)(startAddress + 0x0800);
}
}
else if (analysis.Content1 == MelsecMcDataType.S)
{
startAddress = (ushort)(startAddress + 0x0000);
}
else if (analysis.Content1 == MelsecMcDataType.X)
{
startAddress = (ushort)(startAddress + 0x0400);
}
else if (analysis.Content1 == MelsecMcDataType.Y)
{
startAddress = (ushort)(startAddress + 0x0500);
}
else if (analysis.Content1 == MelsecMcDataType.CS)
{
startAddress += (ushort)(startAddress + 0x01C0);
}
else if (analysis.Content1 == MelsecMcDataType.CC)
{
startAddress += (ushort)(startAddress + 0x03C0);
}
else if (analysis.Content1 == MelsecMcDataType.CN)
{
startAddress += (ushort)(startAddress + 0x0E00);
}
else if (analysis.Content1 == MelsecMcDataType.TS)
{
startAddress += (ushort)(startAddress + 0x00C0);
}
else if (analysis.Content1 == MelsecMcDataType.TC)
{
startAddress += (ushort)(startAddress + 0x02C0);
}
else if (analysis.Content1 == MelsecMcDataType.TN)
{
startAddress += (ushort)(startAddress + 0x0600);
}
else
{
return new OperateResult<byte[]>( StringResources.Language.MelsecCurrentTypeNotSupportedBitOperate );
}
byte[] _PLCCommand = new byte[9];
_PLCCommand[0] = 0x02; // STX
_PLCCommand[1] = value ? (byte)0x37 : (byte)0x38; // Read
_PLCCommand[2] = SoftBasic.BuildAsciiBytesFrom( startAddress )[2]; // 偏移地址
_PLCCommand[3] = SoftBasic.BuildAsciiBytesFrom( startAddress )[3];
_PLCCommand[4] = SoftBasic.BuildAsciiBytesFrom( startAddress )[0];
_PLCCommand[5] = SoftBasic.BuildAsciiBytesFrom( startAddress )[1];
_PLCCommand[6] = 0x03; // ETX
MelsecHelper.FxCalculateCRC( _PLCCommand ).CopyTo( _PLCCommand, 7 ); // CRC
return OperateResult.CreateSuccessResult( _PLCCommand );
}
/// <summary>
/// 根据类型地址长度确认需要读取的指令头
/// </summary>
/// <param name="address">起始地址</param>
/// <param name="length">长度</param>
/// <returns>带有成功标志的指令数据</returns>
public static OperateResult<byte[]> BuildReadWordCommand( string address, ushort length )
{
var addressResult = FxCalculateWordStartAddress( address );
if (!addressResult.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( addressResult );
length = (ushort)(length * 2);
ushort startAddress = addressResult.Content;
byte[] _PLCCommand = new byte[11];
_PLCCommand[0] = 0x02; // STX
_PLCCommand[1] = 0x30; // Read
_PLCCommand[2] = SoftBasic.BuildAsciiBytesFrom( startAddress )[0]; // 偏移地址
_PLCCommand[3] = SoftBasic.BuildAsciiBytesFrom( startAddress )[1];
_PLCCommand[4] = SoftBasic.BuildAsciiBytesFrom( startAddress )[2];
_PLCCommand[5] = SoftBasic.BuildAsciiBytesFrom( startAddress )[3];
_PLCCommand[6] = SoftBasic.BuildAsciiBytesFrom( (byte)length )[0]; // 读取长度
_PLCCommand[7] = SoftBasic.BuildAsciiBytesFrom( (byte)length )[1];
_PLCCommand[8] = 0x03; // ETX
MelsecHelper.FxCalculateCRC( _PLCCommand ).CopyTo( _PLCCommand, 9 ); // CRC
return OperateResult.CreateSuccessResult( _PLCCommand ); // Return
}
/// <summary>
/// 根据类型地址长度确认需要读取的指令头
/// </summary>
/// <param name="address">起始地址</param>
/// <param name="length">bool数组长度</param>
/// <returns>带有成功标志的指令数据</returns>
public static OperateResult<byte[], int> BuildReadBoolCommand( string address, ushort length )
{
var addressResult = FxCalculateBoolStartAddress( address );
if (!addressResult.IsSuccess) return OperateResult.CreateFailedResult<byte[], int>( addressResult );
// 计算下实际需要读取的数据长度
ushort length2 = (ushort)((addressResult.Content2 + length - 1) / 8 - (addressResult.Content2 / 8) + 1);
ushort startAddress = addressResult.Content1;
byte[] _PLCCommand = new byte[11];
_PLCCommand[0] = 0x02; // STX
_PLCCommand[1] = 0x30; // Read
_PLCCommand[2] = SoftBasic.BuildAsciiBytesFrom( startAddress )[0]; // 偏移地址
_PLCCommand[3] = SoftBasic.BuildAsciiBytesFrom( startAddress )[1];
_PLCCommand[4] = SoftBasic.BuildAsciiBytesFrom( startAddress )[2];
_PLCCommand[5] = SoftBasic.BuildAsciiBytesFrom( startAddress )[3];
_PLCCommand[6] = SoftBasic.BuildAsciiBytesFrom( (byte)length2 )[0]; // 读取长度
_PLCCommand[7] = SoftBasic.BuildAsciiBytesFrom( (byte)length2 )[1];
_PLCCommand[8] = 0x03; // ETX
MelsecHelper.FxCalculateCRC( _PLCCommand ).CopyTo( _PLCCommand, 9 ); // CRC
return OperateResult.CreateSuccessResult( _PLCCommand, (int)addressResult.Content3 );
}
/// <summary>
/// 根据类型地址以及需要写入的数据来生成指令头
/// </summary>
/// <param name="address">起始地址</param>
/// <param name="value">实际的数据信息</param>
/// <returns>带有成功标志的指令数据</returns>
public static OperateResult<byte[]> BuildWriteWordCommand( string address, byte[] value )
{
var addressResult = FxCalculateWordStartAddress( address );
if (!addressResult.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( addressResult );
// 字节数据转换成ASCII格式
if (value != null) value = SoftBasic.BuildAsciiBytesFrom( value );
ushort startAddress = addressResult.Content;
byte[] _PLCCommand = new byte[11 + value.Length];
_PLCCommand[0] = 0x02; // STX
_PLCCommand[1] = 0x31; // Read
_PLCCommand[2] = SoftBasic.BuildAsciiBytesFrom( startAddress )[0]; // Offect Address
_PLCCommand[3] = SoftBasic.BuildAsciiBytesFrom( startAddress )[1];
_PLCCommand[4] = SoftBasic.BuildAsciiBytesFrom( startAddress )[2];
_PLCCommand[5] = SoftBasic.BuildAsciiBytesFrom( startAddress )[3];
_PLCCommand[6] = SoftBasic.BuildAsciiBytesFrom( (byte)(value.Length / 2) )[0]; // Read Length
_PLCCommand[7] = SoftBasic.BuildAsciiBytesFrom( (byte)(value.Length / 2) )[1];
Array.Copy( value, 0, _PLCCommand, 8, value.Length );
_PLCCommand[_PLCCommand.Length - 3] = 0x03; // ETX
MelsecHelper.FxCalculateCRC( _PLCCommand ).CopyTo( _PLCCommand, _PLCCommand.Length - 2 ); // CRC
return OperateResult.CreateSuccessResult( _PLCCommand );
}
/// <summary>
/// 从PLC反馈的数据进行提炼操作
/// </summary>
/// <param name="response">PLC反馈的真实数据</param>
/// <returns>数据提炼后的真实数据</returns>
public static OperateResult<byte[]> ExtractActualData( byte[] response )
{
try
{
byte[] data = new byte[(response.Length - 4) / 2];
for (int i = 0; i < data.Length; i++)
{
byte[] buffer = new byte[2];
buffer[0] = response[i * 2 + 1];
buffer[1] = response[i * 2 + 2];
data[i] = Convert.ToByte( Encoding.ASCII.GetString( buffer ), 16 );
}
return OperateResult.CreateSuccessResult( data );
}
catch (Exception ex)
{
return new OperateResult<byte[]>( )
{
Message = "Extract Msg" + ex.Message + Environment.NewLine +
"Data: " + BasicFramework.SoftBasic.ByteToHexString( response )
};
}
}
/// <summary>
/// 从PLC反馈的数据进行提炼bool数组操作
/// </summary>
/// <param name="response">PLC反馈的真实数据</param>
/// <param name="start">起始提取的点信息</param>
/// <param name="length">bool数组的长度</param>
/// <returns>数据提炼后的真实数据</returns>
public static OperateResult<bool[]> ExtractActualBoolData( byte[] response, int start, int length )
{
OperateResult<byte[]> extraResult = ExtractActualData( response );
if (!extraResult.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( extraResult );
// 转化bool数组
try
{
bool[] data = new bool[length];
bool[] array = BasicFramework.SoftBasic.ByteToBoolArray( extraResult.Content, extraResult.Content.Length * 8 );
for (int i = 0; i < length; i++)
{
data[i] = array[i + start];
}
return OperateResult.CreateSuccessResult( data );
}
catch (Exception ex)
{
return new OperateResult<bool[]>( )
{
Message = "Extract Msg" + ex.Message + Environment.NewLine +
"Data: " + BasicFramework.SoftBasic.ByteToHexString( response )
};
}
}
/// <summary>
/// 解析数据地址成不同的三菱地址类型
/// </summary>
/// <param name="address">数据地址</param>
/// <returns>地址结果对象</returns>
private static OperateResult<MelsecMcDataType, ushort> FxAnalysisAddress( string address )
{
var result = new OperateResult<MelsecMcDataType, ushort>( );
try
{
switch (address[0])
{
case 'M':
case 'm':
{
result.Content1 = MelsecMcDataType.M;
result.Content2 = Convert.ToUInt16( address.Substring( 1 ), MelsecMcDataType.M.FromBase );
break;
}
case 'X':
case 'x':
{
result.Content1 = MelsecMcDataType.X;
result.Content2 = Convert.ToUInt16( address.Substring( 1 ), 8 );
break;
}
case 'Y':
case 'y':
{
result.Content1 = MelsecMcDataType.Y;
result.Content2 = Convert.ToUInt16( address.Substring( 1 ), 8 );
break;
}
case 'D':
case 'd':
{
result.Content1 = MelsecMcDataType.D;
result.Content2 = Convert.ToUInt16( address.Substring( 1 ), MelsecMcDataType.D.FromBase );
break;
}
case 'S':
case 's':
{
result.Content1 = MelsecMcDataType.S;
result.Content2 = Convert.ToUInt16( address.Substring( 1 ), MelsecMcDataType.S.FromBase );
break;
}
case 'T':
case 't':
{
if (address[1] == 'N' || address[1] == 'n')
{
result.Content1 = MelsecMcDataType.TN;
result.Content2 = Convert.ToUInt16( address.Substring( 2 ), MelsecMcDataType.TN.FromBase );
break;
}
else if (address[1] == 'S' || address[1] == 's')
{
result.Content1 = MelsecMcDataType.TS;
result.Content2 = Convert.ToUInt16( address.Substring( 2 ), MelsecMcDataType.TS.FromBase );
break;
}
else if (address[1] == 'C' || address[1] == 'c')
{
result.Content1 = MelsecMcDataType.TC;
result.Content2 = Convert.ToUInt16( address.Substring( 2 ), MelsecMcDataType.TC.FromBase );
break;
}
else
{
throw new Exception( StringResources.Language.NotSupportedDataType );
}
}
case 'C':
case 'c':
{
if (address[1] == 'N' || address[1] == 'n')
{
result.Content1 = MelsecMcDataType.CN;
result.Content2 = Convert.ToUInt16( address.Substring( 2 ), MelsecMcDataType.CN.FromBase );
break;
}
else if (address[1] == 'S' || address[1] == 's')
{
result.Content1 = MelsecMcDataType.CS;
result.Content2 = Convert.ToUInt16( address.Substring( 2 ), MelsecMcDataType.CS.FromBase );
break;
}
else if (address[1] == 'C' || address[1] == 'c')
{
result.Content1 = MelsecMcDataType.CC;
result.Content2 = Convert.ToUInt16( address.Substring( 2 ), MelsecMcDataType.CC.FromBase );
break;
}
else
{
throw new Exception( StringResources.Language.NotSupportedDataType );
}
}
default: throw new Exception( StringResources.Language.NotSupportedDataType );
}
}
catch (Exception ex)
{
result.Message = ex.Message;
return result;
}
result.IsSuccess = true;
return result;
}
/// <summary>
/// 返回读取的地址及长度信息
/// </summary>
/// <param name="address">读取的地址信息</param>
/// <returns>带起始地址的结果对象</returns>
private static OperateResult<ushort> FxCalculateWordStartAddress( string address )
{
// 初步解析,失败就返回
var analysis = FxAnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<ushort>( analysis );
// 二次解析
ushort startAddress = analysis.Content2;
if (analysis.Content1 == MelsecMcDataType.D)
{
if (startAddress >= 8000)
{
startAddress = (ushort)((startAddress - 8000) * 2 + 0x0E00);
}
else
{
startAddress = (ushort)(startAddress * 2 + 0x1000);
}
}
else if (analysis.Content1 == MelsecMcDataType.CN)
{
if (startAddress >= 200)
{
startAddress = (ushort)((startAddress - 200) * 4 + 0x0C00);
}
else
{
startAddress = (ushort)(startAddress * 2 + 0x0A00);
}
}
else if (analysis.Content1 == MelsecMcDataType.TN)
{
startAddress = (ushort)(startAddress * 2 + 0x0800);
}
else
{
return new OperateResult<ushort>( StringResources.Language.MelsecCurrentTypeNotSupportedWordOperate );
}
return OperateResult.CreateSuccessResult( startAddress );
}
/// <summary>
/// 返回读取的地址及长度信息,以及当前的偏置信息
/// </summary><param name="address">读取的地址信息</param>
/// <returns>带起始地址的结果对象</returns>
private static OperateResult<ushort, ushort, ushort> FxCalculateBoolStartAddress( string address )
{
// 初步解析
var analysis = FxAnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<ushort, ushort, ushort>( analysis );
// 二次解析
ushort startAddress = analysis.Content2;
if (analysis.Content1 == MelsecMcDataType.M)
{
if (startAddress >= 8000)
{
startAddress = (ushort)((startAddress - 8000) / 8 + 0x01E0);
}
else
{
startAddress = (ushort)(startAddress / 8 + 0x0100);
}
}
else if (analysis.Content1 == MelsecMcDataType.X)
{
startAddress = (ushort)(startAddress / 8 + 0x0080);
}
else if (analysis.Content1 == MelsecMcDataType.Y)
{
startAddress = (ushort)(startAddress / 8 + 0x00A0);
}
else if (analysis.Content1 == MelsecMcDataType.S)
{
startAddress = (ushort)(startAddress / 8 + 0x0000);
}
else if (analysis.Content1 == MelsecMcDataType.CS)
{
startAddress += (ushort)(startAddress / 8 + 0x01C0);
}
else if (analysis.Content1 == MelsecMcDataType.CC)
{
startAddress += (ushort)(startAddress / 8 + 0x03C0);
}
else if (analysis.Content1 == MelsecMcDataType.TS)
{
startAddress += (ushort)(startAddress / 8 + 0x00C0);
}
else if (analysis.Content1 == MelsecMcDataType.TC)
{
startAddress += (ushort)(startAddress / 8 + 0x02C0);
}
else
{
return new OperateResult<ushort, ushort, ushort>( StringResources.Language.MelsecCurrentTypeNotSupportedBitOperate );
}
return OperateResult.CreateSuccessResult( startAddress, analysis.Content2, ( ushort)(analysis.Content2 % 8) );
}
#endregion
}
}