2024-12-19 16:07:07 +08:00
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
|
|
using JiShe.CollectBus.Common.Enums;
|
|
|
|
|
|
using JiShe.CollectBus.Common.Models;
|
|
|
|
|
|
using System.Reflection;
|
2024-12-27 17:00:31 +08:00
|
|
|
|
using System.Net;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
|
|
|
|
|
|
namespace JiShe.CollectBus.Common.Extensions
|
|
|
|
|
|
{
|
|
|
|
|
|
public static class HexStringExtensions
|
|
|
|
|
|
{
|
|
|
|
|
|
//起始字符
|
|
|
|
|
|
private const string startStr = "68";
|
|
|
|
|
|
//结束字符
|
|
|
|
|
|
private const string endStr = "16";
|
|
|
|
|
|
//头部字节长度
|
|
|
|
|
|
private const int hearderLen = 6;
|
|
|
|
|
|
//消息认证码字段长度
|
|
|
|
|
|
private const int pWLen = 16;
|
|
|
|
|
|
|
|
|
|
|
|
private const int tPLen = 6;
|
|
|
|
|
|
|
|
|
|
|
|
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 HexStringExtensions()
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static object GetAnalyzeValue(this List<string> hexStringList, CommandChunkEnum chunk)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (hexStringList.Count < hearderLen || hexStringList[0] != startStr || hexStringList[5] != startStr || hexStringList.Count < FixedLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (chunk)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CommandChunkEnum.AFN:
|
|
|
|
|
|
var aFn = hexStringList[(int)CommandChunkEnum.AFN].HexToDec();//1字节
|
|
|
|
|
|
return aFn;
|
|
|
|
|
|
case CommandChunkEnum.FN:
|
|
|
|
|
|
//(DT2*8)+DT1=fn
|
|
|
|
|
|
var dt1Bin = hexStringList[(int)CommandChunkEnum.FN - 1].HexToBin();
|
|
|
|
|
|
var dt1 = dt1Bin != "0" ? dt1Bin.Length : 0;
|
|
|
|
|
|
var dt2 = hexStringList[(int)CommandChunkEnum.FN].HexToDec();
|
|
|
|
|
|
var fn = dt2 * 8 + dt1;
|
|
|
|
|
|
return fn;
|
|
|
|
|
|
case CommandChunkEnum.A:
|
|
|
|
|
|
var aHexList = hexStringList.Skip((int)CommandChunkEnum.A).Take(5).ToList();
|
|
|
|
|
|
var a1 = aHexList[1] + aHexList[0];
|
|
|
|
|
|
var a2 = aHexList[3] + aHexList[2];
|
|
|
|
|
|
var a2Dec = a2.HexToDec();
|
|
|
|
|
|
var a3 = aHexList[4];
|
|
|
|
|
|
var a = $"{a1}{a2Dec.ToString().PadLeft(5, '0')}";
|
|
|
|
|
|
var a3Bin = aHexList[4].HexToBin().PadLeft(8, '0');
|
|
|
|
|
|
var msa = a3Bin.Substring(0, 7).BinToDec();
|
|
|
|
|
|
return new Tuple<string,int>(a, msa);
|
|
|
|
|
|
case CommandChunkEnum.SEQ:
|
|
|
|
|
|
var seq = hexStringList[(int)CommandChunkEnum.SEQ].HexToBin().PadLeft(8, '0');
|
|
|
|
|
|
var tpV = (TpV)Convert.ToInt32(seq.Substring(0, 1));
|
|
|
|
|
|
var firfin = (FIRFIN)Convert.ToInt32(seq.Substring(1, 2));
|
|
|
|
|
|
var con = (CON)Convert.ToInt32(seq.Substring(3, 1));
|
|
|
|
|
|
var prseqBin = seq.Substring(4, 4);
|
|
|
|
|
|
return new Seq
|
|
|
|
|
|
{
|
|
|
|
|
|
CON = con,
|
|
|
|
|
|
FIRFIN = firfin,
|
|
|
|
|
|
PRSEQ = prseqBin.BinToDec(),
|
|
|
|
|
|
TpV = tpV
|
|
|
|
|
|
};
|
|
|
|
|
|
case CommandChunkEnum.Data:
|
|
|
|
|
|
var lenIndex = (int)CommandChunkEnum.Len;
|
|
|
|
|
|
var lenBin = (hexStringList[lenIndex + 1]+hexStringList[lenIndex]).HexToBin();
|
|
|
|
|
|
var len = lenBin.Remove(lenBin.Length - 2).BinToDec();
|
|
|
|
|
|
|
|
|
|
|
|
//验证长度 2=(帧校验和+结束字符)
|
|
|
|
|
|
if (hexStringList.Count - 2 != hearderLen + len)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
var dataHexList = hexStringList.Skip(FixedLength).Take(len + hearderLen - FixedLength).ToList();
|
|
|
|
|
|
return dataHexList;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool IsStartStr(this string str)
|
|
|
|
|
|
{
|
|
|
|
|
|
return str == startStr ? true : false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 字节加33
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="hexStringList"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> AddHex33(this List<string> hexStringList)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < hexStringList.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
hexStringList[i] = (Convert.ToInt32(hexStringList[i], 16) + Convert.ToInt32("33", 16)).ToString("X2");
|
|
|
|
|
|
if (hexStringList[i].Length > 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
hexStringList[i] = hexStringList[i].Substring(hexStringList[i].Length - 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return hexStringList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region 376.1下行命令
|
|
|
|
|
|
|
|
|
|
|
|
/// <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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static byte[] BuildAmmeterParameterReadingSendCmd(string address, List<int> meterNumberList)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
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);
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return bytes;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表抄读一类数据-下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="address"></param>
|
|
|
|
|
|
/// <param name="pn"></param>
|
|
|
|
|
|
/// <param name="aTypeOfDataItems">一类数据项</param>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static byte[] BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
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 = HexStringExtensions.BuildSendCommandBytes(reqParameter);
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return bytes;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <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 = HexStringExtensions.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 = HexStringExtensions.BuildSendCommandBytes(reqParameter);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表读取二类数据-下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="address"></param>
|
|
|
|
|
|
/// <param name="pn"></param>
|
|
|
|
|
|
/// <param name="iIDataTypeItems">fn</param>
|
|
|
|
|
|
/// <param name="density">冻结密度</param>
|
|
|
|
|
|
/// <param name="points">冻结点数</param>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="beginTime">起始时间</param>
|
|
|
|
|
|
public static byte[] BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density,int points,DateTime? beginTime = null)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var queryDate = beginTime ?? DateTime.Today.AddDays(-1);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
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 = HexStringExtensions.BuildSendCommandBytes(reqParameter, dataUnit);
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return bytes;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表读取二类数据-下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="address"></param>
|
|
|
|
|
|
/// <param name="pn"></param>
|
|
|
|
|
|
/// <param name="iIDataTypeItems">fn</param>
|
|
|
|
|
|
/// <param name="tdType">数据时标</param>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="beginTime">起始时间</param>
|
|
|
|
|
|
public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems,TdType tdType, DateTime? beginTime = null)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var queryDate = beginTime ?? DateTime.Today.AddDays(-1);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
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 = HexStringExtensions.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 = HexStringExtensions.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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password,string modelCode, int port, string baudRate, decimal power)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
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 = 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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, string baudRate, decimal power)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
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 = 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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, string baudRate, decimal power)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
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 = 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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static void WsOnSupperPower(string address,string password,string modelCode,bool isOn,int port,string baudRate)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
List<string> modelCodes = new List<string>() { "DDS3102-S2", "DDS71", "DDZY71", "DTZY71", "DSZY71" };
|
|
|
|
|
|
//这些型号需进入软编程
|
|
|
|
|
|
if (modelCodes.Contains(modelCode))
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataUnit1 = SoftProgram(address, modelCode, password);
|
|
|
|
|
|
BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit2 = 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
|
|
|
|
|
|
/// <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 = HexStringExtensions.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 = HexStringExtensions.BuildSendCommandBytes(reqParameter);
|
|
|
|
|
|
return bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 集中器校时 秒、分、时、日、星期-月(3-1+4)、年
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="address"></param>
|
|
|
|
|
|
/// <param name="time"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static byte[] BuildConrCheckTimeSendCmd(string address, DateTime time)
|
|
|
|
|
|
{
|
|
|
|
|
|
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);
|
|
|
|
|
|
var dataUnit = strTimeFm.Replace(" ", "").StringToPairs();
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建透明转发-下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="address">集中器地址</param>
|
|
|
|
|
|
/// <param name="port">终端通信端口 1~31</param>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="baudRate">300,600,1200,2400,4800,7200,9600,19200对应 0~7</param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
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,
|
2024-12-19 16:07:07 +08:00
|
|
|
|
int waitContentTimeout = 100, int waitByteTimeout = 100)
|
|
|
|
|
|
{
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var baudRateValue = GetBaudreate(baudRate);
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRateValue, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
[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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
private static List<string> BuildTransparentForwardingSendDataUnit(int port, int baudRate, List<string> datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8,
|
2024-12-19 16:07:07 +08:00
|
|
|
|
int waitContentTimeout = 100, int waitByteTimeout = 100)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataUnit = new List<string>();
|
|
|
|
|
|
|
|
|
|
|
|
var portHex = port.DecToHex().PadLeft(2, '0');
|
|
|
|
|
|
dataUnit.Add(portHex);
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var baudRateBin = baudRate.DecToBin().PadLeft(3, '0');
|
2024-12-19 16:07:07 +08:00
|
|
|
|
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];
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
//var indexHex = (i + 1).DecToHex().PadLeft(4, '0');
|
|
|
|
|
|
var indexHex = meter.SerialNumber.DecToHex().PadLeft(4, '0');
|
2024-12-19 16:07:07 +08:00
|
|
|
|
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'));
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
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');
|
2024-12-19 16:07:07 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
//AUX=消息认证码字段(PW,16个字节)
|
|
|
|
|
|
private static List<string> GetPW()
|
|
|
|
|
|
{
|
|
|
|
|
|
var str = "00";
|
|
|
|
|
|
var pWList = Enumerable.Repeat(str, pWLen).ToList();
|
|
|
|
|
|
return pWList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 帧校验和
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="userData">用户数据区</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static string GetCS(List<string> userData)
|
|
|
|
|
|
{
|
|
|
|
|
|
byte sum = 0;
|
|
|
|
|
|
foreach (var d in userData)
|
|
|
|
|
|
{
|
|
|
|
|
|
var b = Convert.ToByte(d, 16);
|
|
|
|
|
|
sum += b;
|
|
|
|
|
|
}
|
|
|
|
|
|
return sum.ToString("X2");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 用户数据区
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="reqParameter"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildUserData(ReqParameter reqParameter, List<string>? dataUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
var c = BuildC(reqParameter.FunCode, reqParameter.PRM);
|
|
|
|
|
|
var a = BuildAList(reqParameter.A, reqParameter.MSA);
|
|
|
|
|
|
|
|
|
|
|
|
var linkUserData = BuildLinkUserData(reqParameter.AFN, reqParameter.Seq,
|
|
|
|
|
|
((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit);
|
|
|
|
|
|
|
|
|
|
|
|
var list = new List<string>() { c };
|
|
|
|
|
|
list.AddRange(a);
|
|
|
|
|
|
list.AddRange(linkUserData);
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 固定长度的报文头 起始字符+长度+长度+起始字符
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="length"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildHeaders(int length)
|
|
|
|
|
|
{
|
|
|
|
|
|
var headers = new List<string>();
|
|
|
|
|
|
headers.Add(startStr);
|
|
|
|
|
|
var l = BuildLength(length);
|
|
|
|
|
|
headers.AddRange(l);
|
|
|
|
|
|
headers.AddRange(l);
|
|
|
|
|
|
headers.Add(startStr);
|
|
|
|
|
|
return headers;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 长度 2字节 [用户数据区长度]
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildLength(int length1)
|
|
|
|
|
|
{
|
|
|
|
|
|
var binaryLen = length1.DecToBin();
|
|
|
|
|
|
var protocolIdentification = Enum.Format(typeof(ProtocolIdentification),
|
|
|
|
|
|
ProtocolIdentification.本规约使用, "d").PadLeft(2, '0');
|
|
|
|
|
|
var lenStr = $"{binaryLen}{protocolIdentification}";
|
|
|
|
|
|
var hexLen = lenStr.BinToHex();
|
|
|
|
|
|
hexLen = hexLen.PadLeft(4, '0');
|
|
|
|
|
|
var list = hexLen.StringToPairs();
|
|
|
|
|
|
list.Reverse();
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 控制域
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="funCode">功能码</param>
|
|
|
|
|
|
/// <param name="fcb"></param>
|
|
|
|
|
|
/// <param name="fcv"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static string BuildC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cMasterStationFunCodeHex = funCode.DecToBin();
|
|
|
|
|
|
cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0');
|
|
|
|
|
|
var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}";
|
|
|
|
|
|
var hexC = strC.BinToHex().PadLeft(2, '0');
|
|
|
|
|
|
return hexC;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 地址域 3220 09872
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="a1">行政区划码 BCD码 3220=2032</param>
|
|
|
|
|
|
/// <param name="a2">逻辑地址 BIN 09872=2690=>9026</param>
|
|
|
|
|
|
/// <param name="a3">主站地址 BIN 0~127</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildAList(string a, int mSA)
|
|
|
|
|
|
{
|
|
|
|
|
|
var list = new List<string>();
|
|
|
|
|
|
|
|
|
|
|
|
var a1 = a.Substring(0, 4);
|
|
|
|
|
|
var a1Pairs = a1.StringToPairs();
|
|
|
|
|
|
a1Pairs.Reverse();
|
|
|
|
|
|
list.AddRange(a1Pairs);
|
|
|
|
|
|
|
|
|
|
|
|
var a2 = Convert.ToInt32(a.Substring(4));
|
|
|
|
|
|
var decA2 = a2.DecToHex();
|
|
|
|
|
|
var a2Pairs = decA2.PadLeft(4, '0').StringToPairs();
|
|
|
|
|
|
a2Pairs.Reverse();
|
|
|
|
|
|
list.AddRange(a2Pairs);
|
|
|
|
|
|
|
|
|
|
|
|
//TODO:主站地址和组地址标志
|
|
|
|
|
|
var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0";
|
|
|
|
|
|
list.Add(a3Bin.BinToHex().PadLeft(2, '0'));
|
|
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static List<string> BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List<string>? dataUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0');
|
|
|
|
|
|
var sEQ = BuildSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ);
|
|
|
|
|
|
var dA = BuildDA(pn);
|
|
|
|
|
|
var dT = BuildDT(fn);
|
|
|
|
|
|
var list = new List<string>() { aFNValue, sEQ };
|
|
|
|
|
|
list.AddRange(dA);
|
|
|
|
|
|
list.AddRange(dT);
|
|
|
|
|
|
|
|
|
|
|
|
if (dataUnit != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
list.AddRange(dataUnit);
|
|
|
|
|
|
}
|
|
|
|
|
|
//list.AddRange(GetDataUnit(aFN,seq));
|
|
|
|
|
|
|
|
|
|
|
|
if (seq.TpV == TpV.附加信息域中带时间标签)
|
|
|
|
|
|
list.AddRange(BuildTp("00"));
|
|
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 帧序列域
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tpV"></param>
|
|
|
|
|
|
/// <param name="fIRFIN"></param>
|
|
|
|
|
|
/// <param name="cON"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static string BuildSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tpVValue = Enum.Format(typeof(TpV),
|
|
|
|
|
|
tpV, "d");
|
|
|
|
|
|
var fIRFINValue = Enum.Format(typeof(FIRFIN),
|
|
|
|
|
|
fIRFIN, "d");
|
|
|
|
|
|
var cONValue = (int)cON;
|
|
|
|
|
|
var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{pRSEQ.DecToBin().PadLeft(4, '0')}";
|
|
|
|
|
|
var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0');
|
|
|
|
|
|
return hexSEQ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 信息点标识
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="pn">计量点</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildDA(int pn)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pn == 0)
|
|
|
|
|
|
return new List<string>() { "00", "00" };
|
|
|
|
|
|
var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组
|
|
|
|
|
|
var dA1 = pn - (dA2 - 1) * 8;//pn % 8
|
|
|
|
|
|
var dA1Hex = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位
|
|
|
|
|
|
var dA2Hex = dA2.DecToHex();
|
|
|
|
|
|
return new List<string>() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') };
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 数据单元标识
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fn"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildDT(int fn)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dT2 = (fn - 1) / 8;//从零开始 第几组
|
|
|
|
|
|
var dT1 = fn - dT2 * 8;
|
|
|
|
|
|
var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位
|
|
|
|
|
|
var dT2Hex = dT2.DecToHex();
|
|
|
|
|
|
return new List<string>() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 时间标签
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="pFC">启动帧帧序号计数器PFC 1字节</param>
|
|
|
|
|
|
/// <param name="delayTime">允许发送传输延时时间 min 1字节</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static List<string> BuildTp(string pFC = "00", int delayTime = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var now = DateTime.Now; // 获取当前时间
|
|
|
|
|
|
var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数
|
|
|
|
|
|
var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数
|
|
|
|
|
|
var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数
|
|
|
|
|
|
var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数
|
|
|
|
|
|
return new List<string>() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 645下行命令
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表阀控下发数据单元
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="specialControlCode">特殊控制码</param>
|
|
|
|
|
|
/// <param name="password">密码</param>
|
|
|
|
|
|
/// <param name="state">是否为开阀</param>
|
|
|
|
|
|
/// <param name="modelCode">型号码</param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string> BuildAmmeterValveControlSendDataUnit(string ammeterAddress, string specialControlCode, string password, bool state, string modelCode = "")
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var code = string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
if (state)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(specialControlCode))
|
|
|
|
|
|
code = "1B";
|
|
|
|
|
|
else
|
|
|
|
|
|
code = specialControlCode == "1B" || specialControlCode == "1C" ? specialControlCode : "1C";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
code = "1A";//跳闸
|
|
|
|
|
|
|
|
|
|
|
|
if (specialControlCode == "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];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();//命令有效截止时间
|
|
|
|
|
|
if (specialControlCode == "1D" || modelCode == "SZBD_DDZY1225")
|
|
|
|
|
|
strDate = "FF FF FF FF FF FF";
|
|
|
|
|
|
var strP = password.StrAddSpan().StrReverseOrder();
|
|
|
|
|
|
var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate;
|
|
|
|
|
|
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
return dataList;
|
|
|
|
|
|
|
|
|
|
|
|
//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>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <param name="state">true 保电 false 保电解除</param>
|
|
|
|
|
|
/// <param name="modelCode">型号码</param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string> BuildAmmeterLockSendDataUnit(string ammeterAddress, string password, bool state, string modelCode = "")
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var code = state ? "3A" : "3B";
|
|
|
|
|
|
|
|
|
|
|
|
var strDate = (code + DateTime.Now.AddDays(1).ToString("00000012ddMMyy")).StrAddSpan();
|
|
|
|
|
|
|
|
|
|
|
|
if (modelCode == "SZBD_DDZY1225")
|
|
|
|
|
|
strDate = $"{code} 00 FF FF FF FF FF FF";
|
|
|
|
|
|
|
|
|
|
|
|
var strP = password.StrAddSpan().StrReverseOrder();
|
|
|
|
|
|
var strSJY = " 02 " + strP + " 01 00 00 00 " + strDate;
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表认证下发数据单元
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="ramDon"></param>
|
|
|
|
|
|
/// <param name="maco"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string> BuildAmmeterIdentitySendDataUnit(string ammeterAddress, string ramDon, string maco)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var codeList = "070004FF".StringToPairs();
|
|
|
|
|
|
codeList.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
var ramDonList = ramDon.StringToPairs();
|
|
|
|
|
|
ramDonList.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
var macoList = maco.StringToPairs();
|
|
|
|
|
|
macoList.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit = new List<string>();
|
|
|
|
|
|
dataUnit.AddRange(codeList);
|
|
|
|
|
|
dataUnit.AddRange(ramDonList);
|
|
|
|
|
|
dataUnit.AddRange(macoList);
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var dataList = Build645SendCommand(ammeterAddress, "03", dataUnit);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表清零下发数据单元
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string> BuildAmmeterClearSendDataUnit(string ammeterAddress, string password)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var strP = password.StrAddSpan().StrReverseOrder();
|
|
|
|
|
|
var strSJY = " 02 " + strP + " 01 00 00 00 ";
|
|
|
|
|
|
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var dataList = Build645SendCommand(ammeterAddress, "1A", dataUnit);
|
|
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表读取下发数据单元
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
|
|
|
|
|
/// <param name="cmdType">功率读取 余额读取</param>
|
|
|
|
|
|
/// <param name="dataId">数据标识</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> BuildAmmeterReadDataUnit(string ammeterAddress, CmdType cmdType, string dataId = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
var dn = "";
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(dataId))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cmdType == CmdType.PowerRead) dn = "04090B01";
|
|
|
|
|
|
else if (cmdType == CmdType.BalanceRead) dn = "00900200";
|
|
|
|
|
|
else if (cmdType == CmdType.CurrentRead) dn = "04090801";
|
|
|
|
|
|
else if (cmdType == CmdType.WsPowerDown) dn = "0E300103";
|
|
|
|
|
|
else if (cmdType == CmdType.ReadMeterStatus) dn = "04000503";
|
|
|
|
|
|
else if (cmdType == CmdType.TimeSet) dn = "04010001";//主用第一套时段数据
|
|
|
|
|
|
else if (cmdType == CmdType.ReadTimeSetMonth) dn = "04010000";//主用时区数据
|
|
|
|
|
|
else if (cmdType == CmdType.ReadTimeSetNum) dn = "04000202";//日时段数
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
dn = dataId;
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit = dn.StringToPairs(true);
|
|
|
|
|
|
|
|
|
|
|
|
var dataList = Build645SendCommand(ammeterAddress, "11", dataUnit);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <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 now = DateTime.Now;
|
|
|
|
|
|
var year = (now.Year - 2000).ToString("X2").PadLeft(4, '0');
|
|
|
|
|
|
var month = now.Month.ToString("X2").PadLeft(4, '0');
|
|
|
|
|
|
var day = now.Day.ToString("X2").PadLeft(4, '0');
|
|
|
|
|
|
var hour = now.Hour.ToString("X2").PadLeft(4, '0');
|
|
|
|
|
|
var minute = now.Minute.ToString("X2").PadLeft(4, '0');
|
|
|
|
|
|
var second = now.Second.ToString("X2").PadLeft(4, '0');
|
|
|
|
|
|
var adress = int.Parse(ammeterAddress.Substring(ammeterAddress.Length - 3)).DecToHex().PadLeft(2,'0');
|
|
|
|
|
|
var fm = new List<string>() { adress, "10", "23", "35", "00", "06", "0C" };
|
|
|
|
|
|
fm.AddRange($"{second}{minute}{hour}{day}{month}{year}".StringToPairs());
|
|
|
|
|
|
|
|
|
|
|
|
var bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray();
|
|
|
|
|
|
var getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0'));//long.Parse ?
|
|
|
|
|
|
fm.AddRange(getCrc);
|
|
|
|
|
|
|
|
|
|
|
|
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None);
|
|
|
|
|
|
bytesList.Add(bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (modelCode == "DTSU193")
|
|
|
|
|
|
{
|
|
|
|
|
|
var now = DateTime.Now;
|
|
|
|
|
|
var year = now.Year.ToString().Substring(2);
|
|
|
|
|
|
var month = now.Month.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var day = now.Day.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var week = ((int)now.DayOfWeek).ToString().PadLeft(2, '0');
|
|
|
|
|
|
var hour = now.Hour.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var minute = now.Minute.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var second = now.Second.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var fm = GenerateCTCommand(ammeterAddress,$"{year}{month}{day}{week}{hour}{minute}{second}");
|
|
|
|
|
|
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm);
|
|
|
|
|
|
bytesList.Add(bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var now = DateTime.Now;
|
|
|
|
|
|
var year = now.Year.ToString().PadLeft(4, '0');
|
|
|
|
|
|
var month = now.Month.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var day = now.Day.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var week = ((int)now.DayOfWeek).ToString().PadLeft(2, '0');
|
|
|
|
|
|
var hour = now.Hour.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var minute = now.Minute.ToString().PadLeft(2, '0');
|
|
|
|
|
|
var second = now.Second.ToString().PadLeft(2, '0');
|
|
|
|
|
|
|
|
|
|
|
|
//组装数据域
|
|
|
|
|
|
List<string> dataList = new List<string>();
|
|
|
|
|
|
var dataMarkList = "04000101".StringToPairs(true);
|
|
|
|
|
|
dataList.AddRange(dataMarkList);
|
|
|
|
|
|
dataList.Add("02");
|
|
|
|
|
|
if (string.IsNullOrEmpty(password))
|
|
|
|
|
|
password = "000000";
|
|
|
|
|
|
var passwordList = password.StringToPairs(true);
|
|
|
|
|
|
dataList.AddRange(passwordList);
|
|
|
|
|
|
dataList.AddRange("00000000".StringToPairs(true));
|
|
|
|
|
|
dataList.AddRange($"{year}{month}{day}{week}".StringToPairs(true));
|
|
|
|
|
|
|
|
|
|
|
|
var fm = Build645SendCommand(ammeterAddress, "14", dataList);
|
|
|
|
|
|
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm);
|
|
|
|
|
|
bytesList.Add(bytes);
|
|
|
|
|
|
|
|
|
|
|
|
dataList = new List<string>();
|
|
|
|
|
|
dataMarkList = "04000102".StringToPairs(true);
|
|
|
|
|
|
dataList.AddRange(dataMarkList);
|
|
|
|
|
|
dataList.Add("02");
|
|
|
|
|
|
dataList.AddRange(passwordList);
|
|
|
|
|
|
dataList.AddRange("00000000".StringToPairs(true));
|
|
|
|
|
|
dataList.AddRange($"{hour}{minute}{second}".StringToPairs(true));
|
|
|
|
|
|
fm = Build645SendCommand(ammeterAddress, "14", dataList);
|
|
|
|
|
|
bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm);
|
|
|
|
|
|
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")
|
|
|
|
|
|
{
|
|
|
|
|
|
//LogHelper.LogStr("ReadMeterTimeSet", $"表编号[{meterInfo.meter_address}]进入PMAC9523时段设置");
|
|
|
|
|
|
var adress = int.Parse(ammeterAddress.Substring(ammeterAddress.Length - 3)).DecToHex().PadLeft(2, '0');
|
|
|
|
|
|
var fm = new List<string>() { adress, "03", "55", "F9", "00", "28" };
|
|
|
|
|
|
var bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray();
|
|
|
|
|
|
var getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0'));
|
|
|
|
|
|
fm.AddRange(getCrc);
|
|
|
|
|
|
|
|
|
|
|
|
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None);
|
|
|
|
|
|
return new List<byte[]>(){ bytes };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var bytes1 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010001"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes2 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010002"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes3 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010003"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes4 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010004"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes9 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010005"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes5 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020001"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes6 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020002"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes7 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020003"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes8 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020004"));
|
|
|
|
|
|
|
|
|
|
|
|
var bytes10 = BuildTransparentForwardingSendCmd(address, port, baudRate,
|
|
|
|
|
|
BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020005"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new List<byte[]>{ bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10 };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建电表表号读取下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
|
|
|
|
|
/// <param name=""></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> BuildAmmeterReadNumSendCmd(string ammeterAddress)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataUnit = "04000402".StringToPairs(true);
|
|
|
|
|
|
return Build645SendCommand(ammeterAddress, "11", dataUnit);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <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 adress = int.Parse(ammeterAddress.Substring(ammeterAddress.Length - 3)).DecToHex().PadLeft(2,'0');
|
|
|
|
|
|
//第一步启用复费率编程:寄存器64503,写数据01启动编程
|
|
|
|
|
|
var fm = new List<string>() { adress, "10", "FB", "F6", "00", "01", "02", "00", "01" };
|
|
|
|
|
|
var bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray();
|
|
|
|
|
|
var getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0'));
|
|
|
|
|
|
fm.AddRange(getCrc);
|
|
|
|
|
|
|
|
|
|
|
|
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None);
|
|
|
|
|
|
bytesList.Add(bytes);
|
|
|
|
|
|
|
|
|
|
|
|
//第二步写复费率模式:寄存器22002,写数据01固定一套费率
|
|
|
|
|
|
fm = new List<string>() { adress, "10", "55", "F1", "00", "01", "02", "00", "01" };
|
|
|
|
|
|
bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray();
|
|
|
|
|
|
getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0'));
|
|
|
|
|
|
fm.AddRange(getCrc);
|
|
|
|
|
|
bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None);
|
|
|
|
|
|
bytesList.Add(bytes);
|
|
|
|
|
|
|
|
|
|
|
|
//第三步写时段参数:寄存器22010开始,后续多少个寄存器根据时段内容来。
|
|
|
|
|
|
var timeSetDetailList = data.FirstOrDefault().Data;
|
|
|
|
|
|
fm = new List<string>() { adress, "10", "55", "F9", "00" };
|
|
|
|
|
|
//寄存器个数
|
|
|
|
|
|
var timeNum = timeSetDetailList.Sum(o => o.Times.Count);
|
|
|
|
|
|
fm.Add($"{timeNum * 2 + 1:X2}");
|
|
|
|
|
|
//数据长度
|
|
|
|
|
|
fm.Add($"{(timeNum * 2 + 1) * 2:X2}");
|
|
|
|
|
|
|
|
|
|
|
|
//时段个数
|
|
|
|
|
|
fm.Add("00");
|
|
|
|
|
|
fm.Add($"{timeNum:X2}");
|
|
|
|
|
|
Dictionary<string, string> setDic = new Dictionary<string, string>();
|
|
|
|
|
|
int rate = 0;
|
|
|
|
|
|
foreach (var item in timeSetDetailList)
|
|
|
|
|
|
{
|
|
|
|
|
|
int.TryParse(item.Rate, out rate);
|
|
|
|
|
|
foreach (var itemItem in item.Times)
|
|
|
|
|
|
{
|
|
|
|
|
|
fm.Add("00");
|
|
|
|
|
|
fm.Add($"{rate - 1:X2}");
|
|
|
|
|
|
fm.Add("00");
|
|
|
|
|
|
fm.Add($"{itemItem.StartTime.TakeTimeToInt():X2}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray();
|
|
|
|
|
|
getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0'));
|
|
|
|
|
|
fm.AddRange(getCrc);
|
|
|
|
|
|
bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建645协议下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ammeterAddress">电表地址</param>
|
|
|
|
|
|
/// <param name="controlCode">控制码</param>
|
|
|
|
|
|
/// <param name="dataUnit">数据域 发送方按字节进行加33处理,接收方按字节减33</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> Build645SendCommand(string ammeterAddress, string controlCode, List<string>? dataUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cmdStrList = new List<string>();
|
|
|
|
|
|
cmdStrList.Add(startStr);
|
|
|
|
|
|
|
|
|
|
|
|
ammeterAddress = ammeterAddress.PadLeft(12, '0');
|
|
|
|
|
|
var addressList = ammeterAddress.StringToPairs();
|
|
|
|
|
|
addressList.Reverse();
|
|
|
|
|
|
cmdStrList.AddRange(addressList);
|
|
|
|
|
|
|
|
|
|
|
|
cmdStrList.Add(startStr);
|
|
|
|
|
|
|
|
|
|
|
|
cmdStrList.Add(controlCode);
|
|
|
|
|
|
|
|
|
|
|
|
var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00";
|
|
|
|
|
|
cmdStrList.Add(len);
|
|
|
|
|
|
|
|
|
|
|
|
if (dataUnit != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
cmdStrList.AddRange(dataUnit.AddHex33());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
|
|
|
|
|
|
strSum = strSum.Substring(strSum.Length - 2);
|
|
|
|
|
|
cmdStrList.Add(strSum);
|
|
|
|
|
|
cmdStrList.Add(endStr);
|
|
|
|
|
|
|
|
|
|
|
|
return cmdStrList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 威胜表的超功率(第一路恶性负载超功率判断阀值)
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress"></param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <param name="dataMark"></param>
|
|
|
|
|
|
/// <param name="power"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string>? AssembleWsSupperPower(string ammeterAddress, string password, string dataMark, decimal power)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
power = Math.Round(power, 4);
|
|
|
|
|
|
if (power > (decimal)99.9999) return null;
|
|
|
|
|
|
var strPower = power < 10 ? $"0{power}" : power.ToString();
|
|
|
|
|
|
var pStr = strPower.Replace(".", "").PadRight(6, '0');
|
|
|
|
|
|
var data = new string[] { pStr[4] + "" + pStr[5], pStr[2] + "" + pStr[3], pStr[0] + "" + pStr[1] };
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return AssembleWrite(ammeterAddress, password, dataMark, data);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 威胜表的超功率(超功率开关)
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress"></param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <param name="isOn"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string> AssembleWsOnSupperPower(string ammeterAddress, string password, bool isOn = true)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var data = new string[] { (isOn ? "01" : "00") };
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return AssembleWrite(ammeterAddress, password, "0E400001", data);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 威胜表的超功率(第一路恶性负载绝对功率判断阈值)
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress"></param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <param name="dataMark"></param>
|
|
|
|
|
|
/// <param name="power"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string>? AssembleWsAbsolutePowerSetting(string ammeterAddress, string password, string dataMark, decimal power)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
power = Math.Round(power, 4);
|
|
|
|
|
|
if (power > (decimal)99.9999) return null;
|
|
|
|
|
|
var strPower = power < 10 ? $"0{power}" : power.ToString();
|
|
|
|
|
|
var pStr = strPower.Replace(".", "").PadRight(6, '0');
|
|
|
|
|
|
var data = new string[] { pStr[4] + "" + pStr[5], pStr[2] + "" + pStr[3], pStr[0] + "" + pStr[1] };
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return AssembleWrite(ammeterAddress, password, dataMark, data);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 威胜表的超功率(第一路恶性负载功率因数判断阀值)
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress"></param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <param name="dataMark"></param>
|
|
|
|
|
|
/// <param name="factor"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string>? AssembleWsPowerFactor(string ammeterAddress, string password, string dataMark, decimal factor)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
factor = Math.Round(factor, 3);
|
|
|
|
|
|
if (factor >= (decimal)1.0 || factor <= 0) return null;
|
|
|
|
|
|
var strFactor = factor.ToString();
|
|
|
|
|
|
var pStr = strFactor.Replace(".", "").PadRight(4, '0');
|
|
|
|
|
|
var data = new string[] { pStr[2] + "" + pStr[3], pStr[0] + "" + pStr[1] };
|
2024-12-27 17:00:31 +08:00
|
|
|
|
return AssembleWrite(ammeterAddress, password, dataMark, data);
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建写数据
|
|
|
|
|
|
/// </summary>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
/// <param name="ammeterAddress"></param>
|
2024-12-19 16:07:07 +08:00
|
|
|
|
/// <param name="password"></param>
|
|
|
|
|
|
/// <param name="di0_3"></param>
|
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static List<string> AssembleWrite(string ammeterAddress, string password, string di0_3, string[] data)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var returnList = new List<string>();
|
|
|
|
|
|
returnList.Add(startStr);
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var addressList = ammeterAddress.StringToPairs();
|
2024-12-19 16:07:07 +08:00
|
|
|
|
addressList.Reverse();
|
|
|
|
|
|
returnList.AddRange(addressList);
|
|
|
|
|
|
|
|
|
|
|
|
returnList.Add(startStr);
|
|
|
|
|
|
returnList.Add("14");
|
|
|
|
|
|
|
|
|
|
|
|
var len = (12 + data.Length).ToString("X2");
|
|
|
|
|
|
returnList.Add(len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var di03List = di0_3.StringToPairs();
|
|
|
|
|
|
di03List.Reverse();
|
|
|
|
|
|
di03List.Add("02");
|
|
|
|
|
|
|
|
|
|
|
|
var pwdList = password.StringToPairs();
|
|
|
|
|
|
pwdList.Reverse();
|
|
|
|
|
|
di03List.AddRange(pwdList);
|
|
|
|
|
|
|
|
|
|
|
|
var mList = new List<string>() { "00", "11", "22", "33" };
|
|
|
|
|
|
di03List.AddRange(mList);
|
|
|
|
|
|
di03List.AddRange(data);
|
|
|
|
|
|
var listAdd33 = di03List.AddHex33();
|
|
|
|
|
|
|
|
|
|
|
|
returnList.AddRange(listAdd33);
|
|
|
|
|
|
|
|
|
|
|
|
var strSum = returnList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
|
|
|
|
|
|
var cs = strSum.Substring(strSum.Length - 2);
|
|
|
|
|
|
returnList.Add(cs);
|
|
|
|
|
|
returnList.Add(endStr);
|
|
|
|
|
|
|
|
|
|
|
|
return returnList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成软编程指令
|
|
|
|
|
|
/// <param name="modelCode">型号编码</param>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-27 17:00:31 +08:00
|
|
|
|
private static List<string> SoftProgram(string ammeterAddress, string modelCode,string password)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
string bccmd = string.Empty;
|
|
|
|
|
|
if (modelCode == "DDS71")
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
bccmd = "68 AA AA AA AA AA AA 68 04 07 4E F4 35 BB BB BB 32";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
bccmd = "68 AA AA AA AA AA AA 68 14 10 41 35 33 41 37 33 33 33 34 33 33 33 77 66 55 44";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//替换密码
|
|
|
|
|
|
var passwordList = password.StringToPairs();
|
|
|
|
|
|
passwordList.Reverse();
|
|
|
|
|
|
passwordList = passwordList.AddHex33();
|
|
|
|
|
|
var passwordStr = string.Join(" ", passwordList);
|
|
|
|
|
|
bccmd = bccmd.Replace("BB BB BB", passwordStr);
|
|
|
|
|
|
//替换表地址
|
2024-12-27 17:00:31 +08:00
|
|
|
|
var addressList = ammeterAddress.StringToPairs();
|
2024-12-19 16:07:07 +08:00
|
|
|
|
addressList.Reverse();
|
|
|
|
|
|
var addressStr = string.Join(" ", addressList);
|
|
|
|
|
|
bccmd = bccmd.Replace("AA AA AA AA AA AA", addressStr);
|
|
|
|
|
|
var fm = bccmd.Split(' ').ToList();
|
|
|
|
|
|
//生成CRC
|
|
|
|
|
|
var cRC = GetCRC(fm);
|
|
|
|
|
|
fm.Add(cRC);
|
|
|
|
|
|
fm.Add("16");
|
|
|
|
|
|
|
|
|
|
|
|
return fm;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
|
|
|
|
|
|
private static List<string> GenerateCTCommand(string ammeterAddress, string data)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<string> fm = new List<string>();
|
|
|
|
|
|
fm.Add(startStr);
|
|
|
|
|
|
List<string> addressList = ammeterAddress.StringToPairs();
|
|
|
|
|
|
addressList.Reverse();
|
|
|
|
|
|
fm.AddRange(addressList);
|
|
|
|
|
|
fm.Add(startStr);
|
|
|
|
|
|
fm.Add("14");
|
|
|
|
|
|
fm.Add("13");
|
|
|
|
|
|
fm.Add("3F");
|
|
|
|
|
|
fm.Add("34");
|
|
|
|
|
|
fm.Add("33");
|
|
|
|
|
|
fm.Add("37");
|
|
|
|
|
|
fm.Add("35");
|
|
|
|
|
|
fm.Add("33");
|
|
|
|
|
|
fm.Add("33");
|
|
|
|
|
|
fm.Add("33");
|
|
|
|
|
|
fm.Add("44");
|
|
|
|
|
|
fm.Add("44");
|
|
|
|
|
|
fm.Add("44");
|
|
|
|
|
|
fm.Add("44");
|
|
|
|
|
|
//组装数据域
|
|
|
|
|
|
var dataList = data.StringToPairs();
|
|
|
|
|
|
dataList.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
fm.AddRange(dataList.AddHex33());
|
|
|
|
|
|
|
|
|
|
|
|
var cRC = GetCRC(fm);
|
|
|
|
|
|
fm.Add(cRC);
|
|
|
|
|
|
fm.Add(endStr);
|
|
|
|
|
|
return fm;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 188 下行命令
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 标准 188协议阀控
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="waterMeterAddress"></param>
|
|
|
|
|
|
/// <param name="mtype">表计类型</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> BuildConfirm188WaterValve(string waterMeterAddress, bool state, string mtype = "10")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(waterMeterAddress)) return null;
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit = new List<string>() { "A0", "17", "00", state ? "55" : "99" };
|
|
|
|
|
|
|
|
|
|
|
|
var dataList = Build188SendCommand(waterMeterAddress, "04", dataUnit);
|
|
|
|
|
|
|
|
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建188水表抄读下发数据单元
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="waterMeterAddress"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> Build188WaterMeterReadingSendDataUnit(string waterMeterAddress)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var dataUnit = new List<string>() { "1F", "90", "00" };
|
|
|
|
|
|
var dataList = Build188SendCommand(waterMeterAddress, "01", dataUnit);
|
|
|
|
|
|
|
|
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建188协议下发命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="waterMeterAddress">水表地址</param>
|
|
|
|
|
|
/// <param name="controlCode">控制码</param>
|
|
|
|
|
|
/// <param name="dataUnit">数据域</param>
|
|
|
|
|
|
/// <param name="meterType">表类型</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string> Build188SendCommand(string waterMeterAddress, string controlCode, List<string>? dataUnit = null, string meterType = "10")
|
|
|
|
|
|
{
|
|
|
|
|
|
//address.Substring(address.Length - 12, 12)
|
|
|
|
|
|
var cmdStrList = new List<string>();
|
|
|
|
|
|
cmdStrList.Add(startStr);
|
|
|
|
|
|
cmdStrList.Add(meterType);
|
|
|
|
|
|
|
|
|
|
|
|
waterMeterAddress = waterMeterAddress.PadLeft(14, '0');
|
|
|
|
|
|
var addressList = waterMeterAddress.StringToPairs();
|
|
|
|
|
|
addressList.Reverse();
|
|
|
|
|
|
cmdStrList.AddRange(addressList);
|
|
|
|
|
|
|
|
|
|
|
|
//控制码
|
|
|
|
|
|
cmdStrList.Add(controlCode);
|
|
|
|
|
|
|
|
|
|
|
|
var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00";
|
|
|
|
|
|
cmdStrList.Add(len);
|
|
|
|
|
|
if (dataUnit != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
cmdStrList.AddRange(dataUnit);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
|
|
|
|
|
|
strSum = strSum.Substring(strSum.Length - 2);
|
|
|
|
|
|
cmdStrList.Add(strSum);
|
|
|
|
|
|
cmdStrList.Add(endStr);
|
|
|
|
|
|
|
|
|
|
|
|
return cmdStrList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 组装水表阀控
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="waterMeterAddress">水表地址</param>
|
|
|
|
|
|
/// <param name="password">The password.</param>
|
|
|
|
|
|
/// <param name="protocol">The poprotocol.</param>
|
|
|
|
|
|
/// <param name="state">if set to <c>true</c> [isopenvalve].</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<string>? WaterMeterValveControl(string waterMeterAddress, string password, int protocol, bool state)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<string>? turnData = null;
|
|
|
|
|
|
if (protocol == 1)
|
|
|
|
|
|
turnData = GetControlCode97(waterMeterAddress.Substring(waterMeterAddress.Length - 12, 12), password, state ? "3355" : "9966");//开阀/关阀
|
|
|
|
|
|
else if (protocol == 30)
|
|
|
|
|
|
turnData = GetControlCode07(waterMeterAddress.Substring(waterMeterAddress.Length - 12, 12), password, state ? "3355" : "9966");//开阀/关阀
|
|
|
|
|
|
return turnData;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static List<string> GetControlCode97(string waterMeterAddress, string password, string valueCode)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataList = new List<string>();
|
|
|
|
|
|
var passwordList = password.StringToPairs();
|
|
|
|
|
|
passwordList.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
var valueCodeList = valueCode.StringToPairs();
|
|
|
|
|
|
valueCodeList.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
dataList.AddRange(valueCodeList);
|
|
|
|
|
|
dataList.AddRange(passwordList);
|
|
|
|
|
|
dataList.AddRange(valueCodeList);
|
|
|
|
|
|
|
|
|
|
|
|
return GetCode(waterMeterAddress, "04", dataList);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static List<string> GetControlCode07(string waterMeterAddress, string password, string valueCode)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataList = new List<string>();
|
|
|
|
|
|
dataList.Add("02");
|
|
|
|
|
|
|
|
|
|
|
|
var passwordList = password.StringToPairs();
|
|
|
|
|
|
passwordList.Reverse();
|
|
|
|
|
|
dataList.AddRange(passwordList);
|
|
|
|
|
|
dataList.AddRange("01000000".StringToPairs());
|
|
|
|
|
|
|
|
|
|
|
|
dataList.AddRange(valueCode.StringToPairs());
|
|
|
|
|
|
|
|
|
|
|
|
dataList.Add("00");
|
|
|
|
|
|
|
|
|
|
|
|
var time = DateTime.Now.AddDays(1).ToString("yyMMddHHmmss");
|
|
|
|
|
|
var timeList = time.StringToPairs();
|
|
|
|
|
|
timeList.Reverse();
|
|
|
|
|
|
dataList.AddRange(timeList);
|
|
|
|
|
|
|
|
|
|
|
|
return GetCode(waterMeterAddress, "1C", dataList);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static List<string> GetCode(string waterMeterAddress, string controlCode, List<string> childDataList)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dataList = new List<string> { startStr };
|
|
|
|
|
|
|
|
|
|
|
|
waterMeterAddress = waterMeterAddress.PadLeft(12, '0');
|
|
|
|
|
|
var addressList = waterMeterAddress.StringToPairs();
|
|
|
|
|
|
addressList.Reverse();
|
|
|
|
|
|
dataList.AddRange(addressList);
|
|
|
|
|
|
|
|
|
|
|
|
dataList.Add(startStr);
|
|
|
|
|
|
dataList.Add(controlCode);
|
|
|
|
|
|
|
|
|
|
|
|
var num = childDataList.Count;
|
|
|
|
|
|
dataList.Add(num.ToString("X2"));
|
|
|
|
|
|
|
|
|
|
|
|
dataList.AddRange(childDataList.AddHex33());
|
|
|
|
|
|
|
|
|
|
|
|
var cs = dataList.Select(it => Convert.ToInt32(it, 16)).Sum().ToString("X2");
|
|
|
|
|
|
cs = cs.Substring(cs.Length - 2, 2);
|
|
|
|
|
|
dataList.Add(cs);
|
|
|
|
|
|
|
|
|
|
|
|
dataList.Add(endStr);
|
|
|
|
|
|
|
|
|
|
|
|
return dataList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetCRC(List<string> inputFrm, int startIndex = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
int sum = 0;
|
|
|
|
|
|
for (int i = startIndex; i < inputFrm.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
sum += (Convert.ToInt32(inputFrm[i], 16));
|
|
|
|
|
|
}
|
|
|
|
|
|
var sum16 = Convert.ToString(sum, 16);
|
|
|
|
|
|
return sum16.Substring(sum16.Length - 2, 2).ToUpper();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-27 17:00:31 +08:00
|
|
|
|
public static byte[] GetCRC16(byte[] data, bool isReverse = false)
|
|
|
|
|
|
{
|
|
|
|
|
|
int len = data.Length;
|
|
|
|
|
|
if (data == null || data.Length == 0) return new byte[] { 0, 0 };
|
|
|
|
|
|
|
|
|
|
|
|
ushort crc = 0xFFFF;
|
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
crc = (ushort)(crc ^ (data[i]));
|
|
|
|
|
|
for (int j = 0; j < 8; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
|
|
|
|
|
|
byte lo = (byte)(crc & 0x00FF); //低位置
|
|
|
|
|
|
if (isReverse) return new byte[] { lo, hi };
|
|
|
|
|
|
return new byte[] { hi, lo };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
public static object GetAnalyzeValue(this List<string> hexStringList, CommandChunkEnum188 chunk)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (hexStringList.Count < 11)
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (chunk)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CommandChunkEnum188.A:
|
|
|
|
|
|
var aHexList = hexStringList[(int)CommandChunkEnum188.A].Take(7).ToList();
|
|
|
|
|
|
aHexList.Reverse();
|
|
|
|
|
|
return string.Join("", aHexList.Skip(1).Take(6).ToList());
|
|
|
|
|
|
case CommandChunkEnum188.C:
|
|
|
|
|
|
var cHex = hexStringList[(int)CommandChunkEnum188.C];
|
|
|
|
|
|
return cHex;
|
|
|
|
|
|
case CommandChunkEnum188.Data:
|
|
|
|
|
|
var lenIndex = (int)CommandChunkEnum188.L;
|
|
|
|
|
|
var len = hexStringList[lenIndex].HexToDec();
|
|
|
|
|
|
|
|
|
|
|
|
//验证长度 2=(帧校验和+结束字符)
|
|
|
|
|
|
if (hexStringList.Count - 2 != 11 + len)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
var dataHexList = hexStringList.Skip(11).Take(len).ToList();
|
|
|
|
|
|
return dataHexList;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//public double AnalyzeCurrentTotalRate(List<string> hexList)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var str = string.Join("", hexList);
|
|
|
|
|
|
// var number = Convert.ToInt32(str) * 0.01;
|
|
|
|
|
|
// return number;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|