tbf/TBF/Rig/ControlBoard/Uni/OutputMessage.cs

246 lines
9.3 KiB
C#

///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Diagnostics;
using log4net;
using Dirichlet.Numerics;
using Common;
using System.Web.Routing;
namespace TBF.Rig.ControlBoard.Uni
{
public static class OutputMessage
{
private static readonly ILog log = LogManager.GetLogger(typeof(OutputMessage));
public const int PayloadLen = 38;
static Action arguments = new Action();
///
static void FetchArguments(Action combinedAction)
{
foreach (var aId in (ActionID[])Enum.GetValues(typeof(ActionID)))
{
if ((combinedAction.ActionId & aId) != 0) arguments.SetArgs(combinedAction, aId);
}
}
public static string Caption()
{
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
return " [. .. .. ..Cmd P1 P2 (pulses) (mass.p) xx (cfg) Xg (------- route -------) (DA2) RV Rpar1 Rpar2 St (DA1) PID x ST Div Sum ]";
}
public static byte[] GetMessage(Action action, short config, UInt128 bitsToInvert)
{
FetchArguments(action);
byte[] message = new byte[PayloadLen + 5]; /// headed 3 bytes, checksum 2 bytes
/// Header + message code (4 bytes)
message[0] = Const.STX;
message[1] = 1; /// Control board addres
message[2] = (byte)PayloadLen; /// Payload length
message[3] = (byte)' '; /// Message code
/// Command
message[4] = GetCommand(action);
message[5] = action.IsStart() ? GetStartParams(action) : action.IsStop() ? GetStopParams(action) : (byte)0;
message[6] = (byte)(((arguments.DivId <= 0) ? 0 : (arguments.DivId - 1)) + ((arguments.FlowMId > 7) ? arguments.FlowMId : 0) + (action.IsDelayedStart ? 128 : 0));
int totalPulsesCount = (arguments.TotalPulsesCount < 0) ? 0 : arguments.TotalPulsesCount;
message[7] = (byte)(totalPulsesCount & 0xFF);
message[8] = (byte)((totalPulsesCount >> 8) & 0xFF);
message[9] = (byte)((totalPulsesCount >> 16) & 0xFF);
int massPulsesCount = (arguments.MassPulsesCount < 0) ? 0 : arguments.MassPulsesCount;
message[10] = (byte)(massPulsesCount & 0xFF);
message[11] = (byte)((massPulsesCount >> 8) & 0xFF);
message[12] = (byte)((massPulsesCount >> 16) & 0xFF);
message[13] = 0;
message[14] = (byte)(config & 0xff);
message[15] = (byte)((config >> 8) & 0xff);
/// Route
UInt128 routeOut = arguments.Route ^ bitsToInvert;
message[16] = ((action.ActionId & ActionID.ChangeRoute) != 0) ? (byte)1 : (byte)0; /// Route change flag
message[17] = (byte)(routeOut & 0xFF); /// RV0 .. RV3
message[18] = (byte)((routeOut >> 8) & 0xFF); /// RV4 .. RV7
message[19] = (byte)((routeOut >> 16) & 0xFF);
message[20] = (byte)((routeOut >> 24) & 0xFF); /// Div1 .. Div5
message[21] = (byte)((routeOut >> 32) & 0xFF);
message[22] = (byte)((routeOut >> 40) & 0xFF); /// F
message[23] = (byte)((routeOut >> 48) & 0xFF); /// G
message[24] = (byte)((routeOut >> 56) & 0xFF); /// H
/// DA2
message[25] = 0;
message[26] = 0;
/// Regulation valve
message[27] = (action.RegVId < 0 || (action.RegVId == TBF.Rig.Uni.RegValveAnalog.RegValve.RVAnalogIdx && action.RegVMode == RegValveMode.TargetFrequency))
? (byte)0 : (byte)(action.RegVId | (int)action.RegVMode);
message[28] = (byte)(action.RVMovePar1 & 0xFF);
message[29] = (byte)((action.RVMovePar1 >> 8) & 0xFF);
message[30] = (byte)(action.RVMovePar2 & 0xFF);
message[31] = (byte)((action.RVMovePar2 >> 8) & 0xFF);
message[32] = GetRVStopParam(action);
/// DA1
message[33] = (byte)(arguments.InitDacVal & 0xFF);
message[34] = (byte)((arguments.InitDacVal >> 8) & 0xFF);
message[35] = (byte)Math.Max(1, Math.Min(255, arguments.PID)); /// PIDRV
message[36] = (byte)Math.Max(4, Math.Min(255, action.TolerRV)); /// TolerRV (4..20 mA reg.valve only)
message[37] = (byte)Math.Max(0, Math.Min(255, arguments.StabTime)); /// StabRV
message[38] = (byte)((arguments.DivThreshold >> 2) & 0xFF);
//---
message[39] = (byte)((action.RegulationMinStep << 4) & 0xFF); // ak 0 = koli kompatibilite, 1-6 = hodnoty prislusne pre spodnu saturaciu vypinacej periody casu
message[40] = (byte)((action.RegulationMinStep << 4) & 0xFF);
//---
/*int x = 0;
if (action.RegVId == 1 || action.RegVId == 2) x = 3;
else if (action.RegVId == 3 || action.RegVId == 4) x = 5;
else if (action.RegVId == 5 || action.RegVId == 5) x = 3;
message[39] = (byte)((x << 4) & 0xFF);
message[40] = (byte)((x << 4) & 0xFF);*/
/*//---
message[39] = 0x50; // ak 0 = koli kompatibilite, 1-6 = hodnoty prislusne pre spodnu saturaciu vypinacej periody casu
message[40] = 0x50;
//---*/
Debug.Assert(40 == PayloadLen + 2);
/// Checksum (2 bytes)
int checksum = 0;
for (int i = 1; i < PayloadLen + 3; i++) checksum += message[i];
message[PayloadLen + 3] = (byte)(checksum & 0xFF);
message[PayloadLen + 4] = (byte)((checksum >> 8) & 0xFF);
log.Info("");
return message;
}
static byte GetCommand(Action action)
{
if (action.StartStop == Command.DelayStartOrStop)
{
return (byte)Command.None;
}
else if (action.StartStop == Command.Start && action.IsProlonged)
{
return (byte)(Command.Start | Command.ProlongedFlag);
}
else
{
return (byte)action.StartStop;
}
}
static byte GetStartParams(Action action)
{
int param = (action.FlowMId <= 7) ? action.FlowMId : 0;
if (action.IsDivUsed) param |= (int)StartParam.DiverterStart;
if (action.IsSyncMethod) param |= (int)StartParam.SynchroMethod;
if (action.IsStartStop) param |= (int)StartParam.StartStopMethod;
return (byte)param;
}
static byte GetStopParams(Action action)
{
return (byte)StopDevs.All;
}
static byte GetRVStopParam(Action a)
{
if (a.IsStop() || (a.ActionId & ActionID.RegVlvStop) != 0)
{
return (byte)0x20;
}
else if ((a.ActionId & ActionID.SetFlow) != 0 && a.RegVId == TBF.Rig.Uni.RegValveAnalog.RegValve.RVAnalogIdx)
{
return (byte)0x42;
}
/*else
{
return (a.RegulationMinStep >= 0 || a.RegulationMinStep <= 6)?(byte)(a.RegulationMinStep << 4):(byte)(7<<4);
}*/
return 0;
}
}
public enum Command : byte
{
None = 0, /// Request data only
Start = 1,
Stop = 2,
GetDiverterTransitionData = 4,
GetScopeAnalyzerData = 7,
ResetScopeAnalyzer = 8,
GetSwitchCounterData = 9,
///
ProlongedFlag = 0x10, /// Not a command of its own, a valid command is (byte)(Command.Start | Command.ProlongedFlag)
DelayStartOrStop = 255, /// Prevents other start or stop command, results in Command.None when creating a message
}
public enum StartParam : byte
{
EtalonMask = 0x07,
DiverterStart = 0x08,
SynchroMethod = 0x10,
DirectGateStart = 0x20, /// ???
StartStopMethod = 0x40,
CalibrationMode = 0x80,
}
public enum StopDevs : byte
{
None = 0,
Reference = 0x01, /// bit 0
Diverter = 0x02, /// bit 1
GatePulse = 0x08, /// bit 3
TimeMeasurement = 0x10, /// bit 4
BypassDevCoupled2Div = 0x20, /// bit 5
RegValveRegulation = 0x80, /// bit 7
All = 0x9B,
}
public enum ValveChgFlag : byte
{
DoNotChange = 0,
Change = 1,
SendPressureMeterAddresses = 2,
}
public enum RegValveMode : byte
{
None = 0,
TargetFrequency = 0x10, /// Low and high frequency limits (0..2000Hz,0..2200Hz) are specified
TargetPosition = 0x20, /// Low and high position (=DAC value) limits (0..100%) are specified
Stop = 0x30, /// Stop regulation
PulseWidth = 0x40, /// Pulse width 0.05 .. 2 sec. ... opening and closing (opening=0x40, closing=0xC0)
NegPulseWidth = 0x80, /// Pulse width 0.05 .. 2 sec. ... closing (closing=0xC0)
}
public enum RegValveState : byte
{
Idle = 0,
PwOrFreqRegul = 2,
DacValueRegul = 3,
}
}