TBF.Rig.DataEntry.Double24

This commit is contained in:
Milan Hanajik 2021-11-10 14:03:10 +01:00
parent 284feb73dc
commit 71517b6cdb
22 changed files with 1627 additions and 758 deletions

View File

@ -0,0 +1,857 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using log4net;
using NHibernate;
using Common;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.BenchControl.GenericDevices;
using TBF.BenchControl.Sequences;
using Dirichlet.Numerics;
using TBF.Resources;
namespace TBF.BenchControl
{
public enum MachineState
{
Undefined = 0,
Disabled,
StartingUp, /// Start-up: Initialize() of all devices + start of the worker thread
FailedToStart, /// Most likely Initialize() of any device thrown an exception
Running, /// RunDeviceBefore() and RunDeviceAfter() of all devices, Start()/Run()/Stop() of operations
ShuttingDown, /// Shutdown: StopDevice() and StopDevice2() of all devices
Off, /// Off after the shutdown
}
/// <summary>
/// This class controls real test bench behavior.
/// It is based on a state machine
/// </summary>
public static class StateMachine
{
private static readonly ILog log = LogManager.GetLogger(typeof(StateMachine));
private static readonly ILog wlog = LogManager.GetLogger(typeof(StateMachine));
/// Private devices and components
static IList<IComponent> components; /// list of all components
static IList<IDevice> devices; /// list of devices
///
/// Bench paths
static IList<Config.Entities.FeedingPath> feedingPaths;
static IList<Config.Entities.BenchPath> benchPaths;
static IList<Config.Entities.OutputPath> outputPaths;
static IList<Config.Entities.MetersPath> metersPaths;
static IList<Config.Entities.HeatMetersPath> heatMetersPaths;
public static IList<Config.Entities.TransitionSequence> TransitionSequences;
public static IList<Config.Entities.TransitionStep> TransitionSteps;
/// Public components
public static Elde.ControlBoardDev ControlBoard;
public static GenericDevices.IAmbient Ambient;
public static IOperation BenchWaitingOp;
public static IOperation BenchErrorOp;
public static GenericDevices.IScaleOrTank Tank1;
public static GenericDevices.IScaleOrTank Tank2;
public static GenericDevices.IScaleOrTank Tank3;
public static GenericDevices.IValve DrainValve1;
public static GenericDevices.IValve DrainValve2;
public static GenericDevices.IValve DrainValve3;
public static IList<IValve> MasterValves; /// list of directly controlled valves
public static IList<IValve> CoupledValves; /// list of coupled valves
public static IList<Elde.ValveEx.Valve> ExtendedValves; /// list of extended valves
public static IList<string> LoopStartNames;
public static IList<string> LoopEndNames;
/// Time and synchronization
#if TURA_IPERL || TURA_IPERL_NEW
public const int Period = 2; /// State machine period in sec.
#else
public const int Period = 1; /// State machine period in sec.
#endif
static DateTime startDateTime; /// DateTime of time instance when the state machine worker thread starts
static int currentTimeSec; /// Time from the start of the state machine in seconds
public static MachineState MachineState; /// see enum MachineState for explanation
/// Worker thread and database session
static Thread workerThread;
static IList<State> states; /// list of states
public static DateTime CycleStartTimeStamp;
public static IList<IValve> DefaultValvesOpen
{
get
{
return GenericDevices.ValveBase.Merge(
Utils.ValvesOpen((feedingPaths != null && feedingPaths.Count > 0) ? feedingPaths[0] : null),
Utils.ValvesOpen((benchPaths != null && benchPaths.Count > 0) ? benchPaths[0] : null),
Utils.ValvesOpen((outputPaths != null && outputPaths.Count > 0) ? outputPaths[0] : null)
);
}
}
public static IList<IValve> DefaultValvesClose
{
get
{
return GenericDevices.ValveBase.Merge(
Utils.ValvesClose((feedingPaths != null && feedingPaths.Count > 0) ? feedingPaths[0] : null),
Utils.ValvesClose((benchPaths != null && benchPaths.Count > 0) ? benchPaths[0] : null),
Utils.ValvesClose((outputPaths != null && outputPaths.Count > 0) ? outputPaths[0] : null)
);
}
}
/// <summary>
/// Loaded by LoadProcedure() or IOperation LoadProcedureOp(...)
/// </summary>
public static Procedure Procedure; /// Procedure
public static TestInstance[] TestInstances; /// Tests
public static bool IsRemoteProcedure;
/// Hardware devices connected to the PC controlling the bench.
public static IList<IComponent> Components { get { return components; } }
public static IList<IDevice> Devices { get { return devices; } }
/// <summary>
/// DateTime of time instance when the state machine worker thread starts
/// </summary>
public static DateTime StartDateTime { get { return startDateTime; } }
/// <summary>
/// Current state name
/// </summary>
public static int Time
{
get { return currentTimeSec; }
set { currentTimeSec = value; }
}
/// <summary>
/// Constructor
/// </summary>
static StateMachine()
{
devices = new List<IDevice>();
states = new List<State>();
currentTimeSec = 0;
}
/// <summary>
/// Add a device to the state machine.
/// </summary>
/// <param name="obj">Device</param>
public static void AddDevice(IDevice device)
{
if (device != null && !devices.Contains(device)) devices.Add(device);
}
/// <summary>
/// Add a state to the state machine.
/// In this way a sequence can be created programtically.
/// </summary>
/// <param name="obj">State</param>
public static void AddState(State state)
{
if (state != null && !states.Contains(state)) states.Add(state);
}
/// <summary>
/// Remove the state from the state machine.
/// </summary>
/// <param name="obj">State</param>
public static void RemoveState(State state)
{
if (state != null && state != State.CurrentState && states.Contains(state)) states.Remove(state);
}
/// <summary>
/// Get a state from a label
/// </summary>
/// <param name="label"></param>
/// <returns>The matching state or null</returns>
static State GetStateFromLabel(string label)
{
if (label == null) return null;
foreach (State state in states)
{
if (state.Label != null && state.Label.Equals(label)) return state;
}
return null;
}
/// <summary>
/// Start the state machine in the state 'label' in a desired mode of operation.
/// This method is called in the UI thread and creates a new state machine thread.
/// This method call should be embedded in: try { StateMachine.Start(...); } catch { }
/// to handle configuration problems. Calls CreateDevices(mode) and CreateStates().
/// </summary>
/// <param name="mode">Mode of operation</param>
/// <param name="benchData">A copy of bench data used by the state machine</param>
/// <param name="label">Identifies the initial state</param>
#if DN100
public static void InitializeBoardEtc(ControlCom2VB.ControlCom2panel ctrlBrdComponent)
#elif FUZHOU_150 || MUNICH
public static void InitializeBoardEtc(ControlComponent3Munich.UserControl1 ctrlBrdComponent)
#elif FUZHOU_300
public static void InitializeBoardEtc(ControlComponent3F300.UserControl1 ctrlBrdComponent)
#elif BERLIN || GELSENWASSER || GENESIS || IZRAEL_200 || PETERSBURG_200 || PUCHONG_200 || SLM_150
public static void InitializeBoardEtc(ControlComponent_Izrael2014.UserControl1 ctrlBrdComponent)
#else /// all newer benches
public static void InitializeBoardEtc(ControlComponent_Torino2015.UserControl1 ctrlBrdComponent)
#endif
{
/// Load the list of components (entities) from the database.
/// Then create the components (derived from IComponent).
components = BenchControl.TbfComponents.LoadComponentsFromDB(TBF.DB.CreateSession(Common.DBKind.Config));
MasterValves = GenericDevices.ValveBase.MasterValves(components);
CoupledValves = GenericDevices.ValveBase.CoupledValves(components);
ExtendedValves = GenericDevices.ValveBase.ExtendedValves(components);
/// Find all balances (to initialize tank capacities in the control board)
/// Find the control board
IList<IScaleOrTank> tanks = new List<IScaleOrTank>();
ProcessData.IperlHeads = new List<TestMethods.iPerlCommunication.iPerlHead.IperlHead>();
SequenceBase.FlowMeters = new List<IFlowMeter>();
SequenceBase.RegulValves = new List<IRegValve>();
SequenceBase.FeedingRegulValves = new List<IRegValve>();
SequenceBase.OutputRegulValves = new List<IRegValve>();
SequenceBase.PumpsWithFM = new List<IPumpFM>();
SequenceBase.WaterMeters = new List<IWaterMeter>();
SequenceBase.Cameras = new List<ICamera>();
LoopStartNames = new List<string>();
LoopEndNames = new List<string>();
UInt128 valvesToInvert = 0;
foreach (var cmpnt in components)
{
if (cmpnt is Elde.ControlBoardDev) ControlBoard = cmpnt as Elde.ControlBoardDev;
if (cmpnt is IBenchInfo) ProcessData.BenchInfo = cmpnt as IBenchInfo;
if (cmpnt is IErrorFlags) ProcessData.ErrorFlagsComp = cmpnt as IErrorFlags;
if (cmpnt is IStatisticsMonitoring) ProcessData.StatisticsMonitoringComp = cmpnt as IStatisticsMonitoring;
if ((cmpnt is Output.DB.SensusOracle.Database) && (ProcessData.OracleDB == null))
{
/// The 1st Oracle database component found --> store the reference
ProcessData.OracleDB = cmpnt as Output.DB.SensusOracle.Database;
}
if ((cmpnt is Output.DB.ProductionTracing.Tracing) && (ProcessData.TracingDB == null))
{
/// The 1st production tracing database component found --> store the reference
ProcessData.TracingDB = cmpnt as Output.DB.ProductionTracing.Tracing;
}
if (cmpnt is TestMethods.iPerlCommunication.iPerlHead.IperlHead)
{
ProcessData.IperlHeads.Add(cmpnt as TestMethods.iPerlCommunication.iPerlHead.IperlHead);
}
if (cmpnt is IFlowMeter) SequenceBase.FlowMeters.Add(cmpnt as IFlowMeter);
if ((cmpnt is IRegValve) && !(cmpnt is BenchControl.Elde.RegulValveTandem.RegulValveTandem))
{
IRegValve rv = cmpnt as IRegValve;
SequenceBase.RegulValves.Add(rv);
if (rv.Category == ValveCategory.Feeding) SequenceBase.FeedingRegulValves.Add(rv);
if (rv.Category == ValveCategory.Output) SequenceBase.OutputRegulValves.Add(rv);
}
if (cmpnt is IPumpFM && !(cmpnt is Elde.PumpTandem.Pump))
{
SequenceBase.PumpsWithFM.Add(cmpnt as IPumpFM);
}
if (cmpnt is IWaterMeter) SequenceBase.WaterMeters.Add(cmpnt as IWaterMeter);
if (cmpnt is ICamera) SequenceBase.Cameras.Add(cmpnt as ICamera);
if (cmpnt is GenericDevices.IAmbient) Ambient = cmpnt as GenericDevices.IAmbient;
if (cmpnt is GenericDevices.IParallelOutput && cmpnt.Name.ToLower().Contains("tower"))
{
BenchWaitingOp = (cmpnt as GenericDevices.IParallelOutput).ShowBenchWaitingOp();
BenchErrorOp = (cmpnt as GenericDevices.IParallelOutput).ShowBenchErrorOp();
}
if (cmpnt is ITestMethod && cmpnt.ClassName == "TestMethods.OuterLoop.Start") LoopStartNames.Add(cmpnt.Name);
if (cmpnt is ITestMethod && cmpnt.ClassName == "TestMethods.OuterLoop.End") LoopEndNames.Add(cmpnt.Name);
if (cmpnt is IScaleOrTank)
{
IScaleOrTank tank = cmpnt as IScaleOrTank;
tanks.Add(tank);
if (Tank1 == null) Tank1 = tank;
else if (Tank2 == null) Tank2 = tank;
else if (Tank3 == null) Tank3 = tank;
}
Elde.Valve.Valve eldeValve = (cmpnt as Elde.Valve.Valve);
if ((eldeValve != null) && eldeValve.Inverted) valvesToInvert |= eldeValve.Mask;
}
/// Pre-initialize the control board (= buffer the arguments ctrlBrdComponent, tankCapacities)
if (ControlBoard != null)
{
/// Create an array with tank capacities from 'tanks' list
double[] tankCapacities = new double[tanks.Count];
for (int i = 0; i < tankCapacities.Length; i++) tankCapacities[i] = tanks[i].Capacity;
ControlBoard.InitializeEldeComponent(ctrlBrdComponent, valvesToInvert, tankCapacities);
}
else
{
throw new Exception("Control board component is missing");
}
}
public static string CurrentlyInitializedComponentName;
///
public static string InitializeComponents()
{
CurrentlyInitializedComponentName = "-";
bool anyComponentIsInSimulMode = false;
StringBuilder inSimulMode = new StringBuilder();
/// Add all devices to the state machine and initialize them
foreach (var cmpnt in components)
{
if (cmpnt.DebugLevel == DebugMode.Simulate)
{
inSimulMode.AppendFormat("{0}{1}", anyComponentIsInSimulMode ? ", " : "", cmpnt.Name);
anyComponentIsInSimulMode = true;
}
if (cmpnt is IDevice)
{
devices.Add(cmpnt as IDevice); /// Only components that were initialized are added
UiBridge.Bridge.OnActivity(null, cmpnt.Name); /// Info
}
CurrentlyInitializedComponentName = cmpnt.Name;
cmpnt.Initialize();
cmpnt.StartChangeHandler(); /// Start handling parameter change events
}
CurrentlyInitializedComponentName = "---";
///
/// (1) Propagate debug levels from parents to children when necessary
/// (2) Set drain valves DrainValve1, DrainValve2 and DrainValve3
///
foreach (var cmpnt in components)
{
if (cmpnt.Cfg is IChildComponentCfg && !string.IsNullOrEmpty(cmpnt.Cfg.ParentName) &&
(cmpnt.Cfg.DebugLevel == DebugMode.Inherit || cmpnt.Cfg.DebugLevel == DebugMode.AutoDetect))
{
foreach (var par in components)
{
if (par.Cfg.Name.Equals(cmpnt.Cfg.ParentName)) { cmpnt.Cfg.DebugLevel = par.Cfg.DebugLevel; break; }
}
}
if (cmpnt is IScaleOrTank)
{
IScaleOrTank tank = cmpnt as IScaleOrTank;
if (tank == Tank1 && DrainValve1 == null)
{
DrainValve1 = tank.DrainValve;
log.WarnFormat("InitializeComponents() ... Scale1={0} DrainValve1={1}",
tank.Name, (DrainValve1 != null) ? DrainValve1.Name : "---");
}
else if (tank == Tank2 && DrainValve2 == null)
{
DrainValve2 = tank.DrainValve;
log.WarnFormat("InitializeComponents() ... Scale2={0} DrainValve2={1}",
tank.Name, (DrainValve2 != null) ? DrainValve2.Name : "---");
}
else if (tank == Tank3 && DrainValve3 == null)
{
DrainValve3 = tank.DrainValve;
log.WarnFormat("InitializeComponents() ... Scale3={0} DrainValve3={1}",
tank.Name, (DrainValve3 != null) ? DrainValve3.Name : "---");
}
}
}
if (anyComponentIsInSimulMode)
return inSimulMode.ToString();
else
return null;
}
/// <summary>
/// Stop devices that were started by InitializeDevices().
/// Works correctly also after exeption from InitializeDevices() as only ...
/// ... correctly started devices were added in 'devices' list.
/// </summary>
public static void StopDevices()
{
for (int i = devices.Count - 1; i >= 0; i--)
{
var dev = devices[i];
UiBridge.Bridge.OnActivity(null, string.Format("1. {0}", dev.Name)); /// Info
dev.StopDevice();
}
}
/// <summary>
/// Stop devices that were started by InitializeDevices().
/// Works correctly also after exeption from InitializeDevices() as only ...
/// ... correctly started devices were added in 'devices' list.
/// </summary>
public static void StopDevices2()
{
for (int i = devices.Count - 1; i >= 0; i--)
{
var dev = devices[i];
UiBridge.Bridge.OnActivity(null, string.Format("2. {0}", dev.Name)); /// Info
dev.StopDevice2();
}
}
/// <summary>
/// Checks remote and local configuration DB paths and transitions for compatibility
/// </summary>
/// <returns>true when DB-s are compatible</returns>
public static bool IsRemoteDBCompatible(out string message)
{
IList<Config.Entities.FeedingPath> remoteFeedingPaths;
IList<Config.Entities.BenchPath> remoteBenchPaths;
IList<Config.Entities.OutputPath> remoteOutputPaths;
IList<Config.Entities.MetersPath> remoteMetersPaths;
IList<Config.Entities.TransitionSequence> remoteTransitions;
try
{
ISession remoteSession = TBF.DB.CreateSession(Common.DBKind.RemoteConfig);
remoteFeedingPaths = remoteSession.QueryOver<Config.Entities.FeedingPath>().List();
remoteBenchPaths = remoteSession.QueryOver<Config.Entities.BenchPath>().List();
remoteOutputPaths = remoteSession.QueryOver<Config.Entities.OutputPath>().List();
remoteMetersPaths = remoteSession.QueryOver<Config.Entities.MetersPath>().List();
remoteTransitions = remoteSession.QueryOver<Config.Entities.TransitionSequence>().List();
}
catch (Exception)
{
message = "Cannot open remote database";
return false;
}
ISession localSession = TBF.DB.CreateSession(Common.DBKind.Config);
var localFeedingPaths = localSession.QueryOver<Config.Entities.FeedingPath>().List();
var localBenchPaths = localSession.QueryOver<Config.Entities.BenchPath>().List();
var localOutputPaths = localSession.QueryOver<Config.Entities.OutputPath>().List();
var localMetersPaths = localSession.QueryOver<Config.Entities.MetersPath>().List();
var localTransitions = localSession.QueryOver<Config.Entities.TransitionSequence>().List();
string subMsg;
if (!IsCompatible(localFeedingPaths, remoteFeedingPaths, out subMsg))
{
message = string.Format("Feeding: {0}", subMsg);
return false;
}
if (!IsCompatible(localBenchPaths, remoteBenchPaths, out subMsg))
{
message = string.Format("Bench: {0}", subMsg);
return false;
}
if (!IsCompatible(localOutputPaths, remoteOutputPaths, out subMsg))
{
message = string.Format("Output: {0}", subMsg);
return false;
}
if (!IsCompatible(localMetersPaths, remoteMetersPaths, out subMsg))
{
message = string.Format("Sensors: {0}", subMsg);
return false;
}
if (!IsCompatible(localTransitions, remoteTransitions, out subMsg))
{
message = string.Format("Transitions: {0}", subMsg);
return false;
}
message = string.Empty;
return true;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T">FeedingPath, BenchPath, OutputPath, MetersPath or TransitionSequence</typeparam>
/// <param name="localList">Local list of paths or transitions</param>
/// <param name="remoteList">Remote list of paths or transitions</param>
/// <param name="message">Message specifying a cause of incompatibility</param>
/// <returns>true when lists are compatible, otherwise false</returns>
private static bool IsCompatible<T>(IList<T> localList, IList<T> remoteList, out string message)
{
message = "Local list is empty";
if ((localList == null) || (localList.Count == 0) || !(localList[0] is IHasName)) return false;
message = "Remote list is empty";
if ((remoteList == null) || (remoteList.Count == 0) || !(remoteList[0] is IHasName)) return false;
///
/// Each path or transition on a remote list must exist on a local list
///
foreach (var rItem in remoteList)
{
bool exists = false;
foreach (var lItem in localList)
{
if ((rItem as IHasName).Name == (lItem as IHasName).Name)
{
exists = true;
break;
}
}
if (!exists)
{
message = string.Format("Remote item {0} does not exist on a local list", (rItem as IHasName).Name);
return false;
}
}
message = string.Empty;
return true;
}
/// <summary>
/// Start the state machine
/// </summary>
public static void Start()
{
if (MachineState != MachineState.StartingUp)
{
/// Unexpected MachineState (not MachineState.StartingUp) --> prevent worker thread from starting
///
MachineState = MachineState.FailedToStart;
return;
}
workerThread = new Thread(Worker);
workerThread.CurrentCulture = Thread.CurrentThread.CurrentCulture;
workerThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
workerThread.Start();
}
/// <summary>
/// Loads all paths and transitions from the DB.
/// Updates StatMachine.feedingPaths ... StatMachine.meterPaths, StatMachine.TransitionSequences
/// </summary>
public static void LoadPathsAndTransitions(ISession session)
{
feedingPaths = session.QueryOver<Config.Entities.FeedingPath>().OrderBy(x => x.ItemNr).Asc.List();
benchPaths = session.QueryOver<Config.Entities.BenchPath>().OrderBy(x => x.ItemNr).Asc.List();
outputPaths = session.QueryOver<Config.Entities.OutputPath>().OrderBy(x => x.ItemNr).Asc.List();
metersPaths = session.QueryOver<Config.Entities.MetersPath>().OrderBy(x => x.ItemNr).Asc.List();
TransitionSequences = session.QueryOver<TransitionSequence>().OrderBy(x => x.ItemNr).Asc.List();
TransitionSteps = session.QueryOver<TransitionStep>().OrderBy(x => x.ItemNr).Asc.List();
#if HEAT_METERS
heatMetersPaths = session.QueryOver<Config.Entities.HeatMetersPath>().OrderBy(x => x.ItemNr).Asc.List();
#endif
}
/// <summary>
/// Loads selected procedure from the DB.
/// Updates StateMachine.Procedure and StateMachine.Tests
/// </summary>
public static bool LoadProcedure(ISession session, string procedureName, bool isRemote, IList<string> autoTests = null)
{
Procedure = null;
IList<Procedure> selectedProcs = session.QueryOver<Procedure>()
.Where(x => (x.ProcedureState == Common.ProcedureState.Active))
.And(x => (x.Name == procedureName))
.List();
if (selectedProcs.Count == 1)
{
IsRemoteProcedure = isRemote;
Procedure = selectedProcs[0];
TestInstances = selectedProcs[0].UpdateTestInstances(LoopStartNames, LoopEndNames, autoTests);
return true;
}
else
{
return false;
}
}
public static void LoadProcedureParams(Procedure procedure)
{
foreach (var cmpnt in components)
{
cmpnt.Cfg.LoadProcedureParamsFromDB(procedure);
}
}
public static void LoadTestParams(Test test)
{
foreach (var cmpnt in components)
{
cmpnt.Cfg.LoadTestParamsFromDB(test);
}
}
/// <summary>
/// Called from the sequence to update paths based on the selected test
/// </summary>
/// <param name="test">Selected test</param>
/// <param name="pfeed"></param>
/// <param name="pben"></param>
/// <param name="pout"></param>
/// <param name="pmtrs"></param>
/// <param name="transitionBefore">Transition sequence entity</param>
/// <param name="transitionAfter">Transition sequence entity</param>
/// <param name="errorMsg">Error message in case of incorrect configuration</param>
/// <returns>true when loaded configuration is correct (all four paths are defined !=null, etc.)</returns>
public static bool GetPaths(Test test,
bool heatMetersPathRequired,
out FeedingPath pfeed,
out BenchPath pben,
out OutputPath pout,
out MetersPath pmtrs,
out HeatMetersPath phmtrs,
out TransitionSequence transitionBefore,
out TransitionSequence transitionBetween,
out TransitionSequence transitionAfter,
out string errorMsg)
{
ITestMethod tm = TbfComponents.FindComponent(test.Method) as ITestMethod;
bool isHydroTest = (tm != null) ? tm.DoTransitions() : false;
pfeed = null;
pben = null;
pout = null;
phmtrs = null;
transitionBefore = null;
transitionBetween = null;
transitionAfter = null;
foreach (var path in feedingPaths)
{
if (test.FeedingPath == path.Name) { pfeed = new FeedingPath(path, components); break; }
}
foreach (var path in benchPaths)
{
if (test.BenchPath == path.Name) { pben = new BenchPath(path, components); break; }
}
foreach (var path in outputPaths)
{
if (test.OutputPath == path.Name) { pout = new OutputPath(path, components); break; }
}
pmtrs = GetMetersPath(test);
if (isHydroTest && (pfeed == null)) errorMsg = Strings.Cannot_load_feeding_path;
else if (isHydroTest && (pben == null)) errorMsg = Strings.Cannot_load_bench_path;
else if (isHydroTest && (pout == null)) errorMsg = Strings.Cannot_load_output_path;
else if (pmtrs == null) errorMsg = Strings.Cannot_load_sensor_path;
else errorMsg = string.Empty;
if ((isHydroTest && (pfeed == null || pben == null || pout == null)) || (pmtrs == null))
{
log.ErrorFormat("GetPaths({0},...) returns false, wrong configuration", test.Name);
return false;
}
#if HEAT_METERS
foreach (var path in heatMetersPaths)
{
if (test.HeatMetersPath == path.Name) { phmtrs = new HeatMetersPath(path, components); break; }
}
#endif
if (heatMetersPathRequired && phmtrs == null)
{
log.ErrorFormat("GetPaths({0},...) returns false, missing heat meters sensors", test.Name);
errorMsg = "Cannot load heat meters sensors";
return false;
}
foreach (var tr in TransitionSequences)
{
if (tr.Name == test.TransBefore) transitionBefore = tr;
if (tr.Name == test.TransBetween) transitionBetween = tr;
if (tr.Name == test.TransAfter) transitionAfter = tr;
}
if (isHydroTest && pout.Scale == null)
{
log.ErrorFormat("GetPaths({0},...) returns false, missing scales in output path {1}", test.Name, test.OutputPath);
errorMsg = string.Format("No balance specified in path {0}", test.OutputPath);
return false;
}
if (Config.Formulas.RealDensity() < 500.0f || Config.Formulas.RealDensity() > 2000.0f)
{
log.ErrorFormat("GetPaths({0},...) returns false, density was not specified", test.Name);
errorMsg = string.Format("Density was not specified");
return false;
}
log.WarnFormat("GetPaths({0},...) returns true, paths loaded OK, isHydroTest={1}", test.Name, isHydroTest);
errorMsg = string.Empty;
return true;
}
/// <summary>
/// Updates paths based on the selected test
/// </summary>
public static MetersPath GetMetersPath(Test test)
{
MetersPath pmtrs = null;
foreach (var path in metersPaths)
{
if (test.MetersPath == path.Name) { pmtrs = new MetersPath(path, components); break; }
}
if (pmtrs != null)
{
int count = Math.Min(TBF.Data.WMsCount, pmtrs.RegisterReaders.Length);
for (int i = 0; i < count; i++)
{
if ((pmtrs.RegisterReaders[i] != null) &&
(pmtrs.RegisterReaders[i].Cfg.DebugLevel == DebugMode.DetectedOff))
{
pmtrs.RegisterReaders[i] = null;
}
}
}
return pmtrs;
}
/*
* This is and example sequence of RunDeviceBefore() / RunOperations() / RunDeviceAfter() calls
* as they are executed during normal run from the progran start to the end.
*
foreach (var device in devices) device.RunDeviceBefore(); . . . . . . in StateMachine.Worker()
State.Create(...).AddOperation(...).AddOperation(...).EnterState() . . in the sequence in Execute(...)
foreach (var device in devices) device.RunDeviceAfter(); . . . . . . . in WaitRunDevsRunOps()
WaitNextTick() (may throw QuitStateMachineException) . . . . . . . . in WaitRunDevsRunOps()
foreach (var device in devices) device.RunDeviceBefore(); . . . . . . in WaitRunDevsRunOps()
IList<Event> events = State.RunOperations(); . . . . . . . . . . . . . in WaitRunDevsRunOps()
foreach (var device in devices) device.RunDeviceAfter(); . . . . . . . in WaitRunDevsRunOps()
WaitNextTick() (may throw QuitStateMachineException) . . . . . . . . in WaitRunDevsRunOps()
foreach (var device in devices) device.RunDeviceBefore(); . . . . . . in WaitRunDevsRunOps()
IList<Event> events = State.RunOperations(); . . . . . . . . . . . . . in WaitRunDevsRunOps()
State.Create(...).AddOperation(...).AddOperation(...).EnterState() . . in the sequence in Execute(...)
foreach (var device in devices) device.RunDeviceAfter(); . . . . . . . in WaitRunDevsRunOps()
WaitNextTick() (may throw QuitStateMachineException) . . . . . . . . in WaitRunDevsRunOps()
foreach (var device in devices) device.RunDeviceBefore(); . . . . . . in WaitRunDevsRunOps()
IList<Event> events = State.RunOperations(); . . . . . . . . . . . . . in WaitRunDevsRunOps()
foreach (var device in devices) device.RunDeviceAfter(); . . . . . . . in WaitRunDevsRunOps()
WaitNextTick() (assume QuitStateMachineException thrown) . . . . . . in WaitRunDevsRunOps()
State.StopOperations(); . . . . . . . . . . . . . . . . . . . . . . . in StateMachine.Worker() catch()
foreach (var device in devices) device.StopDevice(); . . . . . . . . . in StateMachine.Worker() catch()
*/
/// <summary>
/// Worker thread: calls Start(), Run() and Stop() methods of operations.
/// It uses 'currentState', 'nextState' and 'quitStateMachine' static fields.
/// </summary>
static void Worker()
{
MachineState = MachineState.Running;
startDateTime = DateTime.Now;
CycleStartTimeStamp = startDateTime; /// Do not leave CycleStartTimeStamp uninitialized
wlog.InfoFormat(" currentTime = {0}s startDateTime = {1}", currentTimeSec.ToString(), startDateTime.ToString());
/// Run all devices for the first time
foreach (var device in devices) device.RunDeviceBefore();
SequenceBase.ReferenceFlowmetersCount = SequenceBase.FlowMeters.Count;
SequenceBase.CalibratedLtrPerRefPulse = new double[SequenceBase.ReferenceFlowmetersCount];
foreach (var flowmtr in SequenceBase.FlowMeters)
{
int ix = flowmtr.Idx1;
if (ix > 0 && ix <= SequenceBase.ReferenceFlowmetersCount)
{
SequenceBase.CalibratedLtrPerRefPulse[ix - 1] = flowmtr.NominalFlow / 7200.0;
}
}
///
/// Run the main sequence
///
(new Sequences.MainSeq()).Execute();
StateMachine.MachineState = MachineState.Off; /// Update StateMachine.MachineState
TBF.UiBridge.Bridge.Bench2UI(TBF.UiBridge.ButtonsEtc.Shutdown); /// Let UI know the state machine is shut down now
}
/// <summary>
/// Do stuff that is repeated in the state execution loops most often
/// </summary>
/// <returns>List of Event-s returned from the state operations, null == quit</returns>
public static IList<Event> WaitRunDevsRunOps(bool lastTime = false)
{
Thread.Sleep(100); /// Insert 1/10 sec.delay between RunOperations() and RunDeviceAfter()
for (int i = devices.Count - 1; i >= 0; i-- )
{
devices[i].RunDeviceAfter();
}
WaitNextTick();
if (lastTime)
{
///
/// Executed when the state machine is being stopped
///
State.StopOperations();
return null;
}
foreach (var device in devices)
{
device.RunDeviceBefore();
}
Thread.Sleep(100); /// Insert 1/10 sec.delay between RunDeviceBefore() and RunOperations()
return State.RunOperations(); /// Returns events from all running operations
/// This is followed by a state change in the sequence
}
/// <summary>
/// Wait time period - synchronize
/// </summary>
/// <returns>true when interrupted by 'quitStateMachine', otherwise false</returns>
public static void WaitNextTick()
{
int currentTimeSecFromClock = Convert.ToInt32(Math.Round((DateTime.Now - startDateTime).TotalSeconds - 0.2));
currentTimeSec = Math.Max(currentTimeSec, currentTimeSecFromClock) + Period;
DateTime nextTickDateTime = startDateTime + TimeSpan.FromSeconds(currentTimeSec);
while (DateTime.Now < nextTickDateTime)
{
Thread.Sleep(100);
}
}
}
}

View File

@ -14,12 +14,15 @@ namespace TBF.Rig.DataContainers.BenchInfo.Extended
/// <summary>
/// Holds information identifying the test bench - serializable configuration.
/// </summary>
public class ComponentCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider
public class ComponentCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ComponentCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
{
return new Configs.ParamsProvider.ComponentCfgCtrl(this, null);
}
///
/// Serialized parameters
@ -151,11 +154,6 @@ namespace TBF.Rig.DataContainers.BenchInfo.Extended
public string ToString(int i)
{
if (i == -1)
{
return string.Format("{0}: Bench name={1}, Bench Id={2}, Procedures={3}", Name, TestBenchName, TestBenchId, RemoteDBUse.ToDescription());
}
switch (i)
{
case 0: return TestBenchName;
@ -175,7 +173,8 @@ namespace TBF.Rig.DataContainers.BenchInfo.Extended
case 14: return TempUnit.ToDescription();
case 15: return PressUnit.ToDescription();
case 16: return LenghtUnit.ToDescription();
default: return string.Empty;
default:
return string.Format("{0}: Bench name={1}, Bench Id={2}, Procedures={3}", Name, TestBenchName, TestBenchId, RemoteDBUse.ToDescription());
}
}

View File

@ -1,7 +1,7 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
partial class CycleBeginningForm
{
@ -134,6 +134,10 @@ namespace TBF.Rig.DataEntry.Fewa
this.suffixComboBox15 = new System.Windows.Forms.ComboBox();
this.suffixComboBox14 = new System.Windows.Forms.ComboBox();
this.suffixComboBox13 = new System.Windows.Forms.ComboBox();
this.snLabel = new System.Windows.Forms.Label();
this.snLabel2 = new System.Windows.Forms.Label();
this.column2Label = new System.Windows.Forms.Label();
this.columnm2Label2 = new System.Windows.Forms.Label();
this.orderGroupBox.SuspendLayout();
this.prefixGroupBox.SuspendLayout();
this.SuspendLayout();
@ -877,11 +881,35 @@ namespace TBF.Rig.DataEntry.Fewa
this.suffixComboBox13.TextChanged += new System.EventHandler(this.suffixComboBox13_TextChanged);
this.suffixComboBox13.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.suffixComboBox13_KeyPress);
//
// snLabel
//
resources.ApplyResources(this.snLabel, "snLabel");
this.snLabel.Name = "snLabel";
//
// snLabel2
//
resources.ApplyResources(this.snLabel2, "snLabel2");
this.snLabel2.Name = "snLabel2";
//
// column2Label
//
resources.ApplyResources(this.column2Label, "column2Label");
this.column2Label.Name = "column2Label";
//
// columnm2Label2
//
resources.ApplyResources(this.columnm2Label2, "columnm2Label2");
this.columnm2Label2.Name = "columnm2Label2";
//
// CycleBeginningForm
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.DarkGray;
this.Controls.Add(this.columnm2Label2);
this.Controls.Add(this.column2Label);
this.Controls.Add(this.snLabel2);
this.Controls.Add(this.snLabel);
this.Controls.Add(this.suffixComboBox24);
this.Controls.Add(this.suffixComboBox23);
this.Controls.Add(this.suffixComboBox22);
@ -1098,5 +1126,9 @@ namespace TBF.Rig.DataEntry.Fewa
private System.Windows.Forms.ComboBox suffixComboBox15;
private System.Windows.Forms.ComboBox suffixComboBox14;
private System.Windows.Forms.ComboBox suffixComboBox13;
private System.Windows.Forms.Label snLabel;
private System.Windows.Forms.Label snLabel2;
private System.Windows.Forms.Label column2Label;
private System.Windows.Forms.Label columnm2Label2;
}
}

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@ -7,7 +7,7 @@ using System.Windows.Forms;
using log4net;
using TBF.Resources;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public partial class CycleBeginningForm : Form, GenericDevices.IHasCompleted
{
@ -15,12 +15,14 @@ namespace TBF.Rig.DataEntry.Fewa
/// <summary> Number of water meters </summary>
public readonly int WMsCount;
readonly EntryFormCfg entryFormCfg;
/// To be retrieved after the form is closed
public string PurchaseOrder;
public string Prefix;
public string[] SNText;
public string[] SN2Text;
string[] suffixText;
public string[] Column2Text;
public string[] suffixText;
public bool[] Disabled;
/// Set to 'true' when the form closes
@ -31,7 +33,7 @@ namespace TBF.Rig.DataEntry.Fewa
int textBoxesCount;
Label[] labels;
ComboBox[] comboBoxes;
ComboBox[] suffixComboBoxes;
ComboBox[] column2ComboBoxes;
CheckBox[] checkBoxes;
IList<ComboBox> enabledComboBoxes;
@ -56,7 +58,7 @@ namespace TBF.Rig.DataEntry.Fewa
comboBox13, comboBox14, comboBox15, comboBox16, comboBox17, comboBox18,
comboBox19, comboBox20, comboBox21, comboBox22, comboBox23, comboBox24,
};
suffixComboBoxes = new ComboBox[]
column2ComboBoxes = new ComboBox[]
{
suffixComboBox1, suffixComboBox2, suffixComboBox3, suffixComboBox4, suffixComboBox5, suffixComboBox6,
suffixComboBox7, suffixComboBox8, suffixComboBox9, suffixComboBox10, suffixComboBox11, suffixComboBox12,
@ -80,15 +82,27 @@ namespace TBF.Rig.DataEntry.Fewa
/// Constructor
/// </summary>
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
public CycleBeginningForm(int waterMetersCount)
public CycleBeginningForm(int waterMetersCount, EntryFormCfg entryFormCfg)
: this()
{
this.WMsCount = waterMetersCount;
this.entryFormCfg = entryFormCfg;
SNText = new string[WMsCount];
SN2Text = new string[WMsCount];
Column2Text = new string[WMsCount];
suffixText = new string[WMsCount];
Disabled = new bool[WMsCount];
if (entryFormCfg.HideOrderSelection)
orderGroupBox.Visible = false;
else
PrepareOrderCombo(orderComboBox);
if (entryFormCfg.HidePrefix)
prefixGroupBox.Visible = false;
else
PreparePrefixCombo(prefixComboBox);
ShuffleTextBoxes(TBF.Data.WMsCount, TBF.Data.LineSize);
//Height = 147 + WaterMetersCount * 90;
@ -114,7 +128,7 @@ namespace TBF.Rig.DataEntry.Fewa
{
labels[dest] = labels[l * lineSize + l * gap + i];
comboBoxes[dest] = comboBoxes[l * lineSize + l * gap + i];
suffixComboBoxes[dest] = suffixComboBoxes[l * lineSize + l * gap + i];
column2ComboBoxes[dest] = column2ComboBoxes[l * lineSize + l * gap + i];
checkBoxes[dest] = checkBoxes[l * lineSize + l * gap + i];
dest++;
}
@ -127,21 +141,18 @@ namespace TBF.Rig.DataEntry.Fewa
{
Localize();
PrepareOrderCombo(orderComboBox);
PreparePrefixCombo(prefixComboBox);
for (int i = 0; i < textBoxesCount; i++)
{
if (Program.LocalSettings.LastSNTextsCount == textBoxesCount)
{
comboBoxes[i].Items.Add((Program.LocalSettings.LastSNTexts[i] == null) ? string.Empty : Program.LocalSettings.LastSNTexts[i]);
suffixComboBoxes[i].Items.Add((Program.LocalSettings.LastAuxSNTexts[i] == null) ? string.Empty : Program.LocalSettings.LastAuxSNTexts[i]);
column2ComboBoxes[i].Items.Add((Program.LocalSettings.LastAuxSNTexts[i] == null) ? string.Empty : Program.LocalSettings.LastAuxSNTexts[i]);
}
labels[i].Visible = comboBoxes[i].Visible = suffixComboBoxes[i].Visible = checkBoxes[i].Visible = true;
labels[i].Visible = comboBoxes[i].Visible = column2ComboBoxes[i].Visible = checkBoxes[i].Visible = true;
enabledComboBoxes.Add(comboBoxes[i]);
enabledComboBoxes.Add(suffixComboBoxes[i]);
enabledComboBoxes.Add(column2ComboBoxes[i]);
}
}
@ -149,12 +160,11 @@ namespace TBF.Rig.DataEntry.Fewa
{
Text = Strings.Data;
orderGroupBox.Text = Strings.Purchase_order;
for (int i = 0; i < textBoxesCount; i++)
{
labels[i].Text = Strings.Serial_Number + " " + (i + 1).ToString();
}
for (int i = 0; i < textBoxesCount; i++) labels[i].Text = (i + 1).ToString();
okButton.Text = Strings.OkBtnText;
clearButton.Text = Strings.ClearBtnText;
column2Label.Text = columnm2Label2.Text = entryFormCfg.Column2Caption;
}
/// <summary>
@ -190,12 +200,13 @@ namespace TBF.Rig.DataEntry.Fewa
for (int i = 0; i < Math.Min(WMsCount, textBoxesCount); i++)
{
SNText[i] = comboBoxes[i].Text;
suffixText[i] = suffixComboBoxes[i].Text;
SN2Text[i] = string.Format("{0}{1}", prefixComboBox.Text, suffixComboBoxes[i].Text);
suffixText[i] = column2ComboBoxes[i].Text;
Column2Text[i] = string.Format("{0}{1}", prefixComboBox.Text, column2ComboBoxes[i].Text);
Disabled[i] = !checkBoxes[i].Checked;
}
PurchaseOrder = orderComboBox.Text;
PurchaseOrder = entryFormCfg.HideOrderSelection ? string.Empty : orderComboBox.Text;
Prefix = entryFormCfg.HidePrefix ? string.Empty : prefixComboBox.Text;
Program.LocalSettings.UpdateHistory(orderComboBox.Text, ref Program.LocalSettings.PurchaseOrderHistory);
Program.LocalSettings.UpdateHistory(prefixComboBox.Text, ref Program.LocalSettings.PrefixHistory);
Program.LocalSettings.LastSNTexts = SNText;
@ -273,8 +284,8 @@ namespace TBF.Rig.DataEntry.Fewa
for (int i = 0; i < Math.Min(WMsCount, textBoxesCount); i++)
{
if (Program.LocalSettings.LastSNTextsCount > i) comboBoxes[i].Text = Program.LocalSettings.LastSNTexts[i];
if (Program.LocalSettings.LastAuxSNTextsCount > i) suffixComboBoxes[i].Text = Program.LocalSettings.LastAuxSNTexts[i];
checkBoxes[i].Checked = !string.IsNullOrEmpty(comboBoxes[i].Text) || !string.IsNullOrEmpty(suffixComboBoxes[i].Text);
if (Program.LocalSettings.LastAuxSNTextsCount > i) column2ComboBoxes[i].Text = Program.LocalSettings.LastAuxSNTexts[i];
checkBoxes[i].Checked = !string.IsNullOrEmpty(comboBoxes[i].Text) || !string.IsNullOrEmpty(column2ComboBoxes[i].Text);
}
}

View File

@ -1,7 +1,7 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
partial class CycleEndForm
{

View File

@ -1,12 +1,12 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using log4net;
using TBF.Resources;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public partial class CycleEndForm : Form, GenericDevices.IHasCompleted
{

View File

@ -1,9 +1,9 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using TBF.Rig.GenericDevices;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public class EntryForm : EntryFormNoStartEnd, IHasWMStatesForm
{

View File

@ -0,0 +1,206 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Common;
using Config;
using Config.Entities;
using TBF.Resources;
using TBF.Rig.Generic;
namespace TBF.Rig.DataEntry.Double24
{
public class EntryFormCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(EntryFormCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
{
return new Configs.ParamsProvider.ComponentCfgCtrl(this, null);
}
///
/// Serialized parameters
///
public bool EnterSerialNrsAtTheEnd;
public bool ShowCycleEndForm;
public bool HideOrderSelection;
public bool HidePrefix;
public string Column2Caption;
public Col2Dest Column2Destination;
/// Private parameterless constructor invoked by all other (public) constructors
EntryFormCfg() { }
public EntryFormCfg(IComponentFactory factory, string name)
: this()
{
this.Factory = factory;
this.Name = name;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
EnterSerialNrsAtTheEnd = false;
ShowCycleEndForm = false;
HideOrderSelection = false;
HidePrefix = true;
Column2Caption = "Radio address";
Column2Destination = Col2Dest.RadioAddress;
}
string[] paramNames = new string[]
{
Strings.Enter_SNs_at_the_end,
Strings.Show_cycle_end_form,
"Hide order selection",
"Hide prefix selection",
"Column 2 caption",
"Column 2 destination",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
var list = new List<string>();
switch (i)
{
case 0:
case 1:
case 2:
case 3:
return new string[] { Strings.yes, Strings.no };
case 4:
return null;
case 5:
for (Col2Dest c2d = 0; c2d < Col2Dest.Count; c2d++) list.Add(c2d.ToDescription());
return list;
default:
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case 0:
return EnterSerialNrsAtTheEnd ? Strings.yes : Strings.no;
case 1:
return ShowCycleEndForm ? Strings.yes : Strings.no;
case 2:
return HideOrderSelection ? Strings.yes : Strings.no;
case 3:
return HidePrefix ? Strings.yes : Strings.no;
case 4:
return Column2Caption;
case 5:
return Column2Destination.ToDescription();
default:
return string.Format("Name={0}, Enter SNs at the end={1}, Show cycle end form={2}", Name, EnterSerialNrsAtTheEnd, ShowCycleEndForm);
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0:
EnterSerialNrsAtTheEnd = (str == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
case 1:
ShowCycleEndForm = (str == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
case 2:
HideOrderSelection = (str == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
case 3:
HidePrefix = (str == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
case 4:
Column2Caption = str;
return CfgUpdateFlags.RestartRqrd;
case 5:
for (Col2Dest c2d = 0; c2d < Col2Dest.Count; c2d++)
{
if (str == c2d.ToDescription())
{
Column2Destination = c2d;
return CfgUpdateFlags.RestartRqrd;
}
}
return CfgUpdateFlags.None;
default:
return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string str, out string message)
{
switch (i)
{
case 0:
case 1:
case 2:
case 3:
case 5:
message = string.Empty;
if (ParamValues(i).Contains(str)) return true;
break;
case 4:
message = string.Empty;
return true;
default:
message = "Invalid index";
return false;
}
message = string.Format(Strings.Invalid_0, ParamName(i)) ;
return false;
}
void CopyContentTo(EntryFormCfg prms)
{
prms.EnterSerialNrsAtTheEnd = EnterSerialNrsAtTheEnd;
prms.ShowCycleEndForm = ShowCycleEndForm;
prms.HideOrderSelection = HideOrderSelection;
prms.HidePrefix = HidePrefix;
prms.Column2Caption = Column2Caption;
prms.Column2Destination = Column2Destination;
}
public Config.Entities.IParamsProvider Clone()
{
EntryFormCfg pars = new EntryFormCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
public enum Col2Dest
{
[Description("Radio address")] RadioAddress,
[Description("Serial nr. Aux")] SerialNrAux,
[Description("Purchase order")] OrderNr,
[Description("Remark")] Remark,
#if ORACLE_DB
[Description("Suffix")] Suffix,
#endif
Count
}
}

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@ -8,7 +8,7 @@ using Config.Entities;
using TBF.Rig;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public class EntryFormNoStartEnd : ComponentBase, IOperation, IDataEntry, IHasCycleBeginForm, IHasCycleEndForm
{
@ -123,7 +123,7 @@ namespace TBF.Rig.DataEntry.Fewa
///
void OpenBeginningDlg(EntryFormNoStartEnd myRef)
{
myRef.modelessDlg = new CycleBeginningForm(TBF.Data.WMsCount);
myRef.modelessDlg = new CycleBeginningForm(TBF.Data.WMsCount, entryFormCfg);
modelessDlg.Show();
}
///
@ -199,8 +199,39 @@ namespace TBF.Rig.DataEntry.Fewa
{
waterMeters[i].Disabled = disabled[i] = dlg.Disabled[i];
waterMeters[i].SerialNr = dlg.SNText[i];
waterMeters[i].SerialNrAux = dlg.SN2Text[i];
if (dlg.PurchaseOrder != null) waterMeters[i].PurchaseOrder = dlg.PurchaseOrder;
switch (entryFormCfg.Column2Destination)
{
case Col2Dest.RadioAddress:
waterMeters[i].RadioAddress = dlg.Column2Text[i];
break;
case Col2Dest.SerialNrAux:
waterMeters[i].SerialNrAux = dlg.Column2Text[i];
break;
case Col2Dest.OrderNr:
waterMeters[i].PurchaseOrder = dlg.Column2Text[i];
break;
#if ORACLE_DB
case Col2Dest.Suffix:
waterMeters[i].Suffix = dlg.Column2Text[i];
break;
#endif
default:
case Col2Dest.Remark:
waterMeters[i].Remark = dlg.Column2Text[i];
break;
}
if (!string.IsNullOrEmpty(dlg.PurchaseOrder) && !entryFormCfg.HideOrderSelection)
{
waterMeters[i].PurchaseOrder = dlg.PurchaseOrder;
}
#if ORACLE_DB
if (!string.IsNullOrEmpty(dlg.Prefix) && !entryFormCfg.HidePrefix)
{
waterMeters[i].Prefix = dlg.PurchaseOrder;
}
#endif
}
}
}

View File

@ -1,20 +1,20 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public class Factory : IComponentFactory
{
public string ClassName { get { return "DataEntry.Fewa"; } }
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public IComponent DummyComponent() { return new EntryFormNoStartEnd(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new EntryForm(cfg); }
public IComponentCfg DefaultConfig() { return new EntryFormCfg(this); }
public IComponentCfg DefaultConfig() { return new EntryFormCfg(this, GetType().Namespace.Substring(8)); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{

View File

@ -1,20 +1,20 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public class FactoryNoStartEnd : IComponentFactory
{
public string ClassName { get { return "DataEntry.Fewa.NoStartEnd"; } }
public string ClassName { get { return GetType().Namespace.Substring(8) + "-NoStartEnd"; } }
public IComponent DummyComponent() { return new EntryFormNoStartEnd(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new EntryFormNoStartEnd(cfg); }
public IComponentCfg DefaultConfig() { return new EntryFormCfg(this); }
public IComponentCfg DefaultConfig() { return new EntryFormCfg(this, GetType().Namespace.Substring(8) + "-NoStartEnd"); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@ -8,7 +8,7 @@ using log4net;
using TBF.Rig.GenericDevices;
using TBF.Resources;
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
public partial class TestStartEndForm : Form, GenericDevices.IHasCompleted
{

View File

@ -1,7 +1,7 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
namespace TBF.Rig.DataEntry.Fewa
namespace TBF.Rig.DataEntry.Double24
{
partial class TestStartEndForm
{

View File

@ -1,45 +0,0 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.DataEntry.Fewa
{
public class EntryFormCfg : ComponentCfgBase, Generic.IComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(EntryFormCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new EntryFormCfgCtrl(); }
///
/// Serialized parameters
///
public bool EnterSerialNrsAtTheEnd;
public bool ShowCycleEndForm;
/// Private parameterless constructor invoked by all other (public) constructors
EntryFormCfg()
{
Name = "DataEntry-FEWA";
ParentName = string.Empty;
EnterSerialNrsAtTheEnd = false;
ShowCycleEndForm = false;
}
public EntryFormCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, EnterSNsAtTheEnd={1}, ShowEndForm={2}", Name, EnterSerialNrsAtTheEnd, ShowCycleEndForm);
}
}
}

View File

@ -1,84 +0,0 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Resources;
namespace TBF.Rig.DataEntry.Fewa
{
public partial class EntryFormCfgCtrl : UserControl, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
EntryFormCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as EntryFormCfg;
Redraw();
}
}
public EntryFormCfgCtrl()
{
InitializeComponent();
}
private void EntryFormCfgCtrl_Load(object sender, EventArgs e)
{
Localize();
Redraw();
}
void Localize()
{
enterSNsAtTheEndCheckBox.Text = Strings.Enter_SNs_at_the_end;
showEndStateFormCheckBox.Text = Strings.Show_cycle_end_form;
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
enterSNsAtTheEndCheckBox.Checked = config.EnterSerialNrsAtTheEnd;
showEndStateFormCheckBox.Checked = config.ShowCycleEndForm;
}
public void Unlock()
{
nameTextBox.Enabled = true;
enterSNsAtTheEndCheckBox.Enabled = true;
showEndStateFormCheckBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.EnterSerialNrsAtTheEnd = enterSNsAtTheEndCheckBox.Checked;
config.ShowCycleEndForm = showEndStateFormCheckBox.Checked;
return flags;
}
}
}

View File

@ -1,114 +0,0 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
namespace TBF.Rig.DataEntry.Fewa
{
partial class EntryFormCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.showEndStateFormCheckBox = new System.Windows.Forms.CheckBox();
this.enterSNsAtTheEndCheckBox = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(99, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(35, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(96, 33);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// showEndStateFormCheckBox
//
this.showEndStateFormCheckBox.AutoSize = true;
this.showEndStateFormCheckBox.Enabled = false;
this.showEndStateFormCheckBox.Location = new System.Drawing.Point(99, 112);
this.showEndStateFormCheckBox.Name = "showEndStateFormCheckBox";
this.showEndStateFormCheckBox.Size = new System.Drawing.Size(151, 17);
this.showEndStateFormCheckBox.TabIndex = 4;
this.showEndStateFormCheckBox.Text = "Watermeter end state form";
this.showEndStateFormCheckBox.UseVisualStyleBackColor = true;
//
// enterSNsAtTheEndCheckBox
//
this.enterSNsAtTheEndCheckBox.AutoSize = true;
this.enterSNsAtTheEndCheckBox.Enabled = false;
this.enterSNsAtTheEndCheckBox.Location = new System.Drawing.Point(99, 89);
this.enterSNsAtTheEndCheckBox.Name = "enterSNsAtTheEndCheckBox";
this.enterSNsAtTheEndCheckBox.Size = new System.Drawing.Size(167, 17);
this.enterSNsAtTheEndCheckBox.TabIndex = 3;
this.enterSNsAtTheEndCheckBox.Text = "Enter serial number at the end";
this.enterSNsAtTheEndCheckBox.UseVisualStyleBackColor = true;
//
// EntryFormCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.enterSNsAtTheEndCheckBox);
this.Controls.Add(this.showEndStateFormCheckBox);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "EntryFormCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.CheckBox showEndStateFormCheckBox;
private System.Windows.Forms.CheckBox enterSNsAtTheEndCheckBox;
}
}

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -25,8 +25,8 @@ namespace TBF.Rig
Factories.Add(new Elde.CoverTest.Factory());
Factories.Add(new DataEntry.Combined.EntryFormFactory());
Factories.Add(new DataEntry.DataStream.Factory());
Factories.Add(new DataEntry.Fewa.Factory());
Factories.Add(new DataEntry.Fewa.FactoryNoStartEnd());
Factories.Add(new DataEntry.Double24.Factory());
Factories.Add(new DataEntry.Double24.FactoryNoStartEnd());
Factories.Add(new DataEntry.HeatMeters6.Factory());
Factories.Add(new DataEntry.HeatMeters12.Factory());
Factories.Add(new DataEntry.Munich3.EntryFormFactory());

View File

@ -241,33 +241,27 @@
<Compile Include="Rig\DataEntry\DataStream\TestStartEndForm.designer.cs">
<DependentUpon>TestStartEndForm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\CycleBeginningForm.cs">
<Compile Include="Rig\DataEntry\Double24\CycleBeginningForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\CycleBeginningForm.designer.cs">
<Compile Include="Rig\DataEntry\Double24\CycleBeginningForm.designer.cs">
<DependentUpon>CycleBeginningForm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\CycleEndForm.cs">
<Compile Include="Rig\DataEntry\Double24\CycleEndForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\CycleEndForm.designer.cs">
<Compile Include="Rig\DataEntry\Double24\CycleEndForm.designer.cs">
<DependentUpon>CycleEndForm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\EntryForm.cs" />
<Compile Include="Rig\DataEntry\Fewa\EntryFormCfg.cs" />
<Compile Include="Rig\DataEntry\Fewa\EntryFormCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\EntryFormCfgCtrl.designer.cs">
<DependentUpon>EntryFormCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\EntryFormNoStartEnd.cs" />
<Compile Include="Rig\DataEntry\Fewa\Factory.cs" />
<Compile Include="Rig\DataEntry\Fewa\FactoryNoStartEnd.cs" />
<Compile Include="Rig\DataEntry\Fewa\TestStartEndForm.cs">
<Compile Include="Rig\DataEntry\Double24\EntryForm.cs" />
<Compile Include="Rig\DataEntry\Double24\EntryFormCfg.cs" />
<Compile Include="Rig\DataEntry\Double24\EntryFormNoStartEnd.cs" />
<Compile Include="Rig\DataEntry\Double24\Factory.cs" />
<Compile Include="Rig\DataEntry\Double24\FactoryNoStartEnd.cs" />
<Compile Include="Rig\DataEntry\Double24\TestStartEndForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\DataEntry\Fewa\TestStartEndForm.designer.cs">
<Compile Include="Rig\DataEntry\Double24\TestStartEndForm.designer.cs">
<DependentUpon>TestStartEndForm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\DataEntry\HeatMeters12\CycleBeginningForm.cs">
@ -2772,16 +2766,13 @@
<EmbeddedResource Include="Rig\DataEntry\DataStream\TestStartEndForm.resx">
<DependentUpon>TestStartEndForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\DataEntry\Fewa\CycleBeginningForm.resx">
<EmbeddedResource Include="Rig\DataEntry\Double24\CycleBeginningForm.resx">
<DependentUpon>CycleBeginningForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\DataEntry\Fewa\CycleEndForm.resx">
<EmbeddedResource Include="Rig\DataEntry\Double24\CycleEndForm.resx">
<DependentUpon>CycleEndForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\DataEntry\Fewa\EntryFormCfgCtrl.resx">
<DependentUpon>EntryFormCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\DataEntry\Fewa\TestStartEndForm.resx">
<EmbeddedResource Include="Rig\DataEntry\Double24\TestStartEndForm.resx">
<DependentUpon>TestStartEndForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\DataEntry\HeatMeters12\CycleBeginningForm.pl.resx">