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 MSA = new List(); static Dictionary> usingMSA = new Dictionary>(); static Build3761SendData() { for (int i = 1; i <= 127; i++) { MSA.Add(i); } } /// /// Gets the msa. /// /// 集中器地址 /// public static int GetMSA(string mark) { lock (locker) { if (!usingMSA.Keys.Contains(mark)) usingMSA.Add(mark, new List()); 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下行命令 /// /// 构建电表修正时间下发命令 /// /// /// /// /// /// /// /// public static List BuildAmmeterCorrectionTimeSendCmd(string address, string modelCode, string ammeterAddress, string password, int port, string baudRate) { var bytesList = new List(); 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; } /// /// 构建电表读取时段设置下发命令 /// /// /// /// /// /// /// /// public static List 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() { 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 { bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10 }; } #region 旧版 /// /// 构建设置时段下发命令 /// /// /// /// /// /// /// /// //public static List BuildAmmeterSetTimeSetSendCmd(string address, string ammeterAddress, string modelCode, int port, string baudRate, List data) //{ // List bytesList = new List(); // 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 fm = null; // //SendInfo sendInfo = null; // //List tempSi = new List(); // ////判断是否需要进入编程模式,获取编程模式指令 // //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 /// /// 构建时段设置下发命令 /// /// /// /// /// /// /// /// public static List BuildAmmeterSetTimeSetSendCmd(string address, string ammeterAddress,string password,int port, string baudRate, List timeSetDetails) { List bytesList = new List(); //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 listdata = new List(); List templistdata = new List(); #region 排序 var timeSets = timeSetDetails; // 旧 //Dictionary dicTsDetails = new Dictionary(); //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 orderTsDetails = new List(); //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; } /// /// 构建电表参数设置-下发命令 /// /// 集中器地址 /// /// public static byte[] BuildAmmeterParameterSetSendCmd(string address, List 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; } /// /// 构建电表参数读取-下发命令 /// /// 集中器地址 /// 对象序号 public static byte[] BuildAmmeterParameterReadingSendCmd(string address, List meterNumberList) { var dataUnit = new List(); 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; } /// /// 构建电表抄读一类数据-下发命令 /// /// /// /// 一类数据项 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; } /// /// 构建电表抄读日冻结正向有功电能示值-下发命令 /// /// /// /// 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); } /// /// 构建电表抄读实时电流-下发命令 /// /// /// 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); } /// /// 构建自动上报开启状态读取-下发命令 /// /// 集中器地址 /// /// 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; } /// /// 构建自动上报开启状态设置-下发命令 /// /// 集中器地址 /// /// /// public static byte[] BuildAmmeterAutoUpSwitchSetSendCmd(string address, int pn,bool isOpen) { var dataUnit = new List(){ 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; } /// /// 构建自动上报采集项设置-下发命令 /// /// 集中器地址 /// 计量点 /// 定时发送周期(单位) /// 定时发送周期 1:用 D6~D7 编码表示,取值 0~3 依次表示分、时、日、月 2:用 D0~D5 表示,为定时上报数据的时间周期 /// 发送基准时间 /// 曲线数据提取倍率 /// /// public static byte[] BuildAmmeterReportCollectionItemsSetSendCmd(string address, int pn,int unit,int cycle,DateTime baseTime,int curveRatio,List pnFns) { List dataUnit = new List(); 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; } /// /// 构建电表读取二类数据-下发命令 /// /// /// /// fn /// 冻结密度 /// 冻结点数 /// 起始时间 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; } /// /// 构建电表读取二类数据-下发命令 /// /// /// /// fn /// 数据时标 /// 起始时间 public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, TdType tdType, DateTime? beginTime = null) { var queryDate = beginTime ?? DateTime.Today.AddDays(-1); List? 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); } /// /// 组装有/无功电量 /// /// /// /// 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); } /// /// 构建超功率设置-下发命令 /// /// /// /// /// /// /// 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); } } /// /// 构建恶性负载绝对功率设置-下发命令 /// /// /// /// /// /// 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); } } /// /// 构建恶性负载功率因数设置-下发命令 /// /// /// /// /// /// 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); } } /// /// 超功率开关 /// /// /// /// /// /// public static void WsOnSupperPower(string address, string password, string modelCode, bool isOn, int port, string baudRate) { List modelCodes = new List() { "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); } /// /// 构建水表参数设置-下发命令 /// /// 集中器地址 /// /// public static byte[] BuildWaterMeterParameterSetSendCmd(string address, List 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; } /// /// 构建通讯参数设置-下发命令 /// /// 集中器地址 /// 主站ip /// 主站端口 /// 备用ip和端口 /// 备用ip和端口 /// APN:CMNET 63 6D 6E 65 74 /// public static byte[] BuildCommunicationParametersSetSendCmd(string address, string masterIP, string masterPort, string backupIP, string backupPort, string aPN) { var dataUnit = new List(); 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; } /// /// 构建抄读终端日历时钟-下发命令 /// /// 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; } /// /// 构建终端版本信息读取-下发命令 /// /// 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; } /// /// 集中器校时 秒、分、时、日、星期-月(3-1+4)、年 /// /// /// /// /// public static byte[] BuildConrCheckTimeSendCmd(string address, DateTime time,bool isManual) { List 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(){"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; } /// /// 硬件初始化 /// /// /// 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; } /// /// 构建透明转发-下发命令 /// /// 集中器地址 /// 终端通信端口 1~31 /// 300,600,1200,2400,4800,7200,9600,19200对应 0~7 /// 转发内容 /// 停止位 /// 校验方式 /// 数据位 /// 等待报文超时时间/s /// 等待字节超时时间/ms public static byte[] BuildTransparentForwardingSendCmd(string address, int port, string baudRate, List 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; } /// /// 根据波特率获取值 /// /// /// 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; } /// /// 根据波特率获取值 /// /// /// 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 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(); } /// /// 构建透明转发-下发数据单元 /// /// 终端通信端口 1~31 /// 0~7 对应300,600,1200,2400,4800,7200,9600,19200 /// 转发内容 /// 停止位 /// 校验方式 /// 数据位 /// 等待报文超时时间/s /// 等待字节超时时间/ms /// private static List BuildTransparentForwardingSendDataUnit(int port, int baudRate, List datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8, int waitContentTimeout = 100, int waitByteTimeout = 100) { var dataUnit = new List(); 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; } /// /// 构建下发命令 /// /// /// /// public static byte[] BuildSendCommandBytes(ReqParameter reqParameter, List? dataUnit = null) { var cmdStrList = new List(); 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; } /// /// 构建电表参数设置-下发数据单元 /// /// /// private static List BuildAmmeterParameterSendDataUnit(List meterParameters) { var hexDatas = new List(); 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(); 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; } /// /// 构建水表参数设置-下发数据单元 /// /// /// private static List BuildWaterMeterParameterSendDataUnit(List meterParameters) { var hexDatas = new List(); 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(); 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 GetPW() { var str = "00"; var pWList = Enumerable.Repeat(str, pWLen).ToList(); return pWList; } /// /// 帧校验和 /// /// 用户数据区 /// private static string GetCS(List userData) { byte sum = 0; foreach (var d in userData) { var b = Convert.ToByte(d, 16); sum += b; } return sum.ToString("X2"); } /// /// 用户数据区 /// /// /// private static List BuildUserData(ReqParameter reqParameter, List? 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() { c }; list.AddRange(a); list.AddRange(linkUserData); return list; } /// /// 固定长度的报文头 起始字符+长度+长度+起始字符 /// /// /// private static List BuildHeaders(int length) { var headers = new List(); headers.Add(startStr); var l = BuildLength(length); headers.AddRange(l); headers.AddRange(l); headers.Add(startStr); return headers; } /// /// 长度 2字节 [用户数据区长度] /// /// private static List 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; } /// /// 控制域 /// /// 功能码 /// /// /// 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; } /// /// 地址域 3220 09872 /// /// 行政区划码 BCD码 3220=2032 /// 逻辑地址 BIN 09872=2690=>9026 /// 主站地址 BIN 0~127 /// private static List BuildAList(string a, int mSA) { var list = new List(); 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 BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List? 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() { 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; } /// /// 帧序列域 /// /// /// /// /// 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; } /// /// 信息点标识 /// /// 计量点 /// private static List BuildDA(int pn) { if (pn == 0) return new List() { "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() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') }; } /// /// 数据单元标识 /// /// /// private static List 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() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') }; } /// /// 时间标签 /// /// 启动帧帧序号计数器PFC 1字节 /// 允许发送传输延时时间 min 1字节 /// private static List 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() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') }; } /// /// 生成时区表数据 /// /// /// private static string GenerateTimeZone(List datas) { var fm = new List(); 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()); } /// /// 生成日时段数据 /// /// /// private static string GenerateDayTimeZone(List sDto) { var fm = new List(); 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 stTimes = new List(); // List etTimes = new List(); 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 } }