|
|
|
|
using System;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace HighWayIot.Common
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 工具类
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class MsgUtil
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
private static readonly Lazy<MsgUtil> lazy = new Lazy<MsgUtil>(() => new MsgUtil());
|
|
|
|
|
|
|
|
|
|
public static MsgUtil Instance
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return lazy.Value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MsgUtil() { }
|
|
|
|
|
|
|
|
|
|
#region 数据解析公共方法
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 字节数组转换成结构体
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="buf"></param>
|
|
|
|
|
/// <param name="len"></param>
|
|
|
|
|
/// <param name="type"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static object BytesToStruct(byte[] buf, int len, Type type)
|
|
|
|
|
{
|
|
|
|
|
object rtn;
|
|
|
|
|
IntPtr buffer = Marshal.AllocHGlobal(len);
|
|
|
|
|
Marshal.Copy(buf, 0, buffer, len);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
rtn = Marshal.PtrToStructure(buffer, type);
|
|
|
|
|
Marshal.FreeHGlobal(buffer);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return rtn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string StringToHexString(string s, Encoding encode)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
byte[] b = encode.GetBytes(s); //按照指定编码将string编程字节数组
|
|
|
|
|
string result = string.Empty;
|
|
|
|
|
for (int i = 0; i < b.Length; i++) //逐字节变为16进制字符,以%隔开
|
|
|
|
|
{
|
|
|
|
|
result += "%" + Convert.ToString(b[i], 16);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//// <summary>
|
|
|
|
|
/// 结构体转byte数组
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="structObj">要转换的结构体</param>
|
|
|
|
|
/// <returns>转换后的byte数组</returns>
|
|
|
|
|
public static byte[] StructToBytes(object structObj)
|
|
|
|
|
{
|
|
|
|
|
//得到结构体的大小
|
|
|
|
|
int size = Marshal.SizeOf(structObj);
|
|
|
|
|
//创建byte数组
|
|
|
|
|
byte[] bytes = new byte[size];
|
|
|
|
|
//分配结构体大小的内存空间
|
|
|
|
|
IntPtr structPtr = Marshal.AllocHGlobal(size);
|
|
|
|
|
//将结构体拷到分配好的内存空间
|
|
|
|
|
Marshal.StructureToPtr(structObj, structPtr, false);
|
|
|
|
|
//从内存空间拷到byte数组
|
|
|
|
|
Marshal.Copy(structPtr, bytes, 0, size);
|
|
|
|
|
//释放内存空间
|
|
|
|
|
Marshal.FreeHGlobal(structPtr);
|
|
|
|
|
//返回byte数组
|
|
|
|
|
return bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
#region 消息验证方法
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// CS和校验
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="Abyte"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public byte Check_CS(byte[] Abyte)
|
|
|
|
|
{
|
|
|
|
|
byte result = new byte();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
int num = 0;
|
|
|
|
|
for (int i = 0; i < Abyte.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
num = (num + Abyte[i]) % 256;
|
|
|
|
|
}
|
|
|
|
|
result = (byte)num;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
result = 0;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// BCC异或取反校验
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string getBCC(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
String ret = "";
|
|
|
|
|
byte[] BCC = new byte[1];
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
BCC[0] = (byte)(BCC[0] ^ data[i]);
|
|
|
|
|
}
|
|
|
|
|
String hex = ((~BCC[0]) & 0xFF).ToString("X");//取反操作
|
|
|
|
|
if (hex.Length == 1)
|
|
|
|
|
{
|
|
|
|
|
hex = '0' + hex;
|
|
|
|
|
}
|
|
|
|
|
ret += hex.ToUpper();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int BytesToInt(byte[] b, int length)
|
|
|
|
|
{
|
|
|
|
|
int temp = 0;
|
|
|
|
|
for (int i = 0; i <= length - 1 && i < 4; i++)
|
|
|
|
|
{
|
|
|
|
|
temp += (int)(b[i] << (i * 8));
|
|
|
|
|
}
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static byte[] CalculateVerify(byte[] pMessage, int iLength)
|
|
|
|
|
{
|
|
|
|
|
UInt16 i;
|
|
|
|
|
int iVerify = 0;
|
|
|
|
|
|
|
|
|
|
iVerify = pMessage[0];
|
|
|
|
|
for (i = 0; i < iLength - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
iVerify = iVerify + pMessage[i + 1];
|
|
|
|
|
}
|
|
|
|
|
return BitConverter.GetBytes(Convert.ToUInt16(iVerify));
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
public byte[] HexStrTorbytes(string strHex)//e.g. " 01 01" ---> { 0x01, 0x01}
|
|
|
|
|
{
|
|
|
|
|
strHex = strHex.Replace(" ", "");
|
|
|
|
|
if ((strHex.Length % 2) != 0)
|
|
|
|
|
strHex += " ";
|
|
|
|
|
byte[] returnBytes = new byte[strHex.Length / 2];
|
|
|
|
|
for (int i = 0; i < returnBytes.Length; i++)
|
|
|
|
|
returnBytes[i] = Convert.ToByte(strHex.Substring(i * 2, 2), 16);
|
|
|
|
|
return returnBytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 将字符串强制转换成int,转换失败则返回0
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="str"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public int ParseToInt(string str)
|
|
|
|
|
{
|
|
|
|
|
int returnInt = 0;
|
|
|
|
|
|
|
|
|
|
if (str == null || str.Trim().Length < 1)
|
|
|
|
|
{
|
|
|
|
|
return returnInt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (int.TryParse(str, out returnInt))
|
|
|
|
|
{
|
|
|
|
|
return returnInt;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] HexToString(string Str)
|
|
|
|
|
{
|
|
|
|
|
byte[] str = new byte[Str.Length / 2];
|
|
|
|
|
for (int i = 0; i < str.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
int temp = Convert.ToInt32(Str.Substring(i * 2, 2), 16);
|
|
|
|
|
str[i] = (byte)temp;
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
public string ConverToString(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
string str;
|
|
|
|
|
StringBuilder stb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if ((int)data[i] > 15)
|
|
|
|
|
{
|
|
|
|
|
stb.Append(Convert.ToString(data[i], 16).ToUpper()); //添加字符串
|
|
|
|
|
}
|
|
|
|
|
else //如果是小于0F需要加个零
|
|
|
|
|
{
|
|
|
|
|
stb.Append("0" + Convert.ToString(data[i], 16).ToUpper());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
str = stb.ToString();
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string bytesToHexStr(byte[] bytes, int iLen)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
if (bytes != null)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < iLen; i++)
|
|
|
|
|
{
|
|
|
|
|
sb.Append(bytes[i].ToString("X2"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从十进制转换到十六进制
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ten"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string Ten2Hex(string ten)
|
|
|
|
|
{
|
|
|
|
|
ulong tenValue = Convert.ToUInt64(ten);
|
|
|
|
|
ulong divValue, resValue;
|
|
|
|
|
string hex = "";
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
//divValue = (ulong)Math.Floor(tenValue / 16);
|
|
|
|
|
|
|
|
|
|
divValue = (ulong)Math.Floor((decimal)(tenValue / 16));
|
|
|
|
|
|
|
|
|
|
resValue = tenValue % 16;
|
|
|
|
|
hex = tenValue2Char(resValue) + hex;
|
|
|
|
|
tenValue = divValue;
|
|
|
|
|
}
|
|
|
|
|
while (tenValue >= 16);
|
|
|
|
|
if (tenValue != 0)
|
|
|
|
|
hex = tenValue2Char(tenValue) + hex;
|
|
|
|
|
return hex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string tenValue2Char(ulong ten)
|
|
|
|
|
{
|
|
|
|
|
switch (ten)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
case 4:
|
|
|
|
|
case 5:
|
|
|
|
|
case 6:
|
|
|
|
|
case 7:
|
|
|
|
|
case 8:
|
|
|
|
|
case 9:
|
|
|
|
|
return ten.ToString();
|
|
|
|
|
case 10:
|
|
|
|
|
return "A";
|
|
|
|
|
case 11:
|
|
|
|
|
return "B";
|
|
|
|
|
case 12:
|
|
|
|
|
return "C";
|
|
|
|
|
case 13:
|
|
|
|
|
return "D";
|
|
|
|
|
case 14:
|
|
|
|
|
return "E";
|
|
|
|
|
case 15:
|
|
|
|
|
return "F";
|
|
|
|
|
default:
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 消息公用的头尾
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 能源通讯协议结构体
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
|
|
public enum CallbackSendData
|
|
|
|
|
{
|
|
|
|
|
_LoginIn = 0XA1,
|
|
|
|
|
_SetTime = 0X08,
|
|
|
|
|
_HeartBeat = 0XA4,
|
|
|
|
|
_ERealFlag = 0XB3,
|
|
|
|
|
_SRealFlag = 0XB4,
|
|
|
|
|
_TRealFlag = 0XB5,
|
|
|
|
|
_IRealFlag = 0XB6,
|
|
|
|
|
|
|
|
|
|
_EFlag = 0XC3,
|
|
|
|
|
_SFlag = 0XC4,
|
|
|
|
|
_TFlag = 0XC5,
|
|
|
|
|
_IFlag = 0XC6,
|
|
|
|
|
}
|
|
|
|
|
public struct struFrame
|
|
|
|
|
{
|
|
|
|
|
//帧开始
|
|
|
|
|
public byte BeginChar_State;
|
|
|
|
|
//采集器类型
|
|
|
|
|
public byte Collection_Type;
|
|
|
|
|
//采集器地址
|
|
|
|
|
public byte[] Collection_Addr;
|
|
|
|
|
//命令序列号
|
|
|
|
|
public byte[] Command_Id;
|
|
|
|
|
//起始符
|
|
|
|
|
public byte StartChar_State;
|
|
|
|
|
//控制码
|
|
|
|
|
public byte Ctrl_State;
|
|
|
|
|
//数据长度
|
|
|
|
|
public byte[] DataLen_State;
|
|
|
|
|
//数据域
|
|
|
|
|
public byte[] Data_State;
|
|
|
|
|
//校验码
|
|
|
|
|
public byte CSChar_State;
|
|
|
|
|
//结束符
|
|
|
|
|
public byte EndChar_State;
|
|
|
|
|
//终端类型
|
|
|
|
|
public byte flagDTN;
|
|
|
|
|
//逻辑编号
|
|
|
|
|
public byte[] addrDNL;
|
|
|
|
|
//主站地址
|
|
|
|
|
public byte flagMSTA;
|
|
|
|
|
//帧内序号
|
|
|
|
|
public byte flagISEQ;
|
|
|
|
|
//帧序号
|
|
|
|
|
public byte flagFSEQ;
|
|
|
|
|
//控制码
|
|
|
|
|
public byte flagCtrl;
|
|
|
|
|
//传送方向
|
|
|
|
|
public byte flagCtrlD;
|
|
|
|
|
//异常标志
|
|
|
|
|
public byte flagCtrlE;
|
|
|
|
|
//功能标志
|
|
|
|
|
public byte flagCtrlF;
|
|
|
|
|
//数据长度
|
|
|
|
|
public int lenData;
|
|
|
|
|
//数据字符串
|
|
|
|
|
public byte[] strData;
|
|
|
|
|
|
|
|
|
|
public object userData;
|
|
|
|
|
public string tName;
|
|
|
|
|
|
|
|
|
|
public object userData2;
|
|
|
|
|
//public bool isCtrl;
|
|
|
|
|
//public bool isData;
|
|
|
|
|
|
|
|
|
|
public bool isTimeCorrectting;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 头文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
public struct Head
|
|
|
|
|
{
|
|
|
|
|
public byte start; //起始
|
|
|
|
|
public short addr; //软件地址
|
|
|
|
|
public byte mstaseq; //主站地址与命令序号
|
|
|
|
|
public byte control; //控制码
|
|
|
|
|
public short length; //数据长度
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 结尾
|
|
|
|
|
/// </summary>
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
public struct Tail
|
|
|
|
|
{
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
|
|
|
|
public byte[] verifica; //校验码
|
|
|
|
|
public byte end; //结束码
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 与MES通讯协议
|
|
|
|
|
//识别一条EPC数据 125+3
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
public struct ReadEPC
|
|
|
|
|
{
|
|
|
|
|
public Head head;
|
|
|
|
|
public int num;//合并编号
|
|
|
|
|
public Tail tail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 写入反馈 125+5
|
|
|
|
|
/// </summary>
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
public struct RecWrite
|
|
|
|
|
{
|
|
|
|
|
public Head head;
|
|
|
|
|
public int num;//合并编号
|
|
|
|
|
public byte state;//1成功,0失败,2写失败,读成功
|
|
|
|
|
public Tail tail;
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
|
|
|
|
|
public struct RecDataCell
|
|
|
|
|
{
|
|
|
|
|
public byte len;//Data长度
|
|
|
|
|
public byte[] data;//len 长度个字节数据
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 自报数据 125+6
|
|
|
|
|
/// </summary>
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
|
|
|
|
|
public struct RecAutoData
|
|
|
|
|
{
|
|
|
|
|
public Head head;
|
|
|
|
|
public int num;//合并编号
|
|
|
|
|
public RecDataCell recDatas;//自报数据
|
|
|
|
|
public Tail tail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///心跳 101
|
|
|
|
|
/// </summary>
|
|
|
|
|
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
|
|
|
|
|
|
|
|
|
public struct Heart
|
|
|
|
|
{
|
|
|
|
|
public Head head;
|
|
|
|
|
public Tail tail;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 与上层应用层 消息指令
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 收到的消息指令
|
|
|
|
|
/// </summary>
|
|
|
|
|
enum RecAppMsgType
|
|
|
|
|
{
|
|
|
|
|
_ReadEpc = 125 + 3,
|
|
|
|
|
_ReadData = 125 + 4,
|
|
|
|
|
_WirteData = 125 + 5,
|
|
|
|
|
_AutoSendData,
|
|
|
|
|
|
|
|
|
|
_HeartBeat = 101,
|
|
|
|
|
_ReadEquipState = 125 + 102,
|
|
|
|
|
_SendGetSoftState = 125 + 103,
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 发送的消息指令
|
|
|
|
|
/// </summary>
|
|
|
|
|
enum RetAppMsgType
|
|
|
|
|
{
|
|
|
|
|
_RetEpc = 125 + 3,
|
|
|
|
|
_RetData = 125 + 4,
|
|
|
|
|
_RetDataBack = 125 + 5,
|
|
|
|
|
_RetAutoSendData,
|
|
|
|
|
|
|
|
|
|
_RetEquipState = 125 + 102,
|
|
|
|
|
_RetGetSoftState = 125 + 103,
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 与设备层 适配层消息指令
|
|
|
|
|
//收到设备层消息
|
|
|
|
|
enum RecEquipMsgType
|
|
|
|
|
{
|
|
|
|
|
_GetEquipInfo = 0X01, //收到适配软件所需设备信息
|
|
|
|
|
_GetSensor = 0x02, //收到适配软件传感器信息
|
|
|
|
|
_EPCinfo = 0x03, //收到设备返回数据 将数据发送MES 并保存数据库
|
|
|
|
|
_SendData = 0x04, //收到读取到的数据 收到数据后,上传给MES,并保存数据库
|
|
|
|
|
_RecGetData = 0x05, //收到写入的数据是否成功反馈
|
|
|
|
|
_RecAutoData = 0x06, //收到设备自报数据
|
|
|
|
|
|
|
|
|
|
_HeartBeat = 101, //心跳
|
|
|
|
|
_EquipState, //设备状态
|
|
|
|
|
}
|
|
|
|
|
//发送给设备层消息
|
|
|
|
|
enum RetEquipMsgType
|
|
|
|
|
{
|
|
|
|
|
_RetEquipInfo = 0X01, //获取适配软件所需设备信息
|
|
|
|
|
_RetSensor = 0x02, //获取适配软件传感器信息
|
|
|
|
|
_GetEPCinfo = 0x03, //向设备发送命令,识别EPC数据
|
|
|
|
|
_GetData = 0x04, //向设备发送命令,读取数据
|
|
|
|
|
_WirteData = 0x05, //向设备发送命令,写入数据
|
|
|
|
|
_RetAutoData = 0x06, //收到设备自爆数据反馈
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|