1900 lines
75 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.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;
// 新
foreach (var timeSet in timeSets)
{
timeSet.Months = timeSet.Months.OrderBy(m => m).ToArray();
}
timeSetDetails = timeSets;
#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:用 D6D7 编码表示,取值 03 依次表示分、时、日、月 2:用 D0D5 表示,为定时上报数据的时间周期</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>
public 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个字节
public 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)
{
try
{
byte sum = 0;
foreach (var d in userData)
{
var b = Convert.ToByte(d, 16);
sum += b;
}
return sum.ToString("X2");
}
catch(Exception)
{
throw;
}
}
/// <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 && dataUnit.Count > 0)
{
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
}
}