1882 lines
75 KiB
C#
1882 lines
75 KiB
C#
using JiShe.CollectBus.Common.Enums;
|
||
using JiShe.CollectBus.Common.Extensions;
|
||
using JiShe.CollectBus.Common.Models;
|
||
using Nito.AsyncEx;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using Volo.Abp.Domain.Entities;
|
||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||
|
||
namespace JiShe.CollectBus.Common.BuildSendDatas
|
||
{
|
||
public static class Build3761SendData
|
||
{
|
||
//起始字符
|
||
private const string startStr = "68";
|
||
//结束字符
|
||
private const string endStr = "16";
|
||
//头部字节长度
|
||
private const int hearderLen = 6;
|
||
//消息认证码字段长度
|
||
private const int pWLen = 16;
|
||
|
||
private const int FixedLength = 18;
|
||
|
||
static object locker = new object();
|
||
static List<int> MSA = new List<int>();
|
||
static Dictionary<string, List<int>> usingMSA = new Dictionary<string, List<int>>();
|
||
|
||
static Build3761SendData()
|
||
{
|
||
for (int i = 1; i <= 127; i++)
|
||
{
|
||
MSA.Add(i);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the msa.
|
||
/// </summary>
|
||
/// <param name="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 376.1下行命令
|
||
|
||
/// <summary>
|
||
/// 构建电表修正时间下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="modelCode"></param>
|
||
/// <param name="ammeterAddress"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <returns></returns>
|
||
public static List<byte[]> BuildAmmeterCorrectionTimeSendCmd(string address, string modelCode, string ammeterAddress, string password, int port, string baudRate)
|
||
{
|
||
var bytesList = new List<byte[]>();
|
||
if (modelCode == "PMAC9523")
|
||
{
|
||
var dataUnit = Build645SendData.BuildPMAC9523AmmeterCorrectionTimeSendDataUnit(ammeterAddress);
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit, StopBit.Stop1, Parity.None);
|
||
bytesList.Add(bytes);
|
||
}
|
||
else if (modelCode == "DTSU193")
|
||
{
|
||
var dataUnit = Build645SendData.BuildDTSU193AmmeterCorrectionTimeSendDataUnit(ammeterAddress);
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit);
|
||
bytesList.Add(bytes);
|
||
}
|
||
else
|
||
{
|
||
var dataUnitList = Build645SendData.BuildAmmeterCorrectionTimeSendDataUnit(ammeterAddress,password);
|
||
foreach (var dataUnit in dataUnitList)
|
||
{
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit);
|
||
bytesList.Add(bytes);
|
||
}
|
||
}
|
||
return bytesList;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 构建电表读取时段设置下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="modelCode"></param>
|
||
/// <param name="ammeterAddress"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <returns></returns>
|
||
public static List<byte[]> BuildReadMeterTimeSetSendCmd(string address, string modelCode, string ammeterAddress, string password, int port, string baudRate)
|
||
{
|
||
if (modelCode == "DTSU193")
|
||
{
|
||
return null;
|
||
}
|
||
|
||
if (modelCode == "PMAC9523")
|
||
{
|
||
var dataUnit = Build645SendData.BuildPMAC9523ReadMeterTimeSetSendDataUnit(ammeterAddress);
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit, StopBit.Stop1, Parity.None);
|
||
return new List<byte[]>() { bytes };
|
||
}
|
||
|
||
var bytes1 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010001"));
|
||
|
||
var bytes2 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010002"));
|
||
|
||
var bytes3 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010003"));
|
||
|
||
var bytes4 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010004"));
|
||
|
||
var bytes9 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010005"));
|
||
|
||
var bytes5 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020001"));
|
||
|
||
var bytes6 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020002"));
|
||
|
||
var bytes7 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020003"));
|
||
|
||
var bytes8 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020004"));
|
||
|
||
var bytes10 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
||
Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020005"));
|
||
|
||
|
||
return new List<byte[]> { bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10 };
|
||
}
|
||
|
||
#region 旧版
|
||
/// <summary>
|
||
/// 构建设置时段下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="ammeterAddress"></param>
|
||
/// <param name="modelCode"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <param name="data"></param>
|
||
/// <returns></returns>
|
||
//public static List<byte[]> BuildAmmeterSetTimeSetSendCmd(string address, string ammeterAddress, string modelCode, int port, string baudRate, List<TimeSetDetail> data)
|
||
//{
|
||
// List<byte[]> bytesList = new List<byte[]>();
|
||
// if (modelCode == "DTSU193")
|
||
// {
|
||
// return null;
|
||
// }
|
||
// else if (modelCode == "PMAC9523")
|
||
// {
|
||
// var dataUnitList = Build645SendData.BuildPMAC9523AmmeterSetTimeSetSendDataUnit(ammeterAddress, data);
|
||
// foreach (var dataUnit in dataUnitList)
|
||
// {
|
||
// var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit, StopBit.Stop1, Parity.None);
|
||
// bytesList.Add(bytes);
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// #region 采用TimeSet方法设置 弃用
|
||
// //List<string> fm = null;
|
||
// //SendInfo sendInfo = null;
|
||
// //List<SendInfo> tempSi = new List<SendInfo>();
|
||
// ////判断是否需要进入编程模式,获取编程模式指令
|
||
// //var pm = ProgramModelConfig.ProgramModels.FirstOrDefault(n => n.BrandName == meterInfo.brand_name
|
||
// //&& n.Model == meterInfo.model_name);
|
||
// //if (pm != null)
|
||
// //{
|
||
// // if (pm.IsEnter)
|
||
// // {
|
||
// // //编程指令
|
||
// // var bccmd= pm.cmdData;
|
||
// // //替换表地址
|
||
// // var addressList= Protocol.QGDW3761.DataTypeConvert.CutStr(meterInfo.meter_address, 2, true);
|
||
// // var addressstr = string.Join(" ",addressList);
|
||
// // bccmd = bccmd.Replace("AA AA AA AA AA AA", addressstr);
|
||
// // fm = bccmd.Split(' ').ToList();
|
||
|
||
// // //生成CRC
|
||
// // var CRC = Protocol.QGDW3761.DataTypeConvert.GetCRC(fm);
|
||
// // fm.Add(CRC);
|
||
// // fm.Add("16");
|
||
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.ProgramModel,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // si.Add(sendInfo);
|
||
// // }
|
||
// // //年时区数
|
||
// // int yearTimeZoneCount = 0;
|
||
// // //日时段数
|
||
// // int dayTimeZoneCount = 0;
|
||
// // //费率
|
||
// // int rate = 0;
|
||
// // //发送两套时区
|
||
// // for (int j = 1; j <= 2; j++)
|
||
// // {
|
||
// // //发送时区表数据
|
||
// // var timeZoneData = GenerateTimeZone(sDto);
|
||
// // yearTimeZoneCount = timeZoneData.Count / 3;
|
||
// // fm = GenerateCTCommand($"040{j}0000", string.Join("", timeZoneData));
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.SetTimeSet,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // tempSi.Add(sendInfo);
|
||
// // //发送日时段数据
|
||
// // for (int i = 1; i <= sDto.data.Count; i++)
|
||
// // {
|
||
// // var dayTimeZone = GenerateDayTimeZone(sDto.data[i - 1].data);
|
||
|
||
// // fm = GenerateCTCommand($"040{j}000{i}", string.Join("", dayTimeZone));
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.SetTimeSet,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // tempSi.Add(sendInfo);
|
||
|
||
// // //计算日时段数
|
||
// // var dz = dayTimeZone.Count / 3;
|
||
// // if (dz > dayTimeZoneCount) dayTimeZoneCount = dz;
|
||
// // //计算费率
|
||
|
||
// // foreach(var detail in sDto.data[i - 1].data)
|
||
// // {
|
||
// // int rt = Convert.ToInt32(detail.rate);
|
||
// // if (rt > rate) rate = rt;
|
||
// // }
|
||
|
||
|
||
// // }
|
||
// // }
|
||
|
||
// // #region 年时区数(NN)
|
||
// // fm = GenerateCTCommand($"04000201", yearTimeZoneCount.ToString().PadLeft(2, '0'));
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.SetTimeSet,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // si.Add(sendInfo);
|
||
// // #endregion
|
||
// // #region 日时段数据(NN)
|
||
// // fm = GenerateCTCommand($"04000202", sDto.data.Count.ToString().PadLeft(2, '0'));
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.SetTimeSet,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // si.Add(sendInfo);
|
||
// // #endregion
|
||
// // #region 日时段数(每日切换数)(NN)
|
||
// // fm = GenerateCTCommand($"04000203", dayTimeZoneCount.ToString().PadLeft(2, '0'));
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.SetTimeSet,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // si.Add(sendInfo);
|
||
// // #endregion
|
||
// // #region 费率数(NN)
|
||
// // fm = GenerateCTCommand($"04000204", rate.ToString().PadLeft(2, '0'));
|
||
// // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true);
|
||
// // sendInfo = new SendInfo
|
||
// // (
|
||
// // confirmResult.msa,
|
||
// // confirmResult.cmd16,
|
||
// // MeterType.Ammeter,
|
||
// // CmdType.SetTimeSet,
|
||
// // null,
|
||
// // sDto
|
||
// // );
|
||
// // si.Add(sendInfo);
|
||
// // #endregion
|
||
// // si.AddRange(tempSi);
|
||
|
||
// // tempSi.Clear();
|
||
// // // si[si.Count - 1].cmdType = CmdType.SetTimeSet;//取最后一条指令的结果返回
|
||
// //}
|
||
|
||
// #endregion
|
||
// }
|
||
// return bytesList;
|
||
//}
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 构建时段设置下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="ammeterAddress"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <param name="timeSetDetails"></param>
|
||
/// <returns></returns>
|
||
public static List<byte[]> BuildAmmeterSetTimeSetSendCmd(string address, string ammeterAddress,string password,int port, string baudRate, List<TimeSetDetail> timeSetDetails)
|
||
{
|
||
List<byte[]> bytesList = new List<byte[]>();
|
||
//Cmd写死 programmodel.json
|
||
string cmd = "";
|
||
var generateBCDataUnit = Build645SendData.BuildAmmeterGenerateBCCommand(ComandCodeEnum.SpecialMeter_A, ammeterAddress, cmd, password,
|
||
"", "");
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, generateBCDataUnit, StopBit.Stop1, Parity.None);
|
||
bytesList.Add(bytes);
|
||
|
||
|
||
List<SetAmmeterJFPGEntity> listdata = new List<SetAmmeterJFPGEntity>();
|
||
List<SetAmmeterJFPGEntity> templistdata = new List<SetAmmeterJFPGEntity>();
|
||
|
||
#region 排序
|
||
var timeSets = timeSetDetails;
|
||
Dictionary<int, TimeSetDetail> dicTsDetails = new Dictionary<int, TimeSetDetail>();
|
||
foreach (var timeSet in timeSets)
|
||
{
|
||
int firstMonty = timeSet.Months[0];
|
||
if (!dicTsDetails.Keys.Contains(firstMonty))
|
||
dicTsDetails.Add(firstMonty, timeSet);
|
||
}
|
||
|
||
var sortKeys = dicTsDetails.Keys.OrderBy(n => n).ToList();
|
||
List<TimeSetDetail> orderTsDetails = new List<TimeSetDetail>();
|
||
foreach (var key in sortKeys)
|
||
{
|
||
orderTsDetails.Add(dicTsDetails[key]);
|
||
}
|
||
|
||
timeSetDetails = orderTsDetails;
|
||
|
||
#endregion
|
||
|
||
//年时区数
|
||
int yearTimeZoneCount = 0;
|
||
//日时段数/日切换数
|
||
int dayTimeZoneCount = 0;
|
||
//费率
|
||
int rate = 0;
|
||
for (int j = 1; j <= 2; j++)
|
||
{
|
||
|
||
SetAmmeterJFPGEntity setJFPGTool = new SetAmmeterJFPGEntity();
|
||
setJFPGTool.ComandCode = ComandCodeEnum.SpecialMeter_B;
|
||
//发送时区表数据
|
||
var timeZoneData = GenerateTimeZone(timeSetDetails);
|
||
setJFPGTool.DataMark = $"040{j}0000";
|
||
setJFPGTool.Data = timeZoneData;
|
||
templistdata.Add(setJFPGTool);
|
||
|
||
yearTimeZoneCount = timeZoneData.Length / 6;
|
||
|
||
//发送日时段数据
|
||
for (int i = 1; i <= timeSets.Count; i++)
|
||
{
|
||
setJFPGTool = new SetAmmeterJFPGEntity();
|
||
|
||
setJFPGTool.ComandCode = ComandCodeEnum.SpecialMeter_B;
|
||
var dayTimeZone = GenerateDayTimeZone(timeSets[i - 1].Data);
|
||
var dataMark = $"040{j}000{i}";
|
||
setJFPGTool.DataMark = dataMark;
|
||
setJFPGTool.Data = dayTimeZone;
|
||
templistdata.Add(setJFPGTool);
|
||
|
||
//计算日时段数
|
||
var dz = dayTimeZone.Length / 6;
|
||
if (dz > dayTimeZoneCount) dayTimeZoneCount = dz;
|
||
//计算费率
|
||
foreach (var detail in timeSets[i - 1].Data)
|
||
{
|
||
var rt = Convert.ToInt32(detail.Rate);
|
||
if (rt > rate) rate = rt;
|
||
}
|
||
}
|
||
}
|
||
#region 年时区数(NN)
|
||
listdata.Add(new SetAmmeterJFPGEntity()
|
||
{
|
||
Data = yearTimeZoneCount.ToString().PadLeft(2, '0'),
|
||
DataMark = "04000201",
|
||
ComandCode = ComandCodeEnum.SpecialMeter_B
|
||
});
|
||
#endregion
|
||
#region 日时段数(NN)
|
||
listdata.Add(new SetAmmeterJFPGEntity()
|
||
{
|
||
Data = timeSets.Count.ToString().PadLeft(2, '0'),
|
||
DataMark = "04000202",
|
||
ComandCode = ComandCodeEnum.SpecialMeter_B
|
||
});
|
||
#endregion
|
||
#region 日切换数(NN)
|
||
listdata.Add(new SetAmmeterJFPGEntity()
|
||
{
|
||
Data = dayTimeZoneCount.ToString().PadLeft(2, '0'),
|
||
DataMark = "04000203",
|
||
ComandCode = ComandCodeEnum.SpecialMeter_B
|
||
});
|
||
#endregion
|
||
#region 费率数(NN)
|
||
listdata.Add(new SetAmmeterJFPGEntity()
|
||
{
|
||
Data = rate.ToString().PadLeft(2, '0'),
|
||
DataMark = "04000204",
|
||
ComandCode = ComandCodeEnum.SpecialMeter_B
|
||
});
|
||
#endregion
|
||
|
||
listdata.AddRange(templistdata);
|
||
templistdata.Clear();
|
||
|
||
foreach (var item in listdata)
|
||
{
|
||
var timeSetDataUnit =
|
||
Build645SendData.BuildAmmeterTimeSetSendDataUnit(ammeterAddress, password, item.DataMark,
|
||
item.Data);
|
||
var timeSetBytes = BuildTransparentForwardingSendCmd(address, port, baudRate, timeSetDataUnit, StopBit.Stop1, Parity.None);
|
||
bytesList.Add(timeSetBytes);
|
||
}
|
||
|
||
return bytesList;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表参数设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="meterParameters"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildAmmeterParameterSetSendCmd(string address, List<AmmeterParameter> meterParameters)
|
||
{
|
||
var dataUnit = BuildAmmeterParameterSendDataUnit(meterParameters);
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.设置参数,
|
||
FunCode = (int)CMasterStationFunCode.请求1级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 10
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表参数读取-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="meterNumberList">对象序号</param>
|
||
public static byte[] BuildAmmeterParameterReadingSendCmd(string address, List<int> meterNumberList)
|
||
{
|
||
var dataUnit = new List<string>();
|
||
var countHex = meterNumberList.Count().DecToHex().PadLeft(4, '0');
|
||
var countHexPairs = countHex.StringToPairs();
|
||
countHexPairs.Reverse();
|
||
dataUnit.AddRange(countHexPairs);
|
||
|
||
foreach (var number in meterNumberList)
|
||
{
|
||
var numberHex = number.DecToHex().PadLeft(4, '0');
|
||
var numberHexPairs = numberHex.StringToPairs();
|
||
numberHexPairs.Reverse();
|
||
dataUnit.AddRange(numberHexPairs);
|
||
}
|
||
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.查询参数,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 0,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 10
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表抄读一类数据-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="pn"></param>
|
||
/// <param name="aTypeOfDataItems">一类数据项</param>
|
||
public static byte[] BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems)
|
||
{
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求实时数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = (int)aTypeOfDataItems
|
||
};
|
||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表抄读日冻结正向有功电能示值-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="pn"></param>
|
||
/// <param name="time"></param>
|
||
public static void BuildAmmeterReadDailyFreezingDataSendCmd(string address, int pn, DateTime time)
|
||
{
|
||
var dataUnit = time.ToString("yy-MM-dd").Split('-').ToList();
|
||
dataUnit.Reverse();
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求历史数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = 161
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表抄读实时电流-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="pn"></param>
|
||
public static void BuildAmmeterRealTimeCurrentDataSendCmd(string address, int pn)
|
||
{
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求实时数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = 25
|
||
};
|
||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建自动上报开启状态读取-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="pn"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildAmmeterReadAutoUpSwitchSendCmd(string address, int pn)
|
||
{
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.查询参数,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = 68
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建自动上报开启状态设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="pn"></param>
|
||
/// <param name="isOpen"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildAmmeterAutoUpSwitchSetSendCmd(string address, int pn,bool isOpen)
|
||
{
|
||
var dataUnit = new List<string>(){ isOpen ? "55" : "AA" };//自动上报任务命令字节
|
||
dataUnit.AddRange(GetPW());
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.设置参数,
|
||
FunCode = (int)CMasterStationFunCode.请求1级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = 68
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 构建自动上报采集项设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="pn">计量点</param>
|
||
/// <param name="unit"> 定时发送周期(单位)</param>
|
||
/// <param name="cycle">定时发送周期 1:用 D6~D7 编码表示,取值 0~3 依次表示分、时、日、月 2:用 D0~D5 表示,为定时上报数据的时间周期</param>
|
||
/// <param name="baseTime">发送基准时间</param>
|
||
/// <param name="curveRatio">曲线数据提取倍率</param>
|
||
/// <param name="pnFns"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildAmmeterReportCollectionItemsSetSendCmd(string address, int pn,int unit,int cycle,DateTime baseTime,int curveRatio,List<PnFn> pnFns)
|
||
{
|
||
List<string> dataUnit = new List<string>();
|
||
|
||
var cycleSb = $"{unit.DecToBin()}{cycle.DecToBin()}";
|
||
dataUnit.Add(cycleSb.BinToHex().PadLeft(2, '0'));
|
||
dataUnit.AddRange(baseTime.ToString("ssmmHHddMMyy").StringToPairs());//发送基准时间
|
||
dataUnit.Add(curveRatio.DecToHex().PadLeft(2, '0'));//曲线数据提取倍率
|
||
dataUnit.Add(pnFns.Count.DecToHex().PadLeft(2, '0'));//数据单元标识个数 n
|
||
|
||
foreach (var item in pnFns)
|
||
{
|
||
dataUnit.AddRange(BuildDA(item.Pn));//单元数据标记、单元数据
|
||
dataUnit.AddRange(BuildDT(item.Fn));//单元数据标记、单元数据
|
||
}
|
||
|
||
dataUnit.AddRange(GetPW());
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.设置参数,
|
||
FunCode = (int)CMasterStationFunCode.请求1级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = 66
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表读取二类数据-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="pn"></param>
|
||
/// <param name="iIDataTypeItems">fn</param>
|
||
/// <param name="density">冻结密度</param>
|
||
/// <param name="points">冻结点数</param>
|
||
/// <param name="beginTime">起始时间</param>
|
||
public static byte[] BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density, int points, DateTime? beginTime = null)
|
||
{
|
||
var queryDate = beginTime ?? DateTime.Today.AddDays(-1);
|
||
var dataUnit = queryDate.ToString("yyMMddHHmm").StringToPairs();
|
||
dataUnit.Reverse();
|
||
|
||
//冻结密度
|
||
dataUnit.Add(((int)density).DecToHex());
|
||
|
||
dataUnit.Add(points.DecToHex());
|
||
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求历史数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = (int)iIDataTypeItems
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表读取二类数据-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="pn"></param>
|
||
/// <param name="iIDataTypeItems">fn</param>
|
||
/// <param name="tdType">数据时标</param>
|
||
/// <param name="beginTime">起始时间</param>
|
||
public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, TdType tdType, DateTime? beginTime = null)
|
||
{
|
||
var queryDate = beginTime ?? DateTime.Today.AddDays(-1);
|
||
List<string>? dataUnit = null;
|
||
switch (tdType)
|
||
{
|
||
case TdType.Td_d:
|
||
dataUnit = queryDate.ToString("yyMMdd").StringToPairs();
|
||
break;
|
||
case TdType.Td_m:
|
||
dataUnit = queryDate.ToString("yyMM").StringToPairs();
|
||
break;
|
||
}
|
||
|
||
if (dataUnit == null) return;
|
||
|
||
dataUnit.Reverse();
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求历史数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = (int)iIDataTypeItems
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 组装有/无功电量
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="pn"></param>
|
||
/// <param name="cmdType"></param>
|
||
public static void BuildAmmeterReadingElectricityDataSendCmd(string address, int pn, int cmdType)
|
||
{
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求实时数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = pn,
|
||
Fn = cmdType
|
||
};
|
||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建超功率设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="modelCode"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <param name="power"></param>
|
||
public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password, string modelCode, int port, string baudRate, decimal power)
|
||
{
|
||
if (power > 0)
|
||
{
|
||
|
||
WsOnSupperPower(address, password, modelCode, true, port, baudRate);
|
||
|
||
//TODO:连续发几条嘛?
|
||
string dataMark;
|
||
//如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001
|
||
if (address.IndexOf('_') > 0)
|
||
{
|
||
var addressSplit = address.Split('_');
|
||
address = addressSplit[0];
|
||
var loop = Convert.ToInt32(addressSplit[1]);
|
||
if (loop == 1) { dataMark = "0E300101"; }
|
||
else if (loop == 2) { dataMark = "0E300201"; }
|
||
else
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
dataMark = "0E300101";
|
||
}
|
||
|
||
var turnData = Build645SendData.AssembleWsSupperPower(address, password, dataMark, power);
|
||
if (turnData != null)
|
||
{
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
WsOnSupperPower(address, password, modelCode, false, port, baudRate);
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建恶性负载绝对功率设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <param name="power"></param>
|
||
public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, string baudRate, decimal power)
|
||
{
|
||
if (power <= 0)
|
||
{
|
||
power = 99;//等于小0 代表关闭
|
||
}
|
||
|
||
string dataMark;
|
||
//如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001
|
||
if (address.IndexOf('_') > 0)
|
||
{
|
||
var addressSplit = address.Split('_');
|
||
address = addressSplit[0];
|
||
|
||
var loop = Convert.ToInt32(addressSplit[1]);
|
||
if (loop == 1) { dataMark = "0E300103"; }
|
||
else if (loop == 2) { dataMark = "0E300203"; }
|
||
else
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
dataMark = "0E300103";
|
||
}
|
||
|
||
var turnData = Build645SendData.AssembleWsAbsolutePowerSetting(address, password, dataMark, power);
|
||
if (turnData != null)
|
||
{
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建恶性负载功率因数设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
/// <param name="power"></param>
|
||
public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, string baudRate, decimal power)
|
||
{
|
||
string dataMark;
|
||
//如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001
|
||
if (address.IndexOf('_') > 0)
|
||
{
|
||
var addressSplit = address.Split('_');
|
||
address = addressSplit[0];
|
||
|
||
var loop = Convert.ToInt32(addressSplit[1]);
|
||
if (loop == 1) { dataMark = "0E300104"; }
|
||
else if (loop == 2) { dataMark = "0E300204"; }
|
||
else
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
dataMark = "0E300104";
|
||
}
|
||
|
||
var turnData = Build645SendData.AssembleWsPowerFactor(address, password, dataMark, power);
|
||
if (turnData != null)
|
||
{
|
||
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 超功率开关
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="password"></param>
|
||
/// <param name="modelCode"></param>
|
||
/// <param name="port"></param>
|
||
/// <param name="baudRate"></param>
|
||
public static void WsOnSupperPower(string address, string password, string modelCode, bool isOn, int port, string baudRate)
|
||
{
|
||
|
||
List<string> modelCodes = new List<string>() { "DDS3102-S2", "DDS71", "DDZY71", "DTZY71", "DSZY71" };
|
||
//这些型号需进入软编程
|
||
if (modelCodes.Contains(modelCode))
|
||
{
|
||
var dataUnit1 = Build645SendData.SoftProgram(address, modelCode, password);
|
||
BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit1);
|
||
}
|
||
|
||
var dataUnit2 = Build645SendData.AssembleWsOnSupperPower(address, password, isOn);
|
||
BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit2);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建水表参数设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="meterParameters"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildWaterMeterParameterSetSendCmd(string address, List<WaterMeterParameter> meterParameters)
|
||
{
|
||
var dataUnit = BuildWaterMeterParameterSendDataUnit(meterParameters);
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.设置参数,
|
||
FunCode = (int)CMasterStationFunCode.请求1级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 10
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建通讯参数设置-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="masterIP">主站ip</param>
|
||
/// <param name="masterPort">主站端口</param>
|
||
/// <param name="backupIP">备用ip和端口</param>
|
||
/// <param name="backupPort">备用ip和端口</param>
|
||
/// <param name="aPN">APN:CMNET 63 6D 6E 65 74</param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildCommunicationParametersSetSendCmd(string address, string masterIP, string masterPort,
|
||
string backupIP, string backupPort, string aPN)
|
||
{
|
||
var dataUnit = new List<string>();
|
||
var masterIPList = masterIP.Split('.').Select(it => int.Parse(it).DecToHex().PadLeft(2, '0')).ToList();
|
||
dataUnit.AddRange(masterIPList);
|
||
|
||
var masterPortList = int.Parse(masterPort).DecToHex().PadLeft(4, '0').StringToPairs();
|
||
masterPortList.Reverse();
|
||
dataUnit.AddRange(masterPortList);
|
||
|
||
var backupIPList = backupIP.Split('.').Select(it => int.Parse(it).DecToHex().PadLeft(2, '0')).ToList();
|
||
dataUnit.AddRange(backupIPList);
|
||
|
||
var backupPortList = int.Parse(backupPort).DecToHex().PadLeft(4, '0').StringToPairs();
|
||
backupPortList.Reverse();
|
||
dataUnit.AddRange(backupPortList);
|
||
|
||
var aPNList = aPN.ToCharArray().Select(it => Convert.ToInt32(it).DecToHex().PadLeft(2, '0')).ToList();
|
||
aPNList.AddRange(Enumerable.Repeat("00", 16 - aPNList.Count));
|
||
dataUnit.AddRange(aPNList);
|
||
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.设置参数,
|
||
FunCode = (int)CMasterStationFunCode.请求1级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 3
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建抄读终端日历时钟-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
public static byte[] BuildTerminalCalendarClockSendCmd(string address)
|
||
{
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求实时数据,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 2
|
||
};
|
||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建终端版本信息读取-下发命令
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
public static byte[] BuildTerminalVersionInfoReadingSendCmd(string address)
|
||
{
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.请求终端配置,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 2,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 1
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 集中器校时 秒、分、时、日、星期-月(3-1+4)、年
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <param name="time"></param>
|
||
/// <param name="isManual"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildConrCheckTimeSendCmd(string address, DateTime time,bool isManual)
|
||
{
|
||
List<string> dataUnit;
|
||
if (isManual)
|
||
{
|
||
var week = ((int)time.DayOfWeek).DecToBin().PadLeft(3, '0');
|
||
var monthTemp = time.Month.ToString().PadLeft(2, '0');
|
||
var m1 = int.Parse(monthTemp[0].ToString()).DecToBin();//十位
|
||
var m2 = int.Parse(monthTemp[1].ToString()).DecToBin().PadLeft(4, '0');//个位
|
||
var weekAndMonthHex = (week + m1 + m2).BinToHex().ToUpper();
|
||
|
||
var strTimeFm = time.ToString("ss mm HH dd $$ yy").Replace("$$", weekAndMonthHex);
|
||
dataUnit = strTimeFm.Replace(" ", "").StringToPairs();
|
||
}
|
||
else
|
||
{
|
||
dataUnit = new List<string>(){"EE","EE","EE","EE"};
|
||
}
|
||
|
||
dataUnit.AddRange(GetPW());
|
||
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.控制命令,
|
||
FunCode = (int)CMasterStationFunCode.请求1级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 31
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 硬件初始化
|
||
/// </summary>
|
||
/// <param name="address"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildConrRebootSendCmd(string address)
|
||
{
|
||
var dataUnit = GetPW();
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.复位,
|
||
FunCode = (int)CMasterStationFunCode.复位命令,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.需要对该帧进行确认,
|
||
PRSEQ = 10,
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 1
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建透明转发-下发命令
|
||
/// </summary>
|
||
/// <param name="address">集中器地址</param>
|
||
/// <param name="port">终端通信端口 1~31</param>
|
||
/// <param name="baudRate">300,600,1200,2400,4800,7200,9600,19200对应 0~7</param>
|
||
/// <param name="datas">转发内容</param>
|
||
/// <param name="stopBit">停止位</param>
|
||
/// <param name="parity">校验方式</param>
|
||
/// <param name="dataBit">数据位</param>
|
||
/// <param name="waitContentTimeout">等待报文超时时间/s</param>
|
||
/// <param name="waitByteTimeout">等待字节超时时间/ms</param>
|
||
public static byte[] BuildTransparentForwardingSendCmd(string address, int port, string baudRate, List<string> datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8,
|
||
int waitContentTimeout = 100, int waitByteTimeout = 100)
|
||
{
|
||
var baudRateValue = GetBaudreate(baudRate);
|
||
|
||
var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRateValue, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout);
|
||
dataUnit.AddRange(GetPW());
|
||
var reqParameter = new ReqParameter2()
|
||
{
|
||
AFN = AFN.数据转发,
|
||
FunCode = (int)CMasterStationFunCode.请求2级数据,
|
||
A = address,
|
||
Seq = new Seq()
|
||
{
|
||
TpV = TpV.附加信息域中无时间标签,
|
||
FIRFIN = FIRFIN.单帧,
|
||
CON = CON.不需要对该帧进行确认,
|
||
PRSEQ = 0
|
||
},
|
||
MSA = GetMSA(address),
|
||
Pn = 0,
|
||
Fn = 1
|
||
};
|
||
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据波特率获取值
|
||
/// </summary>
|
||
/// <param name="val"></param>
|
||
/// <returns></returns>
|
||
public static int GetBaudreate(string val)
|
||
{
|
||
var type = 0;
|
||
switch (val)
|
||
{
|
||
case "300": type = 0; break;
|
||
case "600": type = 1; break;
|
||
case "1200": type = 2; break;
|
||
case "2400": type = 3; break;
|
||
case "4800": type = 4; break;
|
||
case "7200": type = 5; break;
|
||
case "9600": type = 6; break;
|
||
case "19200": type = 7; break;
|
||
}
|
||
return type;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据波特率获取值
|
||
/// </summary>
|
||
/// <param name="val"></param>
|
||
/// <returns></returns>
|
||
public static int GetProtocolType(string val)
|
||
{
|
||
var type = 0;
|
||
switch (val)
|
||
{
|
||
case "DL/T 645—2007": type = 30; break;
|
||
case "DL/T 645—1997": type = 1; break;
|
||
case "交流采样装置": type = 2; break;
|
||
case "串行接口连接窄带低压载波通讯": type = 31; break;
|
||
}
|
||
return type;
|
||
}
|
||
|
||
[Obsolete]
|
||
public static 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 = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();
|
||
if (specialnocode == "1D" || modelCode == "SZBD_DDZY1225")
|
||
strDate = "FF FF FF FF FF FF";
|
||
string strP = password.StrAddSpan().StrReverseOrder();
|
||
string strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + Code + " 00 " + strDate;
|
||
string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2");
|
||
string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " ";
|
||
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="port">终端通信端口 1~31</param>
|
||
/// <param name="baudRate">0~7 对应300,600,1200,2400,4800,7200,9600,19200</param>
|
||
/// <param name="datas">转发内容</param>
|
||
/// <param name="stopBit">停止位</param>
|
||
/// <param name="parity">校验方式</param>
|
||
/// <param name="dataBit">数据位</param>
|
||
/// <param name="waitContentTimeout">等待报文超时时间/s</param>
|
||
/// <param name="waitByteTimeout">等待字节超时时间/ms</param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildTransparentForwardingSendDataUnit(int port, int baudRate, List<string> datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8,
|
||
int waitContentTimeout = 100, int waitByteTimeout = 100)
|
||
{
|
||
var dataUnit = new List<string>();
|
||
|
||
var portHex = port.DecToHex().PadLeft(2, '0');
|
||
dataUnit.Add(portHex);
|
||
|
||
var baudRateBin = baudRate.DecToBin().PadLeft(3, '0');
|
||
var stopBitBin = ((int)stopBit).DecToBin();
|
||
var parityBin = parity != Parity.None ? $"1{((int)parity).DecToBin()}" : "00";
|
||
var dataBitBin = ((int)dataBit).DecToBin().PadLeft(2, '0');
|
||
var controlHex = $"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}".BinToHex().PadLeft(2, '0'); ;
|
||
dataUnit.Add(controlHex);
|
||
|
||
var waitContentTimeoutBin = $"1{waitContentTimeout.DecToBin().PadLeft(7, '0')}";
|
||
var waitContentTimeoutHex = waitContentTimeoutBin.BinToHex().PadLeft(2, '0');
|
||
var waitByteTimeoutHex = waitByteTimeout.DecToHex().PadLeft(2, '0');
|
||
|
||
dataUnit.Add(waitContentTimeoutHex);
|
||
dataUnit.Add(waitByteTimeoutHex);
|
||
|
||
var countHex = datas.Count.DecToHex().PadLeft(4, '0');
|
||
var countHexPairs = countHex.StringToPairs();
|
||
countHexPairs.Reverse();
|
||
dataUnit.AddRange(countHexPairs);
|
||
|
||
dataUnit.AddRange(datas);
|
||
|
||
return dataUnit;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建下发命令
|
||
/// </summary>
|
||
/// <param name="reqParameter"></param>
|
||
/// <param name="dataUnit"></param>
|
||
/// <returns></returns>
|
||
public static byte[] BuildSendCommandBytes(ReqParameter reqParameter, List<string>? dataUnit = null)
|
||
{
|
||
var cmdStrList = new List<string>();
|
||
var userDatas = BuildUserData(reqParameter, dataUnit);
|
||
var hearders = BuildHeaders(userDatas.Count);
|
||
var cs = GetCS(userDatas);
|
||
cmdStrList.AddRange(hearders);
|
||
cmdStrList.AddRange(userDatas);
|
||
cmdStrList.Add(cs);
|
||
cmdStrList.Add(endStr);
|
||
//Console.WriteLine(string.Join(" ", cmdStrList));
|
||
var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray();
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建电表参数设置-下发数据单元
|
||
/// </summary>
|
||
/// <param name="meterParameters"></param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildAmmeterParameterSendDataUnit(List<AmmeterParameter> meterParameters)
|
||
{
|
||
var hexDatas = new List<string>();
|
||
|
||
var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0');
|
||
hexDatas.Add(countHex);
|
||
|
||
for (int i = 0; i <= meterParameters.Count - 1; i++)
|
||
{
|
||
var meter = meterParameters[i];
|
||
|
||
//var indexHex = (i + 1).DecToHex().PadLeft(4, '0');
|
||
var indexHex = meter.SerialNumber.DecToHex().PadLeft(4, '0');
|
||
hexDatas.Add(indexHex);
|
||
|
||
var pnHex = meter.Pn.DecToHex().PadLeft(4, '0');
|
||
hexDatas.Add(pnHex);
|
||
|
||
var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0');
|
||
var portBin = meter.Port.DecToBin().PadLeft(5, '0');
|
||
var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0');
|
||
hexDatas.Add(baudRateAndPortHex);
|
||
|
||
var protocolTypeHex = ((int)meter.ProtocolType).DecToHex().PadLeft(2, '0');
|
||
hexDatas.Add(protocolTypeHex);
|
||
|
||
hexDatas.Add(meter.Address);
|
||
|
||
hexDatas.Add(meter.Password.PadLeft(12, '0'));
|
||
|
||
var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}";
|
||
var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0');
|
||
hexDatas.Add(rateNumberHex);
|
||
|
||
var intBitNumberBin = (meter.IntegerBitNumber - 4).DecToBin().PadLeft(2, '0');
|
||
var decBitNumberBin = (meter.DecimalBitNumber - 1).DecToBin().PadLeft(2, '0');
|
||
var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}";
|
||
var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0');
|
||
hexDatas.Add(intAndDecBitNumberHex);
|
||
|
||
hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0'));
|
||
|
||
var userCategoryNumber = 0;//meter.UserCategoryNumber
|
||
var userSubclassNumber = 0;//meter.UserSubclassNumber
|
||
if (meter.ProtocolType == 32) userCategoryNumber = 1;
|
||
else if (meter.ProtocolType == 45) { userCategoryNumber = 1; userSubclassNumber = 9; }
|
||
|
||
var userCategoryNumberBin = userCategoryNumber.DecToBin().PadLeft(4, '0');
|
||
var userSubclassNumberBin = userSubclassNumber.DecToBin().PadLeft(4, '0');
|
||
var userNumberHex = $"{userCategoryNumberBin}{userSubclassNumberBin}".BinToHex().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 = hexData.StringToPairs();
|
||
lst.Reverse();
|
||
datas.AddRange(lst);
|
||
}
|
||
}
|
||
datas.AddRange(GetPW());
|
||
return datas;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建水表参数设置-下发数据单元
|
||
/// </summary>
|
||
/// <param name="meterParameters"></param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildWaterMeterParameterSendDataUnit(List<WaterMeterParameter> meterParameters)
|
||
{
|
||
var hexDatas = new List<string>();
|
||
|
||
var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0');
|
||
hexDatas.Add(countHex);
|
||
|
||
for (int i = 0; i <= meterParameters.Count - 1; i++)
|
||
{
|
||
|
||
var meter = meterParameters[i];
|
||
var protocolType = (int)meter.ProtocolType;
|
||
|
||
var currentProtocolType = protocolType;
|
||
if (protocolType == 43)
|
||
currentProtocolType = 1;
|
||
else if (protocolType > 32) currentProtocolType = 32;
|
||
|
||
//TODO:无线水表 小数位
|
||
if (currentProtocolType == 32 && meter.Address.Substring(0, 2) != "00")
|
||
{
|
||
var ejz = meter.Address.Substring(0, 2).HexToBin().PadLeft(8, '0');
|
||
var xs = ejz.Substring(6, 2).BinToDec();
|
||
var zs = ejz.Substring(0, 6).BinToDec();
|
||
//userData.Add(new QGDW3671UserData() { Name = "整数位无线水表", Value = zs });
|
||
//userData.Add(new QGDW3671UserData() { Name = "小数位无线水表", Value = xs });
|
||
}
|
||
|
||
var userCategoryNumber = meter.UserCategoryNumber;
|
||
var userSubclassNumber = meter.UserSubclassNumber;
|
||
|
||
if (protocolType == 32)
|
||
userCategoryNumber = 1;
|
||
else if (protocolType == 45)
|
||
{
|
||
userCategoryNumber = 1;
|
||
userSubclassNumber = 9;
|
||
}
|
||
else if (protocolType == 1)
|
||
userSubclassNumber = 1;
|
||
|
||
var indexHex = (i + 1).DecToHex().PadLeft(4, '0');
|
||
hexDatas.Add(indexHex);
|
||
|
||
var pnHex = meter.Pn.DecToHex().PadLeft(4, '0');
|
||
hexDatas.Add(pnHex);
|
||
|
||
var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0');
|
||
var portBin = meter.Port.DecToBin().PadLeft(5, '0');
|
||
var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0');
|
||
hexDatas.Add(baudRateAndPortHex);
|
||
|
||
var protocolTypeHex = currentProtocolType.DecToHex().PadLeft(2, '0');
|
||
hexDatas.Add(protocolTypeHex);
|
||
|
||
hexDatas.Add(meter.Address);
|
||
|
||
hexDatas.Add(meter.Password.PadLeft(12, '0'));
|
||
|
||
var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}";
|
||
var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0');
|
||
hexDatas.Add(rateNumberHex);
|
||
|
||
var intBitNumberBin = meter.IntegerBitNumber.DecToBin().PadLeft(2, '0');
|
||
var decBitNumberBin = meter.DecimalBitNumber.DecToBin().PadLeft(2, '0');
|
||
var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}";
|
||
var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0');
|
||
hexDatas.Add(intAndDecBitNumberHex);
|
||
|
||
hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0'));
|
||
|
||
var userCategoryNumberBin = userCategoryNumber.DecToBin().PadLeft(4, '0');
|
||
var userSubclassNumberBin = userSubclassNumber.DecToBin().PadLeft(4, '0');
|
||
var userNumberHex = $"{userCategoryNumberBin}{userSubclassNumberBin}".BinToHex().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 = hexData.StringToPairs();
|
||
lst.Reverse();
|
||
datas.AddRange(lst);
|
||
}
|
||
}
|
||
datas.AddRange(GetPW());
|
||
return datas;
|
||
}
|
||
|
||
|
||
//AUX=消息认证码字段(PW,16个字节)
|
||
private static List<string> GetPW()
|
||
{
|
||
var str = "00";
|
||
var pWList = Enumerable.Repeat(str, pWLen).ToList();
|
||
return pWList;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 帧校验和
|
||
/// </summary>
|
||
/// <param name="userData">用户数据区</param>
|
||
/// <returns></returns>
|
||
private static 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");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 用户数据区
|
||
/// </summary>
|
||
/// <param name="reqParameter"></param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildUserData(ReqParameter reqParameter, List<string>? dataUnit)
|
||
{
|
||
var c = BuildC(reqParameter.FunCode, reqParameter.PRM);
|
||
var a = BuildAList(reqParameter.A, reqParameter.MSA);
|
||
|
||
var linkUserData = BuildLinkUserData(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>
|
||
/// 固定长度的报文头 起始字符+长度+长度+起始字符
|
||
/// </summary>
|
||
/// <param name="length"></param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildHeaders(int length)
|
||
{
|
||
var headers = new List<string>();
|
||
headers.Add(startStr);
|
||
var l = BuildLength(length);
|
||
headers.AddRange(l);
|
||
headers.AddRange(l);
|
||
headers.Add(startStr);
|
||
return headers;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 长度 2字节 [用户数据区长度]
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static List<string> BuildLength(int length1)
|
||
{
|
||
var binaryLen = length1.DecToBin();
|
||
var protocolIdentification = Enum.Format(typeof(ProtocolIdentification),
|
||
ProtocolIdentification.本规约使用, "d").PadLeft(2, '0');
|
||
var lenStr = $"{binaryLen}{protocolIdentification}";
|
||
var hexLen = lenStr.BinToHex();
|
||
hexLen = hexLen.PadLeft(4, '0');
|
||
var list = hexLen.StringToPairs();
|
||
list.Reverse();
|
||
return list;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 控制域
|
||
/// </summary>
|
||
/// <param name="funCode">功能码</param>
|
||
/// <param name="fcb"></param>
|
||
/// <param name="fcv"></param>
|
||
/// <returns></returns>
|
||
private static string BuildC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效)
|
||
{
|
||
var cMasterStationFunCodeHex = funCode.DecToBin();
|
||
cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0');
|
||
var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}";
|
||
var hexC = strC.BinToHex().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 static List<string> BuildAList(string a, int mSA)
|
||
{
|
||
var list = new List<string>();
|
||
|
||
var a1 = a.Substring(0, 4);
|
||
var a1Pairs = a1.StringToPairs();
|
||
a1Pairs.Reverse();
|
||
list.AddRange(a1Pairs);
|
||
|
||
var a2 = Convert.ToInt32(a.Substring(4));
|
||
var decA2 = a2.DecToHex();
|
||
var a2Pairs = decA2.PadLeft(4, '0').StringToPairs();
|
||
a2Pairs.Reverse();
|
||
list.AddRange(a2Pairs);
|
||
|
||
//TODO:主站地址和组地址标志
|
||
var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0";
|
||
list.Add(a3Bin.BinToHex().PadLeft(2, '0'));
|
||
|
||
return list;
|
||
}
|
||
|
||
private static List<string> BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List<string>? dataUnit)
|
||
{
|
||
var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0');
|
||
var sEQ = BuildSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ);
|
||
var dA = BuildDA(pn);
|
||
var dT = BuildDT(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(BuildTp("00"));
|
||
|
||
return list;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 帧序列域
|
||
/// </summary>
|
||
/// <param name="tpV"></param>
|
||
/// <param name="fIRFIN"></param>
|
||
/// <param name="cON"></param>
|
||
/// <returns></returns>
|
||
private static string BuildSEQ(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}{pRSEQ.DecToBin().PadLeft(4, '0')}";
|
||
var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0');
|
||
return hexSEQ;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 信息点标识
|
||
/// </summary>
|
||
/// <param name="pn">计量点</param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildDA(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 = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位
|
||
var dA2Hex = dA2.DecToHex();
|
||
return new List<string>() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') };
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 数据单元标识
|
||
/// </summary>
|
||
/// <param name="fn"></param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildDT(int fn)
|
||
{
|
||
var dT2 = (fn - 1) / 8;//从零开始 第几组
|
||
var dT1 = fn - dT2 * 8;
|
||
var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位
|
||
var dT2Hex = dT2.DecToHex();
|
||
return new List<string>() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 时间标签
|
||
/// </summary>
|
||
/// <param name="pFC">启动帧帧序号计数器PFC 1字节</param>
|
||
/// <param name="delayTime">允许发送传输延时时间 min 1字节</param>
|
||
/// <returns></returns>
|
||
private static List<string> BuildTp(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') };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成时区表数据
|
||
/// </summary>
|
||
/// <param name="sDto"></param>
|
||
/// <returns></returns>
|
||
private static string GenerateTimeZone(List<TimeSetDetail> datas)
|
||
{
|
||
var fm = new List<string>();
|
||
var timeSets = datas;
|
||
for (int i = 1; i <= timeSets.Count; i++)
|
||
{
|
||
var item = timeSets[i - 1];
|
||
var months = item.Months.ToList().OrderBy(n => n).ToArray();
|
||
for (int j = 0; j < months.Length; j++)
|
||
{
|
||
|
||
if (j == 0)
|
||
{
|
||
fm.Add($"{months[j].ToString().PadLeft(2, '0')}01{i.ToString().PadLeft(2, '0')}");
|
||
}
|
||
else
|
||
{
|
||
if (months[j] - months[j - 1] > 1)
|
||
{
|
||
fm.Add($"{months[j].ToString().PadLeft(2, '0')}01{i.ToString().PadLeft(2, '0')}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
fm = fm.OrderByDescending(n => Convert.ToInt32(n)).ToList();
|
||
|
||
|
||
return string.Join("", fm.ToArray());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成日时段数据
|
||
/// </summary>
|
||
/// <param name="sDto"></param>
|
||
/// <returns></returns>
|
||
private static string GenerateDayTimeZone(List<MutileRateDetail> sDto)
|
||
{
|
||
var fm = new List<string>();
|
||
foreach (var item in sDto)
|
||
{
|
||
var sts = item.Times.Select(n => n.StartTime).OrderBy(n => n).ToList();
|
||
for (int j = 0; j < sts.Count; j++)
|
||
{
|
||
|
||
fm.Add($"{sts[j].Replace(":", "")}{item.Rate.PadLeft(2, '0')}");
|
||
|
||
}
|
||
}
|
||
|
||
fm = fm.OrderByDescending(n => Convert.ToInt32(n)).ToList();
|
||
//处理跨天的情况 23:00-7:00 这种需要拆分为2条 需要添加一条00:00 记录 23:00 00:00
|
||
List<string> stTimes = new List<string>();
|
||
// List<string> etTimes = new List<string>();
|
||
foreach (var item in sDto)
|
||
{
|
||
stTimes.AddRange(item.Times.Select(n => n.StartTime).OrderBy(n => n).ToList());
|
||
// etTimes.AddRange(item.times.Select(n => n.endTime).OrderByDescending(n => n).ToList());
|
||
|
||
}
|
||
stTimes = stTimes.OrderBy(n => n).ToList();
|
||
if (!stTimes[0].Equals("00:00"))
|
||
{
|
||
//查出最大时间的费率
|
||
var rate = "0";
|
||
foreach (var item in sDto)
|
||
{
|
||
if (item.Times.Select(n => n.StartTime).Contains(stTimes[stTimes.Count - 1]))
|
||
{
|
||
rate = item.Rate;
|
||
break;
|
||
}
|
||
}
|
||
fm.Add($"{"00:00".Replace(":", "")}{rate.PadLeft(2, '0')}");
|
||
}
|
||
return string.Join("", fm.ToArray());
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
}
|