You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
9.4 KiB
287 lines
9.4 KiB
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Mirle.Component.MPLC.MCProtocol
|
|
{
|
|
/// <summary>
|
|
/// Frame3E
|
|
/// </summary>
|
|
public class Frame3E
|
|
{
|
|
/// <summary>
|
|
/// 建構式
|
|
/// </summary>
|
|
public Frame3E()
|
|
{
|
|
_networkNo = 0;
|
|
_stationNo = 0;
|
|
}
|
|
/// <summary>
|
|
/// 建構式
|
|
/// </summary>
|
|
/// <param name="networkNo">網路編號</param>
|
|
/// <param name="stationNo">站點編號</param>
|
|
public Frame3E(int networkNo, int stationNo)
|
|
{
|
|
_networkNo = (byte)networkNo;
|
|
_stationNo = (byte)stationNo;
|
|
}
|
|
/// <summary>
|
|
/// 完成碼
|
|
/// </summary>
|
|
private struct CompleteCode
|
|
{
|
|
/// <summary>
|
|
/// 沒有資料
|
|
/// </summary>
|
|
public const int NoData = 0xF000;
|
|
/// <summary>
|
|
/// 有效資料
|
|
/// </summary>
|
|
public const int InvalidData = 0xF001;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private const byte _PCNo = 0xff;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private const byte _IONo_L = 0xff; //0x03ff
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private const byte _IONo_H = 0x03; //0x03ff
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private const byte _CPUTimer_L = 0x10; //0x0010
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private const byte _CPUTimer_H = 0x00;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private const int _receiceDataMinimumBytes = 11;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private readonly byte _networkNo = 0x00;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private readonly byte _stationNo = 0x00;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public readonly int MaximumWords = 960;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="mainCmd"></param>
|
|
/// <param name="subCmd"></param>
|
|
/// <param name="address"></param>
|
|
/// <param name="deviceCode"></param>
|
|
/// <param name="size"></param>
|
|
/// <param name="data"></param>
|
|
/// <returns></returns>
|
|
private byte[] CreateFrame(int mainCmd, int subCmd, int address, byte deviceCode, int size, IReadOnlyCollection<byte> data)
|
|
{
|
|
int dataLength = 12 + data.Count;
|
|
var frame = new List<byte>()
|
|
{
|
|
0x50, 0x00, //3E Frame
|
|
_networkNo,
|
|
_PCNo,
|
|
_IONo_L, _IONo_H,
|
|
_stationNo,
|
|
(byte)(dataLength % 256), (byte)(dataLength / 256),
|
|
_CPUTimer_L , _CPUTimer_H,
|
|
(byte)mainCmd, (byte)(mainCmd >> 8),
|
|
(byte)subCmd, (byte)(subCmd >> 8),
|
|
(byte)address, (byte)(address >> 8),
|
|
(byte)(address >> 16),
|
|
deviceCode,
|
|
(byte)size, (byte)(size >> 8),
|
|
};
|
|
frame.AddRange(data);
|
|
return frame.ToArray();
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="device"></param>
|
|
/// <param name="length"></param>
|
|
/// <returns></returns>
|
|
public byte[] CreateReadWordsFrame(MCDevice device, int length)
|
|
{
|
|
if (device == null && length < 1)
|
|
{
|
|
return null;
|
|
}
|
|
if (length > MaximumWords)
|
|
{
|
|
length = MaximumWords;
|
|
}
|
|
int mainCmd = 0x0401;
|
|
int subCmd = 0x0000;
|
|
int address = device.Address;
|
|
byte deviceCode = device.BinaryDeviceCode;
|
|
int size = length;
|
|
return CreateFrame(mainCmd, subCmd, address, deviceCode, size, new List<byte>());
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="device"></param>
|
|
/// <param name="data"></param>
|
|
/// <returns></returns>
|
|
public byte[] CreateWriteWordsFrame(MCDevice device, int[] data)
|
|
{
|
|
if (device == null && data == null)
|
|
{
|
|
return null;
|
|
}
|
|
int mainCmd = 0x1401;
|
|
int subCmd = 0x0000;
|
|
int address = device.Address;
|
|
byte deviceCode = device.BinaryDeviceCode;
|
|
int size = Math.Min(data.Length, MaximumWords);
|
|
var byteData = new List<byte>();
|
|
for (int i = 0; i < Math.Min(data.Length, MaximumWords); i++)
|
|
{
|
|
byteData.Add((byte)data[i]);
|
|
byteData.Add((byte)(data[i] >> 8));
|
|
}
|
|
return CreateFrame(mainCmd, subCmd, address, deviceCode, size, byteData);
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="device"></param>
|
|
/// <returns></returns>
|
|
public byte[] CreateReadBitFrame(MCDevice device)
|
|
{
|
|
if (device == null)
|
|
{
|
|
return null;
|
|
}
|
|
int mainCmd = 0x0401;
|
|
int subCmd = 0x0001;
|
|
int address = device.Address;
|
|
byte deviceCode = device.BinaryDeviceCode;
|
|
int size = 1;
|
|
return CreateFrame(mainCmd, subCmd, address, deviceCode, size, new List<byte>());
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="device"></param>
|
|
/// <param name="isOn"></param>
|
|
/// <returns></returns>
|
|
public byte[] CreateWriteBitFrame(MCDevice device, bool isOn)
|
|
{
|
|
if (device == null)
|
|
{
|
|
return null;
|
|
}
|
|
int mainCmd = 0x1401;
|
|
int subCmd = 0x0001;
|
|
int address = device.Address;
|
|
byte deviceCode = device.BinaryDeviceCode;
|
|
int size = 1;
|
|
var byteData = new List<byte>();
|
|
byteData.Add((byte)(isOn ? 0x10 : 0x00));
|
|
return CreateFrame(mainCmd, subCmd, address, deviceCode, size, byteData);
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="receiveData"></param>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public int ResolveReadBitReturnFrame(byte[] receiveData, out bool value)
|
|
{
|
|
if (receiveData == null || receiveData.Length < _receiceDataMinimumBytes)
|
|
{
|
|
value = false;
|
|
return CompleteCode.NoData;
|
|
}
|
|
ushort dataBytesLength = BitConverter.ToUInt16(receiveData, 7); //+ CompleteCode 2Bytes
|
|
ushort completeCode = BitConverter.ToUInt16(receiveData, 9);
|
|
if (receiveData.Length != 9 + dataBytesLength)
|
|
{
|
|
value = false;
|
|
return CompleteCode.InvalidData;
|
|
}
|
|
value = receiveData[11] == 0x10;
|
|
return completeCode;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="receiveData"></param>
|
|
/// <returns></returns>
|
|
public int ResolveWriteBitReturnFrame(byte[] receiveData)
|
|
{
|
|
if (receiveData == null || receiveData.Length < _receiceDataMinimumBytes)
|
|
{
|
|
return CompleteCode.NoData;
|
|
}
|
|
ushort dataBytesLength = BitConverter.ToUInt16(receiveData, 7); //+ CompleteCode 2Bytes
|
|
ushort completeCode = BitConverter.ToUInt16(receiveData, 9);
|
|
if (receiveData.Length != 9 + dataBytesLength)
|
|
{
|
|
return CompleteCode.InvalidData;
|
|
}
|
|
return completeCode;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="receiveData"></param>
|
|
/// <param name="data"></param>
|
|
/// <returns></returns>
|
|
public int ResolveReadWordsReturnFrame(byte[] receiveData, out int[] data)
|
|
{
|
|
if (receiveData == null || receiveData.Length < _receiceDataMinimumBytes)
|
|
{
|
|
data = null;
|
|
return CompleteCode.NoData;
|
|
}
|
|
ushort dataBytesLength = BitConverter.ToUInt16(receiveData, 7); //+ CompleteCode 2Bytes
|
|
ushort completeCode = BitConverter.ToUInt16(receiveData, 9);
|
|
if (receiveData.Length != 9 + dataBytesLength)
|
|
{
|
|
data = null;
|
|
return CompleteCode.InvalidData;
|
|
}
|
|
data = new int[(dataBytesLength - 2) / 2];
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
data[i] = BitConverter.ToUInt16(receiveData, _receiceDataMinimumBytes + i * 2);
|
|
}
|
|
return completeCode;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="receiveData"></param>
|
|
/// <returns></returns>
|
|
public int ResolveWriteWordsReturnFrame(byte[] receiveData)
|
|
{
|
|
if (receiveData == null || receiveData.Length < _receiceDataMinimumBytes)
|
|
{
|
|
return CompleteCode.NoData;
|
|
}
|
|
ushort dataBytesLength = BitConverter.ToUInt16(receiveData, 7); //+ CompleteCode 2Bytes
|
|
ushort completeCode = BitConverter.ToUInt16(receiveData, 9);
|
|
if (receiveData.Length != 9 + dataBytesLength)
|
|
{
|
|
return CompleteCode.InvalidData;
|
|
}
|
|
return completeCode;
|
|
}
|
|
}
|
|
}
|