1641 lines
64 KiB
C#
Raw Normal View History

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;
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>
public static void BuildAmmeterParameterReadingSendCmd(string address, List<int> meterNumberList)
{
var dataUnit = new List<string>();
var countHex = meterNumberList.Count().DecToHex().PadLeft(4, '0');
var countHexPairs = countHex.StringToPairs();
countHexPairs.Reverse();
dataUnit.AddRange(countHexPairs);
foreach (var number in meterNumberList)
{
var numberHex = number.DecToHex().PadLeft(4, '0');
var numberHexPairs = numberHex.StringToPairs();
numberHexPairs.Reverse();
dataUnit.AddRange(numberHexPairs);
}
var reqParameter = new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = address,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 0,
},
MSA = GetMSA(address),
Pn = 0,
Fn = 10
};
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
}
/// <summary>
/// 构建电表抄读一类数据-下发命令
/// </summary>
/// <param name="address"></param>
/// <param name="pn"></param>
/// <param name="aTypeOfDataItems">一类数据项</param>
public static void BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems)
{
var reqParameter = new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = address,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 2,
},
MSA = GetMSA(address),
Pn = pn,
Fn = (int)aTypeOfDataItems
};
var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter);
}
/// <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>
public static void BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density,int points)
{
var queryDate = DateTime.Today.AddDays(-1);
var dataUnit = queryDate.ToString("yyMMddHHmm").StringToPairs();
dataUnit.Reverse();
//冻结密度
dataUnit.Add(((int)density).DecToHex());
dataUnit.Add(points.DecToHex());
var reqParameter = new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = address,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 2,
},
MSA = GetMSA(address),
Pn = pn,
Fn = (int)iIDataTypeItems
};
var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter, dataUnit);
}
/// <summary>
/// 构建电表读取二类数据-下发命令
/// </summary>
/// <param name="address"></param>
/// <param name="pn"></param>
/// <param name="iIDataTypeItems">fn</param>
/// <param name="tdType">数据时标</param>
public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems,TdType tdType)
{
var queryDate = DateTime.Today.AddDays(-1);
List<string>? dataUnit = null;
switch (tdType)
{
case TdType.Td_d:
dataUnit = queryDate.ToString("yyMMdd").StringToPairs();
break;
case TdType.Td_m:
dataUnit = queryDate.ToString("yyMM").StringToPairs();
break;
}
if(dataUnit == null) return;
dataUnit.Reverse();
var reqParameter = new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = address,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 2,
},
MSA = GetMSA(address),
Pn = pn,
Fn = (int)iIDataTypeItems
};
var bytes = 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>
public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password,string modelCode, int port, BaudRate baudRate, decimal power)
{
if (power > 0)
{
WsOnSupperPower(address, password, modelCode, true, port, baudRate);
//TODO:连续发几条嘛?
string dataMark;
//如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001
if (address.IndexOf('_') > 0)
{
var addressSplit = address.Split('_');
address = addressSplit[0];
var loop = Convert.ToInt32(addressSplit[1]);
if (loop == 1) { dataMark = "0E300101"; }
else if (loop == 2) { dataMark = "0E300201"; }
else
return;
}
else
{
dataMark = "0E300101";
}
var turnData = AssembleWsSupperPower(address, password, dataMark, power);
if (turnData != null)
{
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData);
}
}
else
{
WsOnSupperPower(address, password, modelCode, false, port, baudRate);
}
}
/// <summary>
/// 构建恶性负载绝对功率设置-下发命令
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="port"></param>
/// <param name="baudRate"></param>
/// <param name="power"></param>
public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, BaudRate baudRate, decimal power)
{
if (power <= 0)
{
power = 99;//等于小0 代表关闭
}
string dataMark;
//如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001
if (address.IndexOf('_') > 0)
{
var addressSplit = address.Split('_');
address = addressSplit[0];
var loop = Convert.ToInt32(addressSplit[1]);
if (loop == 1) { dataMark = "0E300103"; }
else if (loop == 2) { dataMark = "0E300203"; }
else
return;
}
else
{
dataMark = "0E300103";
}
var turnData = AssembleWsAbsolutePowerSetting(address, password, dataMark, power);
if (turnData != null)
{
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData);
}
}
/// <summary>
/// 构建恶性负载功率因数设置-下发命令
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="port"></param>
/// <param name="baudRate"></param>
/// <param name="power"></param>
public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, BaudRate baudRate, decimal power)
{
string dataMark;
//如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001
if (address.IndexOf('_') > 0)
{
var addressSplit = address.Split('_');
address = addressSplit[0];
var loop = Convert.ToInt32(addressSplit[1]);
if (loop == 1) { dataMark = "0E300104"; }
else if (loop == 2) { dataMark = "0E300204"; }
else
return;
}
else
{
dataMark = "0E300104";
}
var turnData = AssembleWsPowerFactor(address, password, dataMark, power);
if (turnData != null)
{
var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData);
}
}
/// <summary>
/// 超功率开关
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="modelCode"></param>
/// <param name="port"></param>
/// <param name="baudRate"></param>
public static void WsOnSupperPower(string address,string password,string modelCode,bool isOn,int port,BaudRate baudRate)
{
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;
}
/// <summary>
/// 构建透明转发-下发命令
/// </summary>
/// <param name="address">集中器地址</param>
/// <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>
public static byte[] BuildTransparentForwardingSendCmd(string address, int port, BaudRate baudRate, List<string> datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8,
int waitContentTimeout = 100, int waitByteTimeout = 100)
{
var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRate, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout);
dataUnit.AddRange(GetPW());
var reqParameter = new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = address,
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 0
},
MSA = GetMSA(address),
Pn = 0,
Fn = 1
};
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
return bytes;
}
[Obsolete]
public static List<string> AmmeterValveControl(string address, string specialnocode, string password, bool state, string modelCode = "")
{
address = address.Trim().TrimStart('0');
if (address.Length < 12) address = address.PadLeft(12, '0');
string Code = string.Empty;
if (state)
{
if (string.IsNullOrEmpty(specialnocode))
Code = "1B";
else
Code = specialnocode == "1B" || specialnocode == "1C" ? specialnocode : "1C";
}
else
Code = "1A";//跳闸
if (specialnocode == "1W")
{
if (state)
Code = "1A";
else
Code = "1C";
}
var pwdLevel = "02";
if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866")
pwdLevel = "04";
else if (modelCode == "DDS2705")
pwdLevel = "03";
if (!string.IsNullOrWhiteSpace(password) && password.Contains("|"))
{
var sp = password.Split('|');
pwdLevel = sp[1];
password = sp[0];
}
string strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();
if (specialnocode == "1D" || modelCode == "SZBD_DDZY1225")
strDate = "FF FF FF FF FF FF";
string strP = password.StrAddSpan().StrReverseOrder();
string strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + Code + " 00 " + strDate;
string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2");
string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " ";
string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
strReturn += strSum.Substring(strSum.Length - 2) + " 16";
return strReturn.Split(' ').ToList();
}
/// <summary>
/// 构建透明转发-下发数据单元
/// </summary>
/// <param name="port">终端通信端口 1~31</param>
/// <param name="baudRate">0~7 对应300,600,1200,2400,4800,7200,9600,19200</param>
/// <param name="datas">转发内容</param>
/// <param name="stopBit">停止位</param>
/// <param name="parity">校验方式</param>
/// <param name="dataBit">数据位</param>
/// <param name="waitContentTimeout">等待报文超时时间/s</param>
/// <param name="waitByteTimeout">等待字节超时时间/ms</param>
/// <returns></returns>
private static List<string> BuildTransparentForwardingSendDataUnit(int port, BaudRate baudRate, List<string> datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8,
int waitContentTimeout = 100, int waitByteTimeout = 100)
{
var dataUnit = new List<string>();
var portHex = port.DecToHex().PadLeft(2, '0');
dataUnit.Add(portHex);
var baudRateBin = ((int)baudRate).DecToBin().PadLeft(3, '0');
var stopBitBin = ((int)stopBit).DecToBin();
var parityBin = parity != Parity.None ? $"1{((int)parity).DecToBin()}" : "00";
var dataBitBin = ((int)dataBit).DecToBin().PadLeft(2, '0');
var controlHex = $"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}".BinToHex().PadLeft(2, '0'); ;
dataUnit.Add(controlHex);
var waitContentTimeoutBin = $"1{waitContentTimeout.DecToBin().PadLeft(7, '0')}";
var waitContentTimeoutHex = waitContentTimeoutBin.BinToHex().PadLeft(2, '0');
var waitByteTimeoutHex = waitByteTimeout.DecToHex().PadLeft(2, '0');
dataUnit.Add(waitContentTimeoutHex);
dataUnit.Add(waitByteTimeoutHex);
var countHex = datas.Count.DecToHex().PadLeft(4, '0');
var countHexPairs = countHex.StringToPairs();
countHexPairs.Reverse();
dataUnit.AddRange(countHexPairs);
dataUnit.AddRange(datas);
return dataUnit;
}
/// <summary>
/// 构建下发命令
/// </summary>
/// <param name="reqParameter"></param>
/// <param name="dataUnit"></param>
/// <returns></returns>
public static byte[] BuildSendCommandBytes(ReqParameter reqParameter, List<string>? dataUnit = null)
{
var cmdStrList = new List<string>();
var userDatas = BuildUserData(reqParameter, dataUnit);
var hearders = BuildHeaders(userDatas.Count);
var cs = GetCS(userDatas);
cmdStrList.AddRange(hearders);
cmdStrList.AddRange(userDatas);
cmdStrList.Add(cs);
cmdStrList.Add(endStr);
Console.WriteLine(string.Join(" ", cmdStrList));
var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray();
return bytes;
}
/// <summary>
/// 构建电表参数设置-下发数据单元
/// </summary>
/// <param name="meterParameters"></param>
/// <returns></returns>
private static List<string> BuildAmmeterParameterSendDataUnit(List<AmmeterParameter> meterParameters)
{
var hexDatas = new List<string>();
var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0');
hexDatas.Add(countHex);
//TODO 优化代码:目标数据入参,返回类型为出参
for (int i = 0; i <= meterParameters.Count - 1; i++)
{
var meter = meterParameters[i];
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 = ((int)meter.ProtocolType).DecToHex().PadLeft(2, '0');
hexDatas.Add(protocolTypeHex);
hexDatas.Add(meter.Address);
hexDatas.Add(meter.Password.PadLeft(12, '0'));
var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}";
var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0');
hexDatas.Add(rateNumberHex);
var intBitNumberBin = (meter.IntegerBitNumber - 4).DecToBin().PadLeft(2, '0');
var decBitNumberBin = (meter.DecimalBitNumber - 1).DecToBin().PadLeft(2, '0');
var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}";
var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0');
hexDatas.Add(intAndDecBitNumberHex);
hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0'));
var userCategoryNumberBin = meter.UserCategoryNumber.DecToBin().PadLeft(4, '0');
var userSubclassNumberBin = meter.UserSubclassNumber.DecToBin().PadLeft(4, '0');
var userNumberHex = $"{userCategoryNumberBin}{userSubclassNumberBin}".BinToHex().PadLeft(2, '0');
hexDatas.Add(userNumberHex);
}
//高位在前,低位在后
var datas = new List<string>();
foreach (var hexData in hexDatas)
{
if (hexData.Length == 2)
datas.Add(hexData);
else
{
var lst = hexData.StringToPairs();
lst.Reverse();
datas.AddRange(lst);
}
}
datas.AddRange(GetPW());
return datas;
}
/// <summary>
/// 构建水表参数设置-下发数据单元
/// </summary>
/// <param name="meterParameters"></param>
/// <returns></returns>
private static List<string> BuildWaterMeterParameterSendDataUnit(List<WaterMeterParameter> meterParameters)
{
var hexDatas = new List<string>();
var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0');
hexDatas.Add(countHex);
for (int i = 0; i <= meterParameters.Count - 1; i++)
{
var meter = meterParameters[i];
var protocolType = (int)meter.ProtocolType;
var currentProtocolType = protocolType;
if (protocolType == 43)
currentProtocolType = 1;
else if (protocolType > 32) currentProtocolType = 32;
//TODO:无线水表 小数位
if (currentProtocolType == 32 && meter.Address.Substring(0, 2) != "00")
{
var ejz = meter.Address.Substring(0, 2).HexToBin().PadLeft(8, '0');
var xs = ejz.Substring(6, 2).BinToDec();
var zs = ejz.Substring(0, 6).BinToDec();
//userData.Add(new QGDW3671UserData() { Name = "整数位无线水表", Value = zs });
//userData.Add(new QGDW3671UserData() { Name = "小数位无线水表", Value = xs });
}
var userCategoryNumber = meter.UserCategoryNumber;
var userSubclassNumber = meter.UserSubclassNumber;
if (protocolType == 32)
userCategoryNumber = 1;
else if (protocolType == 45)
{
userCategoryNumber = 1;
userSubclassNumber = 9;
}
else if (protocolType == 1)
userSubclassNumber = 1;
var indexHex = (i + 1).DecToHex().PadLeft(4, '0');
hexDatas.Add(indexHex);
var pnHex = meter.Pn.DecToHex().PadLeft(4, '0');
hexDatas.Add(pnHex);
var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0');
var portBin = meter.Port.DecToBin().PadLeft(5, '0');
var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0');
hexDatas.Add(baudRateAndPortHex);
var protocolTypeHex = currentProtocolType.DecToHex().PadLeft(2, '0');
hexDatas.Add(protocolTypeHex);
hexDatas.Add(meter.Address);
hexDatas.Add(meter.Password.PadLeft(12, '0'));
var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}";
var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0');
hexDatas.Add(rateNumberHex);
var intBitNumberBin = meter.IntegerBitNumber.DecToBin().PadLeft(2, '0');
var decBitNumberBin = meter.DecimalBitNumber.DecToBin().PadLeft(2, '0');
var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}";
var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0');
hexDatas.Add(intAndDecBitNumberHex);
hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0'));
var userCategoryNumberBin = userCategoryNumber.DecToBin().PadLeft(4, '0');
var userSubclassNumberBin = userSubclassNumber.DecToBin().PadLeft(4, '0');
var userNumberHex = $"{userCategoryNumberBin}{userSubclassNumberBin}".BinToHex().PadLeft(2, '0');
hexDatas.Add(userNumberHex);
}
//高位在前,低位在后
var datas = new List<string>();
foreach (var hexData in hexDatas)
{
if (hexData.Length == 2)
datas.Add(hexData);
else
{
var lst = hexData.StringToPairs();
lst.Reverse();
datas.AddRange(lst);
}
}
datas.AddRange(GetPW());
return datas;
}
//AUX=消息认证码字段PW,16个字节
private static List<string> GetPW()
{
var str = "00";
var pWList = Enumerable.Repeat(str, pWLen).ToList();
return pWList;
}
/// <summary>
/// 帧校验和
/// </summary>
/// <param name="userData">用户数据区</param>
/// <returns></returns>
private static string GetCS(List<string> userData)
{
byte sum = 0;
foreach (var d in userData)
{
var b = Convert.ToByte(d, 16);
sum += b;
}
return sum.ToString("X2");
}
/// <summary>
/// 用户数据区
/// </summary>
/// <param name="reqParameter"></param>
/// <returns></returns>
private static List<string> BuildUserData(ReqParameter reqParameter, List<string>? dataUnit)
{
var c = BuildC(reqParameter.FunCode, reqParameter.PRM);
var a = BuildAList(reqParameter.A, reqParameter.MSA);
var linkUserData = BuildLinkUserData(reqParameter.AFN, reqParameter.Seq,
((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit);
var list = new List<string>() { c };
list.AddRange(a);
list.AddRange(linkUserData);
return list;
}
/// <summary>
/// 固定长度的报文头 起始字符+长度+长度+起始字符
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
private static List<string> BuildHeaders(int length)
{
var headers = new List<string>();
headers.Add(startStr);
var l = BuildLength(length);
headers.AddRange(l);
headers.AddRange(l);
headers.Add(startStr);
return headers;
}
/// <summary>
/// 长度 2字节 [用户数据区长度]
/// </summary>
/// <returns></returns>
private static List<string> BuildLength(int length1)
{
var binaryLen = length1.DecToBin();
var protocolIdentification = Enum.Format(typeof(ProtocolIdentification),
ProtocolIdentification.使, "d").PadLeft(2, '0');
var lenStr = $"{binaryLen}{protocolIdentification}";
var hexLen = lenStr.BinToHex();
hexLen = hexLen.PadLeft(4, '0');
var list = hexLen.StringToPairs();
list.Reverse();
return list;
}
/// <summary>
/// 控制域
/// </summary>
/// <param name="funCode">功能码</param>
/// <param name="fcb"></param>
/// <param name="fcv"></param>
/// <returns></returns>
private static string BuildC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效)
{
var cMasterStationFunCodeHex = funCode.DecToBin();
cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0');
var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}";
var hexC = strC.BinToHex().PadLeft(2, '0');
return hexC;
}
/// <summary>
/// 地址域 3220 09872
/// </summary>
/// <param name="a1">行政区划码 BCD码 3220=2032</param>
/// <param name="a2">逻辑地址 BIN 09872=2690=>9026</param>
/// <param name="a3">主站地址 BIN 0~127</param>
/// <returns></returns>
private static List<string> BuildAList(string a, int mSA)
{
var list = new List<string>();
var a1 = a.Substring(0, 4);
var a1Pairs = a1.StringToPairs();
a1Pairs.Reverse();
list.AddRange(a1Pairs);
var a2 = Convert.ToInt32(a.Substring(4));
var decA2 = a2.DecToHex();
var a2Pairs = decA2.PadLeft(4, '0').StringToPairs();
a2Pairs.Reverse();
list.AddRange(a2Pairs);
//TODO:主站地址和组地址标志
var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0";
list.Add(a3Bin.BinToHex().PadLeft(2, '0'));
return list;
}
private static List<string> BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List<string>? dataUnit)
{
var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0');
var sEQ = BuildSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ);
var dA = BuildDA(pn);
var dT = BuildDT(fn);
var list = new List<string>() { aFNValue, sEQ };
list.AddRange(dA);
list.AddRange(dT);
if (dataUnit != null)
{
list.AddRange(dataUnit);
}
//list.AddRange(GetDataUnit(aFN,seq));
if (seq.TpV == TpV.)
list.AddRange(BuildTp("00"));
return list;
}
/// <summary>
/// 帧序列域
/// </summary>
/// <param name="tpV"></param>
/// <param name="fIRFIN"></param>
/// <param name="cON"></param>
/// <returns></returns>
private static string BuildSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ)
{
var tpVValue = Enum.Format(typeof(TpV),
tpV, "d");
var fIRFINValue = Enum.Format(typeof(FIRFIN),
fIRFIN, "d");
var cONValue = (int)cON;
var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{pRSEQ.DecToBin().PadLeft(4, '0')}";
var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0');
return hexSEQ;
}
/// <summary>
/// 信息点标识
/// </summary>
/// <param name="pn">计量点</param>
/// <returns></returns>
private static List<string> BuildDA(int pn)
{
if (pn == 0)
return new List<string>() { "00", "00" };
var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组
var dA1 = pn - (dA2 - 1) * 8;//pn % 8
var dA1Hex = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位
var dA2Hex = dA2.DecToHex();
return new List<string>() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') };
}
/// <summary>
/// 数据单元标识
/// </summary>
/// <param name="fn"></param>
/// <returns></returns>
private static List<string> BuildDT(int fn)
{
var dT2 = (fn - 1) / 8;//从零开始 第几组
var dT1 = fn - dT2 * 8;
var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位
var dT2Hex = dT2.DecToHex();
return new List<string>() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') };
}
/// <summary>
/// 时间标签
/// </summary>
/// <param name="pFC">启动帧帧序号计数器PFC 1字节</param>
/// <param name="delayTime">允许发送传输延时时间 min 1字节</param>
/// <returns></returns>
private static List<string> BuildTp(string pFC = "00", int delayTime = 0)
{
var now = DateTime.Now; // 获取当前时间
var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数
var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数
var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数
var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数
return new List<string>() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') };
}
#endregion
#region 645
/// <summary>
/// 构建电表阀控下发数据单元
/// </summary>
/// <param name="address">电表地址</param>
/// <param name="specialControlCode">特殊控制码</param>
/// <param name="password">密码</param>
/// <param name="state">是否为开阀</param>
/// <param name="modelCode">型号码</param>
/// <returns></returns>
public static List<string> BuildAmmeterValveControlSendDataUnit(string address, string specialControlCode, string password, bool state, string modelCode = "")
{
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();
var dataList = Build645SendCommand(address, "1C", dataUnit);
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>
/// <param name="address">电表地址</param>
/// <param name="password"></param>
/// <param name="state">true 保电 false 保电解除</param>
/// <param name="modelCode">型号码</param>
/// <returns></returns>
public static List<string> BuildAmmeterLockSendDataUnit(string address, string password, bool state, string modelCode = "")
{
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();
var dataList = Build645SendCommand(address, "1C", dataUnit);
return dataList;
}
/// <summary>
/// 构建电表认证下发数据单元
/// </summary>
/// <param name="address">电表地址</param>
/// <param name="ramDon"></param>
/// <param name="maco"></param>
/// <returns></returns>
public static List<string> BuildAmmeterIdentitySendDataUnit(string address, string ramDon, string maco)
{
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);
var dataList = Build645SendCommand(address, "03", dataUnit);
return dataList;
}
/// <summary>
/// 构建电表清零下发数据单元
/// </summary>
/// <param name="address">电表地址</param>
/// <param name="password"></param>
/// <returns></returns>
public static List<string> BuildAmmterClearSendDataUnit(string address, string password)
{
var strP = password.StrAddSpan().StrReverseOrder();
var strSJY = " 02 " + strP + " 01 00 00 00 ";
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
var dataList = Build645SendCommand(address, "1A", dataUnit);
return dataList;
}
/// <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>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="dataMark"></param>
/// <param name="power"></param>
/// <returns></returns>
public static List<string>? AssembleWsSupperPower(string address, string password, string dataMark, decimal power)
{
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] };
return AssembleWrite(address, password, dataMark, data);
}
/// <summary>
/// 威胜表的超功率(超功率开关)
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="isOn"></param>
/// <returns></returns>
public static List<string> AssembleWsOnSupperPower(string address, string password, bool isOn = true)
{
var data = new string[] { (isOn ? "01" : "00") };
return AssembleWrite(address, password, "0E400001", data);
}
/// <summary>
/// 威胜表的超功率(第一路恶性负载绝对功率判断阈值)
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="dataMark"></param>
/// <param name="power"></param>
/// <returns></returns>
public static List<string>? AssembleWsAbsolutePowerSetting(string address, string password, string dataMark, decimal power)
{
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] };
return AssembleWrite(address, password, dataMark, data);
}
/// <summary>
/// 威胜表的超功率(第一路恶性负载功率因数判断阀值)
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="dataMark"></param>
/// <param name="factor"></param>
/// <returns></returns>
public static List<string>? AssembleWsPowerFactor(string address, string password, string dataMark, decimal factor)
{
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] };
return AssembleWrite(address, password, dataMark, data);
}
/// <summary>
/// 构建写数据
/// </summary>
/// <param name="address"></param>
/// <param name="password"></param>
/// <param name="di0_3"></param>
/// <param name="data"></param>
/// <returns></returns>
public static List<string> AssembleWrite(string address, string password, string di0_3, string[] data)
{
var returnList = new List<string>();
returnList.Add(startStr);
var addressList = address.StringToPairs();
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>
private static List<string> SoftProgram(string address,string modelCode,string password)
{
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);
//替换表地址
var addressList = address.StringToPairs();
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;
}
#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();
}
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
}
}