JiShe.CollectBus/JiShe.CollectBus.Protocol/StandardProtocolPlugin.cs
2024-10-21 16:24:29 +08:00

1010 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using JiShe.CollectBus.Common;
using JiShe.CollectBus.Protocol.Contracts.Abstracts;
using JiShe.CollectBus.Protocol.Contracts.Attributes;
using JiShe.CollectBus.Protocol.Contracts.DependencyInjection;
using JiShe.CollectBus.Protocol.Contracts.Models;
using Microsoft.Extensions.Caching.Distributed;
using System.Data;
using System.Net.Sockets;
using TouchSocket.Sockets;
namespace JiShe.CollectBus.Protocol
{
[ProtocolName("StandardProtocol")]
public class StandardProtocolPlugin(IDistributedCache cache) : BaseProtocolPlugin(cache), ISingletonDependency
{
//起始字符
private const string stx = "68";
//结束字符
private const string end = "16";
//头部字节长度
private const int hearderLen = 6;
//消息认证码字段长度
private const int pWLen = 16;
private const int tPLen = 6;
static object locker = new object();
static List<int> MSA = new List<int>();
static Dictionary<string, List<int>> usingMSA = new Dictionary<string, List<int>>();
static StandardProtocolPlugin()
{
for (int i = 1; i <= 127; i++)
{
MSA.Add(i);
}
}
public override ProtocolInfo Get()
{
return new ProtocolInfo("Standard", "376.1", "TCP","376.1协议","DTS1980");
}
public new void Load()
{
base.Load();
}
public override void Received(ReceivedDataEventArgs e)
{
var messageHexString = Convert.ToHexString(e.ByteBlock.Span);
var cmdResult = AnalysisCmd(messageHexString);
if (cmdResult == null)
{
return;
}
AnalysisData(cmdResult);
}
public override void Send()
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the msa.
/// </summary>
/// <param name="mark">The mark.</param>
/// <returns></returns>
public static int GetMSA(string mark)
{
lock (locker)
{
if (!usingMSA.Keys.Contains(mark))
usingMSA.Add(mark, new List<int>());
int msa = MSA.Except(usingMSA[mark]).FirstOrDefault();
//if (msa == 1) msa = 2;//msa=1为自定义指令保留
usingMSA[mark].Add(msa);
if (msa == 127)
usingMSA[mark].RemoveAll(m => true);
return msa;
}
}
#region
//68
//32 00
//32 00
//68
//C9 1100'1001. 控制域C。
// D7=1, (终端发送)上行方向。
// D6=1, 此帧来自启动站。
// D5=0, (上行方向)要求访问位。表示终端无事件数据等待访问。
// D4=0, 保留
// D3~D0=9, 功能码。链路测试
//20 32 行政区划码
//90 26 终端地址
//00 主站地址和组地址标志。终端为单地址。 //3220 09 87 2
// 终端启动的发送帧的 MSA 应为 0, 其主站响应帧的 MSA 也应为 0.
//02 应用层功能码。AFN=2, 链路接口检测
//70 0111'0000. 帧序列域。无时间标签、单帧、需要确认。
//00 00 信息点。DA1和DA2全为“0”时表示终端信息点。
//01 00 信息类。F1, 登录。
//44 帧尾,包含用户区数据校验和
//16 帧结束标志
/// <summary>
/// 解析上行命令
/// </summary>
/// <param name="cmd"></param>
/// <returns></returns>
public CommandReulst? AnalysisCmd(string cmd)
{
CommandReulst? commandReulst = null;
var hexStringList = DataConvert.StringToPairs(cmd);
if (hexStringList.Count < hearderLen)
{
return commandReulst;
}
//验证起始字符
if (hexStringList[0] != stx || hexStringList[5] != stx)
{
return commandReulst;
}
var lenHexStr = $"{hexStringList[2]}{hexStringList[1]}";
var lenBin = DataConvert.HexToBin(lenHexStr);
var len = DataConvert.BinToDec(lenBin.Remove(lenBin.Length - 2));
//验证长度
if (hexStringList.Count - 2 != hearderLen + len)
return commandReulst;
var userDataIndex = hearderLen;
var c = hexStringList[userDataIndex];//控制域 1字节
userDataIndex += 1;
var aHexList = hexStringList.Skip(userDataIndex).Take(5).ToList();//地址域 5字节
var a = AnalysisA(aHexList);
var a3Bin = DataConvert.HexToBin(aHexList[4]).PadLeft(8, '0');
var mSA = DataConvert.BinToDec(a3Bin.Substring(0, 7));
userDataIndex += 5;
var aFN = (AFN)DataConvert.HexToDec(hexStringList[userDataIndex]);//1字节
userDataIndex += 1;
var seq = DataConvert.HexToBin(hexStringList[userDataIndex]).PadLeft(8, '0');
var tpV = (TpV)Convert.ToInt32(seq.Substring(0, 1));
var fIRFIN = (FIRFIN)Convert.ToInt32(seq.Substring(1, 2));
var cON = (CON)Convert.ToInt32(seq.Substring(3, 1));
var prseqBin = seq.Substring(4, 4);
userDataIndex += 1;
// (DA2 - 1) * 8 + DA1 = pn
var da1Bin = DataConvert.HexToBin(hexStringList[userDataIndex]);
var da1 = da1Bin == "0" ? 0 : da1Bin.Length;
userDataIndex += 1;
var da2 = DataConvert.HexToDec(hexStringList[userDataIndex]);
userDataIndex += 1;
var pn = da2 == 0 ? 0 : (da2 - 1) * 8 + da1;
//(DT2*8)+DT1=fn
var dt1Bin = DataConvert.HexToBin(hexStringList[userDataIndex]);
var dt1 = dt1Bin != "0" ? dt1Bin.Length : 0;
userDataIndex += 1;
var dt2 = DataConvert.HexToDec(hexStringList[userDataIndex]);
userDataIndex += 1;
var fn = dt2 * 8 + dt1;
//数据单元
var datas = hexStringList.Skip(userDataIndex).Take(len + hearderLen - userDataIndex).ToList();
//EC
//Tp
commandReulst = new CommandReulst()
{
A = a,
MSA = mSA,
AFN = aFN,
Seq = new Seq()
{
TpV = tpV,
FIRFIN = fIRFIN,
CON = cON,
PRSEQ = DataConvert.BinToDec(prseqBin),
},
CmdLength = len,
Pn = pn,
Fn = fn,
HexDatas = datas
};
return commandReulst;
}
/// <summary>
/// 解析地址
/// </summary>
/// <param name="aHexList"></param>
/// <returns></returns>
private string AnalysisA(List<string> aHexList)
{
var a1 = aHexList[1] + aHexList[0];
var a2 = aHexList[3] + aHexList[2];
var a2Dec = DataConvert.HexToDec(a2);
var a3 = aHexList[4];
var a = $"{a1}{a2Dec.ToString().PadLeft(5, '0')}";
return a;
}
/// <summary>
/// 解析上行命令数据包
/// </summary>
/// <param name="commandReulst"></param>
public void AnalysisData(CommandReulst commandReulst)
{
switch (commandReulst.AFN)
{
case AFN.:
//commandReulst.fn
//1:全部确认
//2:全部否认
//3:按数据单元表示确认和否认
//4 硬件安全认证错误应答
break;
case AFN.:
break;
case AFN.:
AnalysisAFN02(commandReulst);
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
default:
break;
}
}
//终端启动发送帧的MSA应为零其主站响应帧的MSA也应为零
public void AnalysisAFN02(CommandReulst commandReulst)
{
if (commandReulst.Fn == 1) //登录
{
Console.WriteLine($"{commandReulst.A},登录:{DateTime.Now}");
var reqParam = new ReqParameter2()
{
AFN = AFN.,
CMasterStationFunCode = CMasterStationFunCode.,
PRM = PRM.,
A = commandReulst.A,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = commandReulst.Seq.PRSEQ,
},
MSA = commandReulst.MSA,
Pn = 0,
Fn = 1
};
commandReulst.ReplyBytes = GetCommandBytes(reqParam);
}
else if (commandReulst.Fn == 2)//退出登录
{
Console.WriteLine($"{commandReulst.A},退出登录:{DateTime.Now}");
}
else if (commandReulst.Fn == 3)//心跳
{
Console.WriteLine($"{commandReulst.A},心跳:{DateTime.Now}");
AnalysisHeartbeat(commandReulst);
}
}
public void AnalysisHeartbeat(CommandReulst commandReulst)
{
if (commandReulst.Seq.TpV == TpV.)
{
//解析
}
if (commandReulst.Seq.CON == CON.)
{
var reqParam = new ReqParameter2()
{
AFN = AFN.,
CMasterStationFunCode = CMasterStationFunCode.,
PRM = PRM.,
A = commandReulst.A,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = commandReulst.Seq.PRSEQ,
},
MSA = commandReulst.MSA,
Pn = 0,
Fn = 1
};
commandReulst.ReplyBytes = GetCommandBytes(reqParam);
}
}
/// <summary>
/// 解析时间标签
/// </summary>
/// <param name="hexDatas"></param>
private void AnalysisTp(List<string> hexDatas)
{
var pFC = DataConvert.HexToDec(hexDatas[0]);//启动帧帧序号计数器
var seconds = Convert.ToInt32(hexDatas[1]); // 获取当前秒数
var minutes = Convert.ToInt32(hexDatas[2]); // 获取当前分钟数
var hours = Convert.ToInt32(hexDatas[3]); // 获取当前小时数
var day = Convert.ToInt32(hexDatas[4]); // 获取当前日期的日数
var delayTime = DataConvert.HexToDec(hexDatas[5]);//延迟时间 min
}
/// <summary>
/// 解析电表档案
/// </summary>
/// <param name="hexDatas"></param>
/// <returns></returns>
public List<MeterParameter> AnalysisAFN04F10DataUnit(List<string> hexDatas)
{
var meterList = new List<MeterParameter>();
var count = DataConvert.HexToDec($"{hexDatas[1]}{hexDatas[0]}");
//if (2 + count * 27 != hexDatas.Count - pWLen - tPLen - 2)
// return;
var index = 2;//数量
for (int i = 1; i <= count; i++)
{
var meterNumber = DataConvert.HexToDec($"{hexDatas[index + 1]}{hexDatas[index]}");
index += 2;
var pn = DataConvert.HexToDec($"{hexDatas[index + 1]}{hexDatas[index]}");
index += 2;
var baudRateAndPortBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0');
var baudRate = DataConvert.BinToDec(baudRateAndPortBin.Substring(0, 3));
var port = DataConvert.BinToDec(baudRateAndPortBin.Substring(3, 5));
index += 1;
var protocolType = (CommunicationProtocolType)DataConvert.HexToDec(hexDatas[index]);
index += 1;
var addressHexList = hexDatas.Skip(index).Take(6).ToList();
addressHexList.Reverse();
var address = string.Join("", addressHexList);
index += 6;
var pwdHexList = hexDatas.Skip(index).Take(6).ToList();
pwdHexList.Reverse();
var password = string.Join("", pwdHexList.Take(3).ToList());
index += 6;
var rateNumberBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0');
var rateNumber = DataConvert.BinToDec(rateNumberBin.Substring(4));
index += 1;
var intBitAndDecBitNumberBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0');
var intBitNumber = DataConvert.BinToDec(intBitAndDecBitNumberBin.Substring(4, 2)) + 4;
var decBitNumber = DataConvert.BinToDec(intBitAndDecBitNumberBin.Substring(6, 2)) + 1;
index += 1;
// hexDatas.GetRange()
var collectorAddressHexList = hexDatas.Skip(index).Take(6).ToList();
collectorAddressHexList.Reverse();
var collectorAddress = string.Join("", collectorAddressHexList);
index += 6;
var userClassNumberBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0');
var userClass = DataConvert.BinToDec(userClassNumberBin.Substring(0, 4));
var userSubClass = DataConvert.BinToDec(userClassNumberBin.Substring(4, 4));
index += 1;
meterList.Add(new MeterParameter()
{
Pn = pn,
BaudRate = baudRate,
Port = port,
ProtocolType = protocolType,
Address = address,
Password = password,
RateNumber = rateNumber,
IntegerBitNumber = intBitNumber,
DecimalBitNumber = decBitNumber,
CollectorAddress = collectorAddress,
UserCategoryNumber = userClass,
UserSubclassNumber = userSubClass,
});
}
return meterList;
}
/// <summary>
/// 解析实时数据F129
/// </summary>
/// <param name="hexDatas"></param>
private void AnalysisAFN0CF129DataUnit(List<string> hexDatas)
{
var minutes = Convert.ToInt32(hexDatas[0]); // 获取当前分钟数
var hours = Convert.ToInt32(hexDatas[1]); // 获取当前小时数
var day = Convert.ToInt32(hexDatas[2]); // 获取当前日期的日数
var month = Convert.ToInt32(hexDatas[3]); // 获取当前月份
var year = Convert.ToInt32(hexDatas[4]); // 获取当前日期的年份
var rateNumber = Convert.ToInt32(hexDatas[5]);
var kwhTotal = hexDatas.Skip(5).Take(5).ToList();
var kwhList = new List<decimal>();
var index = 11;
for (int i = 0; i < rateNumber; i++)
{
var kwhHexList = hexDatas.Skip(11).Take(5).ToList();
kwhHexList.Reverse();
var integerStr = $"{kwhHexList.Take(0)}{kwhHexList.Take(1)}{kwhHexList.Take(2)}";
var decimalValStr = $"{kwhHexList[3]}{kwhHexList[4]}";
var val = decimal.Parse($"{integerStr}{decimalValStr}");
kwhList.Add(val);
index += 5;
}
}
#endregion
#region
/// <summary>
/// 设置电表档案
/// </summary>
/// <param name="a">集中器地址</param>
/// <param name="meterParameters"></param>
public void GetSetAmmeterParameter(string a, List<MeterParameter> meterParameters)
{
var dataUnit = GetAFN04F10DataUnit(meterParameters);
var bytes = GetCommandBytes(new ReqParameter2()
{
AFN = AFN.,
CMasterStationFunCode = CMasterStationFunCode.1,
A = a,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 10,
},
MSA = GetMSA(a),
Pn = 0,
Fn = 10
}, dataUnit);
}
/// <summary>
/// 查询电表档案
/// </summary>
/// <param name="a"></param>
/// <param name="meterNumberList">对象序号</param>
public void GetAmmeterParameter(string a, List<int> meterNumberList)
{
var dataUnit = new List<string>();
var countHex = DataConvert.DecToHex(meterNumberList.Count()).PadLeft(4, '0');
var countHexPairs = DataConvert.StringToPairs(countHex);
countHexPairs.Reverse();
dataUnit.AddRange(countHexPairs);
foreach (var number in meterNumberList)
{
var numberHex = DataConvert.DecToHex(number).PadLeft(4, '0');
var numberHexPairs = DataConvert.StringToPairs(numberHex);
numberHexPairs.Reverse();
dataUnit.AddRange(numberHexPairs);
}
var bytes = GetCommandBytes(new ReqParameter2()
{
AFN = AFN.,
CMasterStationFunCode = CMasterStationFunCode.2,
A = a,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 0,
},
MSA = GetMSA(a),
Pn = 0,
Fn = 10
}, dataUnit);
}
public void GetAmmterReading(string a,int pn)
{
var bytes = GetCommandBytes(new ReqParameter2()
{
AFN = AFN.,
CMasterStationFunCode = CMasterStationFunCode.2,
A = a,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 2,
},
MSA = GetMSA(a),
Pn = pn,
Fn = 129
});
}
/// <summary>
/// 组装电表阀控
/// </summary>
/// <param name="address">电表地址</param>
/// <param name="specialnocode">特殊控制码</param>
/// <param name="password">密码</param>
/// <param name="state">是否为开阀</param>
/// <returns></returns>
public List<string> AmmeterValveControl(string address, string specialnocode, string password, bool state, string modelCode = "")
{
address = address.Trim().TrimStart('0');
if (address.Length < 12) address = address.PadLeft(12, '0');
string Code = string.Empty;
if (state)
{
if (string.IsNullOrEmpty(specialnocode))
Code = "1B";
else
Code = specialnocode == "1B" || specialnocode == "1C" ? specialnocode : "1C";
}
else
Code = "1A";//跳闸
if (specialnocode == "1W")
{
if (state)
Code = "1A";
else
Code = "1C";
}
var pwdLevel = "02";
if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866")
pwdLevel = "04";
else if (modelCode == "DDS2705")
pwdLevel = "03";
if (!string.IsNullOrWhiteSpace(password) && password.Contains("|"))
{
var sp = password.Split('|');
pwdLevel = sp[1];
password = sp[0];
}
string strDate = DataConvert.StrAddSpan(DateTime.Now.AddYears(3).ToString("000012ddMMyy"));
if (specialnocode == "1D" || modelCode == "SZBD_DDZY1225")
strDate = "FF FF FF FF FF FF";
string strP = DataConvert.StrReverseOrder(DataConvert.StrAddSpan(password));
string strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + Code + " 00 " + strDate;
string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2");
string strReturn = "68 " + DataConvert.StrReverseOrder(DataConvert.StrAddSpan(address)) + " 68 1C " + strLen + " " + DataConvert.StrAddHex33(strSJY) + " ";
string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
strReturn += strSum.Substring(strSum.Length - 2) + " 16";
return strReturn.Split(' ').ToList();
}
/// <summary>
/// 帧命令组装
/// </summary>
/// <param name="reqParameter">请求参数</param>
/// <param name="dataUnit">数据单元</param>
/// <returns></returns>
public byte[] GetCommandBytes(ReqParameter reqParameter, List<string>? dataUnit = null)
{
var cmdStrList = new List<string>();
var userDatas = GetUserData(reqParameter, dataUnit);
var hearders = GetHeaders(userDatas.Count);
var cs = GetCS(userDatas);
cmdStrList.AddRange(hearders);
cmdStrList.AddRange(userDatas);
cmdStrList.Add(cs);
cmdStrList.Add(end);
Console.WriteLine(string.Join(" ", cmdStrList));
var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray();
return bytes;
}
/// <summary>
/// 固定长度的报文头 起始字符+长度+长度+起始字符
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
private List<string> GetHeaders(int length)
{
var headers = new List<string>();
headers.Add(stx);
var l = GetLength(length);
headers.AddRange(l);
headers.AddRange(l);
headers.Add(stx);
return headers;
}
/// <summary>
/// 用户数据区
/// </summary>
/// <param name="reqParameter"></param>
/// <returns></returns>
public List<string> GetUserData(ReqParameter reqParameter, List<string>? dataUnit)
{
var c = GetC(reqParameter.CMasterStationFunCode, reqParameter.PRM);
var a = GetAList(reqParameter.A, reqParameter.MSA);
var linkUserData = GetLinkUserData(reqParameter.AFN, reqParameter.Seq,
((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit);
var list = new List<string>() { c };
list.AddRange(a);
list.AddRange(linkUserData);
return list;
}
/// <summary>
/// 长度 2字节 [用户数据区长度]
/// </summary>
/// <returns></returns>
private List<string> GetLength(int length1)
{
var binaryLen = DataConvert.DecToBin(length1);
var protocolIdentification = Enum.Format(typeof(ProtocolIdentification),
ProtocolIdentification.使, "d").PadLeft(2, '0');
var lenStr = $"{binaryLen}{protocolIdentification}";
var hexLen = DataConvert.BinToHex(lenStr);
hexLen = hexLen.PadLeft(4, '0');
var list = DataConvert.StringToPairs(hexLen);
list.Reverse();
return list;
}
/// <summary>
/// 控制域
/// </summary>
/// <param name="cMasterStationFunCode"></param>
/// <param name="fcb"></param>
/// <param name="fcv"></param>
/// <returns></returns>
private string GetC(CMasterStationFunCode cMasterStationFunCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效)
{
var cMasterStationFunCodeHex = DataConvert.DecToBin((int)cMasterStationFunCode);
cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0');
var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}";
var hexC = DataConvert.BinToHex(strC).PadLeft(2, '0');
return hexC;
}
/// <summary>
/// 地址域 3220 09872
/// </summary>
/// <param name="a1">行政区划码 BCD码 3220=2032</param>
/// <param name="a2">逻辑地址 BIN 09872=2690=>9026</param>
/// <param name="a3">主站地址 BIN 0~127</param>
/// <returns></returns>
private List<string> GetAList(string a, int mSA)
{
var list = new List<string>();
var a1 = a.Substring(0, 4);
var a1Pairs = DataConvert.StringToPairs(a1);
a1Pairs.Reverse();
list.AddRange(a1Pairs);
var a2 = Convert.ToInt32(a.Substring(4));
var decA2 = DataConvert.DecToHex(a2);
var a2Pairs = DataConvert.StringToPairs(decA2.PadLeft(4, '0'));
a2Pairs.Reverse();
list.AddRange(a2Pairs);
//TODO:主站地址和组地址标志
var a3Bin = $"{DataConvert.DecToBin(mSA).PadLeft(7, '0')}0";
list.Add(DataConvert.BinToHex(a3Bin));
return list;
}
#region
private List<string> GetLinkUserData(AFN aFN, Seq seq, int pn, int fn, List<string>? dataUnit)
{
var aFNValue = DataConvert.DecToHex((int)aFN).PadLeft(2, '0');
var sEQ = GetSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ);
var dA = GetDA(pn);
var dT = GetDT(fn);
var list = new List<string>() { aFNValue, sEQ };
list.AddRange(dA);
list.AddRange(dT);
if (dataUnit != null)
{
list.AddRange(dataUnit);
}
//list.AddRange(GetDataUnit(aFN,seq));
if (seq.TpV == TpV.)
list.AddRange(GetTp("00"));
return list;
}
/// <summary>
/// 帧序列域
/// </summary>
/// <param name="tpV"></param>
/// <param name="fIRFIN"></param>
/// <param name="cON"></param>
/// <returns></returns>
private string GetSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ)
{
var tpVValue = Enum.Format(typeof(TpV),
tpV, "d");
var fIRFINValue = Enum.Format(typeof(FIRFIN),
fIRFIN, "d");
var cONValue = (int)cON;
var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{DataConvert.DecToBin(pRSEQ).PadLeft(4, '0')}";
var hexSEQ = DataConvert.BinToHex(sEQBin).PadLeft(2, '0');
return hexSEQ;
}
/// <summary>
/// 信息点标识
/// </summary>
/// <param name="pn">计量点</param>
/// <returns></returns>
private List<string> GetDA(int pn)
{
if (pn == 0)
return new List<string>() { "00", "00" };
var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组
var dA1 = pn - (dA2 - 1) * 8;//pn % 8
var dA1Hex = DataConvert.BinToHex("1".PadRight(dA1, '0'));//对位信息 第几位 二进制有效位
var dA2Hex = DataConvert.DecToHex(dA2);
return new List<string>() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') };
}
/// <summary>
/// 数据单元标识
/// </summary>
/// <param name="fn"></param>
/// <returns></returns>
private List<string> GetDT(int fn)
{
var dT2 = (fn - 1) / 8;//从零开始 第几组
var dT1 = fn - dT2 * 8;
var dT1Hex = DataConvert.BinToHex("1".PadRight(dT1, '0'));//对位信息 第几位 二进制有效位
var dT2Hex = DataConvert.DecToHex(dT2);
return new List<string>() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') };
}
private List<string> GetDataUnit(AFN aFN, Seq seq)
{
var datas = new List<string>();
switch (aFN)
{
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
case AFN.:
break;
default:
break;
}
if (seq.TpV == TpV.)
datas.AddRange(GetTp("00"));
return datas;
}
private void GetAFN00DataUnit(Seq seq)
{
//EC+Tp
}
/// <summary>
/// 终端电能表配置参数
/// </summary>
/// <param name="meterParameters"></param>
/// <returns></returns>
public List<string> GetAFN04F10DataUnit(List<MeterParameter> meterParameters)
{
var hexDatas = new List<string>();
var countHex = DataConvert.DecToHex(meterParameters.Count()).PadLeft(4, '0');
hexDatas.Add(countHex);
//TODO 优化代码:目标数据入参,返回类型为出参
for (int i = 0; i <= meterParameters.Count - 1; i++)
{
var meter = meterParameters[i];
var indexHex = DataConvert.DecToHex(i + 1).PadLeft(4, '0');
hexDatas.Add(indexHex);
var pnHex = DataConvert.DecToHex(meter.Pn).PadLeft(4, '0');
hexDatas.Add(pnHex);
var baudRateBin = DataConvert.DecToBin(meter.BaudRate).PadLeft(3, '0');
var portBin = DataConvert.DecToBin(meter.Port).PadLeft(5, '0');
var baudRateAndPortHex = DataConvert.BinToHex($"{baudRateBin}{portBin}").PadLeft(2, '0');
hexDatas.Add(baudRateAndPortHex);
var protocolTypeHex = DataConvert.DecToHex((int)meter.ProtocolType).PadLeft(2, '0');
hexDatas.Add(protocolTypeHex);
hexDatas.Add(meter.Address);
hexDatas.Add(meter.Password.PadLeft(12, '0'));
var rateNumberBin = $"0000{DataConvert.DecToBin(meter.RateNumber).PadLeft(4, '0')}";
var rateNumberHex = DataConvert.BinToHex(rateNumberBin).PadLeft(2, '0');
hexDatas.Add(rateNumberHex);
var intBitNumberBin = DataConvert.DecToBin(meter.IntegerBitNumber - 4).PadLeft(2, '0');
var decBitNumberBin = DataConvert.DecToBin(meter.DecimalBitNumber - 1).PadLeft(2, '0');
var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}";
var intAndDecBitNumberHex = DataConvert.BinToHex(intAndDecBitNumberBin).PadLeft(2, '0');
hexDatas.Add(intAndDecBitNumberHex);
hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0'));
var userCategoryNumberBin = DataConvert.DecToBin(meter.UserCategoryNumber).PadLeft(4, '0');
var userSubclassNumberBin = DataConvert.DecToBin(meter.UserSubclassNumber).PadLeft(4, '0');
var userNumberHex = DataConvert.BinToHex($"{userCategoryNumberBin}{userSubclassNumberBin}").PadLeft(2, '0');
hexDatas.Add(userNumberHex);
}
//高位在前,低位在后
var datas = new List<string>();
foreach (var hexData in hexDatas)
{
if (hexData.Length == 2)
datas.Add(hexData);
else
{
var lst = DataConvert.StringToPairs(hexData);
lst.Reverse();
datas.AddRange(lst);
}
}
datas.AddRange(GetPW());
return datas;
}
/// <summary>
/// 透明转发
/// </summary>
/// <param name="port">终端通信端口 1~31</param>
/// <param name="baudRate">0~7 对应300,600,1200,2400,4800,7200,9600,19200</param>
/// <param name="stopBit"></param>
/// <param name="parity"></param>
/// <param name="dataBit"></param>
/// <returns></returns>
public List<string> GetAFN1001DataUnit(int port, BaudRate baudRate, StopBit stopBit, Parity parity, DataBit dataBit,
int waitContentTimeout, int waitByteTimeout, List<string> datas)
{
var dataUnit = new List<string>();
var portHex = DataConvert.DecToHex(port).PadLeft(2, '0');
dataUnit.Add(portHex);
var baudRateBin = DataConvert.DecToBin((int)baudRate).PadLeft(3, '0');
var stopBitBin = DataConvert.DecToBin((int)stopBit);
var parityBin = parity != Parity.None ? $"1{DataConvert.DecToBin((int)parity)}" : $"0{DataConvert.DecToBin((int)parity)}";
var dataBitBin = DataConvert.DecToBin((int)dataBit).PadLeft(2, '0');
var controlHex = DataConvert.BinToHex($"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}").PadLeft(2, '0'); ;
dataUnit.Add(controlHex);
var waitContentTimeoutBin = $"1{DataConvert.DecToBin(waitContentTimeout).PadLeft(7, '0')}";
var waitContentTimeoutHex = DataConvert.BinToHex(waitContentTimeoutBin).PadLeft(2, '0');
var waitByteTimeoutHex = DataConvert.DecToHex(waitByteTimeout).PadLeft(2, '0');
dataUnit.Add(waitContentTimeoutHex);
dataUnit.Add(waitByteTimeoutHex);
var countHex = DataConvert.DecToHex(datas.Count).PadLeft(4, '0');
var countHexPairs = DataConvert.StringToPairs(countHex);
countHexPairs.Reverse();
dataUnit.AddRange(countHexPairs);
dataUnit.AddRange(datas);
return dataUnit;
}
//TODO AUX=消息认证码字段PW,16个字节+时间标签
private List<string> GetPW()
{
var str = "00";
var pWList = Enumerable.Repeat(str, pWLen).ToList();
return pWList;
}
/// <summary>
/// 时间标签
/// </summary>
/// <param name="pFC">启动帧帧序号计数器PFC 1字节</param>
/// <param name="delayTime">允许发送传输延时时间 min 1字节</param>
/// <returns></returns>
private List<string> GetTp(string pFC = "00", int delayTime = 0)
{
var now = DateTime.Now; // 获取当前时间
var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数
var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数
var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数
var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数
return new List<string>() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') };
}
#endregion
/// <summary>
/// 帧校验和
/// </summary>
/// <param name="userData">用户数据区</param>
/// <returns></returns>
private string GetCS(List<string> userData)
{
byte sum = 0;
foreach (var d in userData)
{
var b = Convert.ToByte(d, 16);
sum += b;
}
return sum.ToString("X2");
}
#endregion
}
}