Merge branch 'master-2-26-Flex' into master-2-26

This commit is contained in:
Milan Hanajik 2021-10-01 10:03:39 +02:00
commit a203885c16
10 changed files with 823 additions and 502 deletions

View File

@ -4,7 +4,7 @@
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Output.FlexFlow.Rest
namespace TBF.BenchControl.Output.FlexFlow
{
public class Factory : IComponentFactory
{

View File

@ -0,0 +1,566 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using log4net;
using Config.Entities;
using System.Text;
namespace TBF.BenchControl.Output.FlexFlow
{
public class FlexFlow : ComponentBase, IOperation, GenericDevices.IResultsWriter, GenericDevices.IStartInfoReader, Generic.IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(FlexFlow));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
FlexFlowCfg flexFlowCfg;
public string StationName
{
get
{
var benchInfo = TBF.BenchControl.Sequences.ProcessData.BenchInfo;
return (benchInfo != null) ? benchInfo.TestBenchName : "TestBench";
}
}
public string UserId { get { return Users.GlobalData.GetCurrentUserName(); } }
enum Retv
{
OK,
Error,
}
enum OpState
{
None,
GetUnitInfosScheduled,
GetUnitInfosRunning,
SaveResultsScheduled,
SaveResultsRunning,
}
///
OpState currentOpState;
bool opCompleted;
bool anyError;
/// <summary>
/// Watermeters to check at the beginning of the cycle
/// </summary>
IList<Results.Entities.WaterMeter> waterMeters;
/// <summary>
/// Data (tracing records) to write at the end of cycle
/// </summary>
Results.Entities.Batch batch;
DateTime resultsTimeStamp;
string resultsTimeStampStr;
public FlexFlow() {}
public FlexFlow(Generic.IComponentCfg cfg)
: base(cfg)
{
flexFlowCfg = cfg as FlexFlowCfg;
}
public override void Initialize()
{
currentOpState = OpState.None;
resultsTimeStampStr = string.Empty;
if (flexFlowCfg.DebugLevel == DebugMode.Normal)
{
/// TODO: Initialize FlexFlow
log.FatalFormat("{0} initialized: {1}", Name, this);
}
else
{
log.FatalFormat("{0} simulated: {1}", Name, this);
}
}
///
/// IDevice interface implementation
///
public void RunDeviceBefore() { }
public void RunDeviceAfter() { }
///
public void StopDevice()
{
if (flexFlowCfg.DebugLevel != DebugMode.Normal) return;
/// TODO: Close FlexFlow
}
public void StopDevice2() {}
/// <summary>
/// Reads information on start of a cycle, Events: Event.InfoRead
/// </summary>
/// <param name="waterMeters">Results of water meters</param>
/// <returns>Reference to the operation</returns>
public IOperation ReadStartInfoOp(IList<Results.Entities.WaterMeter> waterMeters)
{
if (!flexFlowCfg.CheckPreviousRecords)
{
return null;
}
else if ((currentOpState == OpState.GetUnitInfosRunning) || (currentOpState == OpState.SaveResultsRunning))
{
throw new Exception("Sequence error");
}
else
{
this.waterMeters = waterMeters;
currentOpState = OpState.GetUnitInfosScheduled;
return this;
}
}
/// <summary>
/// Writes the test cycle results into a file, Events: Event.ResultsWritten
/// </summary>
/// <param name="procedure">Procedure to print the results of</param>
/// <param name="unsortedResults">Results to write into the file</param>
/// <returns>Reference to the operation</returns>
public IOperation ProcessResultsOp(Results.Entities.Batch batch)
{
if (!flexFlowCfg.SaveResults)
{
log.WarnFormat("{0} saving results disabled", Name);
return null;
}
else if ((currentOpState == OpState.GetUnitInfosRunning) || (currentOpState == OpState.SaveResultsRunning))
{
log.WarnFormat("{0} sequence error", Name);
throw new Exception("Sequence error");
}
else
{
this.batch = batch;
this.resultsTimeStamp = batch.EndTime;
this.resultsTimeStampStr = batch.EndTime.ToString("yyyy-MM-dd HH:mm:ss");
currentOpState = OpState.SaveResultsScheduled;
return this;
}
}
/// <summary>Start this operation</summary>
public void Start()
{
var oriOpState = currentOpState;
if (currentOpState == OpState.GetUnitInfosScheduled)
{
currentOpState = OpState.GetUnitInfosRunning;
}
else if (currentOpState == OpState.SaveResultsScheduled)
{
currentOpState = OpState.SaveResultsRunning;
}
opCompleted = false;
anyError = false;
log.WarnFormat("{0} Start() completed, op.state {1} --> {2}", Name, oriOpState, currentOpState);
}
/// <summary>Run this operation</summary>
/// <returns>Event.ResultsWritten or Event.Error</returns>
public Event Run()
{
var oriOpState = currentOpState;
if (currentOpState == OpState.GetUnitInfosRunning)
{
if (flexFlowCfg.DebugLevel == DebugMode.Simulate)
{
return Event.InfoRead;
}
else if (!opCompleted)
{
log.WarnFormat("{0} : Run() : currentOp = {1}", Name, currentOpState);
opCompleted = true;
if (GetUnitInfos(waterMeters) != Retv.OK)
{
anyError = true;
}
var retval = anyError ? Event.InfoNotRead : Event.InfoRead;
log.WarnFormat("{0} Run() returned {1}, op.state {2} --> {3}", Name, retval, oriOpState, currentOpState);
return retval;
}
else
{
var retval = anyError ? Event.InfoNotRead : Event.InfoRead;
log.WarnFormat("{0} Run() returned {1}, op.state {2} --> {3}", Name, retval, oriOpState, currentOpState);
return retval;
}
}
else if (currentOpState == OpState.SaveResultsRunning)
{
if (flexFlowCfg.DebugLevel == DebugMode.Simulate || batch.WaterMeters.Count == 0)
{
return Event.ResultsWritten;
}
else if (!opCompleted)
{
opCompleted = true;
if (SaveResults(batch) != Retv.OK)
{
anyError = true;
}
var retval = anyError ? Event.ErrorProcessingResults : Event.ResultsWritten;
log.WarnFormat("{0} Run() returned {1}, op.state {2} --> {3}", Name, retval, oriOpState, currentOpState);
return retval;
}
else
{
var retval = anyError ? Event.ErrorProcessingResults : Event.ResultsWritten;
log.WarnFormat("{0} Run() returned {1}, op.state {2} --> {3}", Name, retval, oriOpState, currentOpState);
return retval;
}
}
else
{
log.WarnFormat("{0} Run() returned {1}, op.state {2} --> {3}", Name, Event.None, oriOpState, currentOpState);
return Event.None;
}
}
/// <summary>Stop this operation</summary>
public void Stop()
{
var oriOpState = currentOpState;
currentOpState = OpState.None;
log.WarnFormat("{0} Stop() completed, op.state {1} --> {2}", Name, oriOpState, currentOpState);
}
Retv GetUnitInfos(IList<Results.Entities.WaterMeter> waterMeters)
{
bool allOK = true;
foreach (var wm in waterMeters)
{
if (wm != null && !wm.Disabled)
{
GetOneUnitInfo(wm, (flexFlowCfg.GetUnitInfoApi == WebApi.REST));
if (wm.LastRecordIsNok)
{
allOK = false;
}
}
}
return allOK ? Retv.OK : Retv.Error;
}
Retv GetOneUnitInfo(Results.Entities.WaterMeter wm, bool isRest)
{
string serviceName = isRest ? "GetUnitInfo REST" : "GetUnitInfo SOAP"; /// For logging only
string url = flexFlowCfg.BaseUrl + flexFlowCfg.GetUnitInfoUrl; /// Complete URL from base URL and relative URL
string localUserId = (!flexFlowCfg.SendUserId || string.IsNullOrEmpty(UserId)) ? "admin" : UserId;
log.DebugFormat("{0} URL is {1}", serviceName, url);
if (string.IsNullOrEmpty(wm.SerialNr))
{
/// S/N is missing
wm.LastRecordIsNok = false; /// OK, this is an RFID comm. error, not a production tracing error
log.DebugFormat("{0} : pcbNr is missing", serviceName);
return Retv.OK;
}
string request;
if (isRest)
{
/// JSON request formatting
request = string.Format("{{{0}\"StationName\": \"{1}\",{0}\"UserID\": \"{2}\",{0}\"SerialNumber\": \"{3}\",{0}}}",
string.Empty, //Environment.NewLine,
StationName,
localUserId,
wm.SerialNr);
}
else
{
/// TODO: Implement XML request formatting
request = string.Format("{{{0}\"StationName\": \"{1}\",{0}\"UserID\": \"{2}\",{0}\"SerialNumber\": \"{3}\",{0}}}",
string.Empty, //Environment.NewLine,
StationName,
localUserId,
wm.SerialNr);
}
log.DebugFormat("{0} request (pcbNr = {1}):\r\n{2}", serviceName, wm.SerialNr, request);
/// Object to be updated when parsing the response
UnitInfoData data = new UnitInfoData(wm.SerialNr, StationName, localUserId);
try
{
var webRequest = isRest ? CreateRestHttpWebRequest(url) : CreateSoapHttpWebRequest(url);
using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
{
streamWriter.Write(request);
}
using (var streamReader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
{
var response = streamReader.ReadToEnd();
log.DebugFormat("{0} response (pcbNr={1}):\r\n{2}", serviceName, wm.SerialNr, response);
if (isRest)
{
/// JSON response parsing
string pattern = "\"id\":";
int position = response.IndexOf(pattern) + pattern.Length;
int length = response.Substring(position).IndexOfAny(new char[] { ',', '}', '\r', '\n' });
int idummy;
if (int.TryParse(response.Substring(position, length).Trim(), out idummy))
{
data.Id = idummy;
}
pattern = "\"value\":";
position = response.IndexOf(pattern) + pattern.Length;
length = response.Substring(position).IndexOfAny(new char[] { ',', '}', '\r', '\n' });
data.Value = response.Substring(position, length);
pattern = "\"ffUnitId\":";
position = response.IndexOf(pattern) + pattern.Length;
length = response.Substring(position).IndexOfAny(new char[] { ',', '}', '\r', '\n' });
long ldummy;
if (long.TryParse(response.Substring(position, length).Trim(), out ldummy))
{
data.FFUnitId = ldummy;
}
pattern = "\"ffTestId\":";
position = response.IndexOf(pattern) + pattern.Length;
length = response.Substring(position).IndexOfAny(new char[] { ',', '}', '\r', '\n' });
if (long.TryParse(response.Substring(position, length).Trim(), out ldummy))
{
data.FFTestId = ldummy;
}
pattern = "\"ffPartId\":";
position = response.IndexOf(pattern) + pattern.Length;
length = response.Substring(position).IndexOfAny(new char[] { ',', '}', '\r', '\n' });
if (long.TryParse(response.Substring(position, length).Trim(), out ldummy))
{
data.FFPartId = ldummy;
}
}
else
{
///
}
}
}
catch (Exception exc)
{
log.ErrorFormat("{0} failed: {1}", serviceName, exc.Message);
}
return (data != null && data.Id == 0) ? Retv.OK : Retv.Error;
}
/// <summary>
/// Write results of a batch of water meters to the DB
/// </summary>
/// <param name="batch">Batch entity</param>
Retv SaveResults(Results.Entities.Batch batch)
{
try
{
int writtenRecordsCount = 0;
foreach (var wMtr in batch.WaterMeters)
{
writtenRecordsCount += SaveOneUnitResult(wMtr, (flexFlowCfg.SaveResultsApi == WebApi.REST));
}
log.ErrorFormat("Batch {0}: {1} of {2} watermeters written to the regular production tracing DB",
batch.BatchNr, writtenRecordsCount, batch.WaterMeters.Count);
}
catch (Exception exc)
{
log.WarnFormat("Failed to write results of batch {0} to production tracing DB: {1}",
batch.BatchNr, exc.Message);
return Retv.Error;
}
return Retv.OK;
}
/// <summary>
/// Write one meter results to the DB
/// </summary>
/// <param name="wm">Watermeter entity</param>
/// <returns>Number of written water meters (0 or 1)</returns>
int SaveOneUnitResult(Results.Entities.WaterMeter wm, bool isRest)
{
string serviceName = isRest ? "SaveTestResult REST" : "SaveTestResult SOAP"; /// For logging only
string url = flexFlowCfg.BaseUrl + flexFlowCfg.SaveResultsUrl; /// Complete URL from base URL and relative URL
string localUserId = (!flexFlowCfg.SendUserId || string.IsNullOrEmpty(UserId)) ? "admin" : UserId;
log.DebugFormat("{0} URL is {1}", serviceName, url);
if (string.IsNullOrEmpty(wm.SerialNr))
{
/// S/N is missing
log.DebugFormat("{0} : pcbNr is missing", serviceName);
return 0;
}
///
/// Request formatting
///
string request;
if (isRest)
{
/// JSON request formatting
string status = wm.Passed ? "Passed" : "Failed";
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("{{"));
sb.AppendLine(string.Format(" \"timestamp\": \"{0:yyyy-MM-dd HH:mm:ss}\",", DateTime.Now));
sb.AppendLine(string.Format(" \"syntaxRev\": \"1.1\","));
sb.AppendLine(string.Format(" \"compatibleRev\": \"1.1\","));
sb.AppendLine(string.Format(" \"factory\": {{"));
sb.AppendLine(string.Format(" \"name\": \"{0}\",", "Flex Chennai"));
sb.AppendLine(string.Format(" \"line\": \"\","));
sb.AppendLine(string.Format(" \"tester\": \"{0}\",", StationName));
sb.AppendLine(string.Format(" \"user\": \"{0}\"", localUserId));
sb.AppendLine(string.Format(" }},"));
sb.AppendLine(string.Format(" \"product\": {{"));
sb.AppendLine(string.Format(" \"name\": \"{0}\",", "iPERL"));
sb.AppendLine(string.Format(" \"revision\": \"{0}\"", "S4"));
sb.AppendLine(string.Format(" }},"));
sb.AppendLine(string.Format(" \"panel\": {{"));
sb.AppendLine(string.Format(" \"id\": \"\","));
sb.AppendLine(string.Format(" \"comment\": \"\","));
sb.AppendLine(string.Format(" \"runmode\": \"{0}\",", "Production"));
sb.AppendLine(string.Format(" \"timestamp\": \"{0:yyyy-MM-dd HH:mm:ss}\",", DateTime.Now));
sb.AppendLine(string.Format(" \"testTime\": \"{0}\",", 0));
sb.AppendLine(string.Format(" \"status\": \"{0}\",", status));
sb.AppendLine(string.Format(" \"dut\": [{{"));
sb.AppendLine(string.Format(" \"id\": \"{0}\",", wm.SerialNr));
sb.AppendLine(string.Format(" \"comment\": \"\","));
sb.AppendLine(string.Format(" \"panel\": \"{0}\",", 1));
sb.AppendLine(string.Format(" \"socket\": \"{0}\",", 0));
sb.AppendLine(string.Format(" \"timestamp\": \"{0:yyyy-MM-dd HH:mm:ss}\",", resultsTimeStamp));
sb.AppendLine(string.Format(" \"runmode\": \"{0}\",", "Production"));
sb.AppendLine(string.Format(" \"testTime\": \"{0}\",", (wm.Batch.EndTime - wm.Batch.StartTime).TotalSeconds.ToString("F0")));
sb.AppendLine(string.Format(" \"status\": \"{0}\",", status));
sb.AppendLine(string.Format(" \"group\": {{"));
sb.AppendLine(string.Format(" \"name\": \"{0}\",", "iPERL"));
sb.AppendLine(string.Format(" \"groupIndex\": \"{0}\",", 0));
sb.AppendLine(string.Format(" \"loopIndex\": \"{0}\",", 0));
sb.AppendLine(string.Format(" \"type\": \"{0}\",", "SequenceCall"));
sb.AppendLine(string.Format(" \"moduleTime\": \"{0}\",", 0));
sb.AppendLine(string.Format(" \"totalTime\": \"{0}\",", (wm.Batch.EndTime - wm.Batch.StartTime).TotalSeconds.ToString("F0")));
sb.AppendLine(string.Format(" \"timestamp\": \"{0:yyyy-MM-dd HH:mm:ss}\",", resultsTimeStamp));
sb.AppendLine(string.Format(" \"status\": \"{0}\"", status));
sb.AppendLine(string.Format(" }}"));
sb.AppendLine(string.Format(" }}]"));
sb.AppendLine(string.Format(" }}"));
sb.AppendLine(string.Format("}}"));
request = sb.ToString();
}
else
{
/// XML request formatting
string status = wm.Passed ? "PASS" : "FAIL";
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("<BATCH TIMESTAMP=\"{0}\" SYNTAX_REV=\"1.0\" COMPATIBLE_REV=\"1.0\">", resultsTimeStampStr));
sb.AppendLine(string.Format(" <TIMESTAMP>{0}</TIMESTAMP>", resultsTimeStampStr));
sb.AppendLine(string.Format(" <FACTORY NAME=\"\" LINE=\"\" TESTER=\"InitialATE(A)_03\" FIXTURE=\"YA134A451UM\" SHIFT=\"day\" USER=\"OP\"/>"));
sb.AppendLine(string.Format(" <PRODUCT NAME=\"iPERL\" REVISION=\"S4\" FAMILY=\"\" CUSTOMER=\"HM\"/>"));
sb.AppendLine(string.Format(" <PANEL ID=\"{0}\" COMMENT=\"\" RUNMODE=\"\" TIMESTAMP=\"{1}\" TESTTIME=\"16.6\" ENDTIME=\"{1}\" STATUS=\"{2}\">", wm.SerialNr, resultsTimeStampStr, status));
sb.AppendLine(string.Format(" <DUT ID=\"{0}\" COMMENT=\"\" PANEL=\"0\" SOCKET=\"1\" TIMESTAMP=\"{1}\" TESTTIME=\"16.6\" ENDTIME=\"{1}\" STATUS=\"{2}\">", wm.SerialNr, resultsTimeStampStr, status));
sb.AppendLine(string.Format(" <GROUP NAME=\"{0}\" STEPGROUP=\"Main\" GROUPINDEX=\"0\" LOOPINDEX=\"-1\" TYPE=\"\" RESOURCE=\"\" MODULETIME=\"\" TOTALTIME=\"\" TIMESTAMP=\"{1}\" STATUS=\"{2}\">", wm.SerialNr, resultsTimeStampStr, status));
sb.AppendLine(string.Format(" <TEST NAME=\"Cavity\" DESCRIPTION=\"Cavity\" UNIT=\"\" VALUE=\"01\" HILIM=\"\" LOLIM=\"\" STATUS=\"{0}\" RULE=\"\" TARGET=\"\"/>", status));
sb.AppendLine(string.Format(" </GROUP>"));
sb.AppendLine(string.Format(" </DUT>"));
sb.AppendLine(string.Format(" </PANEL>"));
sb.AppendLine(string.Format("</BATCH>"));
request = sb.ToString();
}
log.DebugFormat("{0} request (pcbNr = {1}):\r\n{2}", serviceName, wm.SerialNr, request);
/// Object to be updated when parsing the response
ResultsData data = new ResultsData(wm.SerialNr, StationName, localUserId);
try
{
var webRequest = isRest ? CreateRestHttpWebRequest(url) : CreateSoapHttpWebRequest(url);
using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
{
streamWriter.Write(request);
}
using (var streamReader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
{
var response = streamReader.ReadToEnd();
log.DebugFormat("{0} response (pcbNr={1}):\r\n{2}", serviceName, wm.SerialNr, response);
if (isRest)
{
/// JSON response parsing
string pattern = "\"id\":";
int position = response.IndexOf(pattern) + pattern.Length;
int length = response.Substring(position).IndexOfAny(new char[] { ',', '}', '\r', '\n' });
int idummy;
if (int.TryParse(response.Substring(position, length).Trim(), out idummy))
{
data.Id = idummy;
}
}
else
{
/// TODO: XML resonse parsing
}
}
}
catch (Exception exc)
{
log.ErrorFormat("{0} failed: {1}", serviceName, exc.Message);
}
return (data != null && data.Id == 0) ? 1 : 0;
}
public HttpWebRequest CreateRestHttpWebRequest(string url)
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "POST";
return request;
}
public HttpWebRequest CreateSoapHttpWebRequest(string url)
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add(@"SOAPAction:http://tempuri.org/Addition");
request.ContentType = "application/xml";
request.Accept = "text/xml";
request.Method = "POST";
return request;
}
}
}

View File

@ -0,0 +1,198 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Resources;
namespace TBF.BenchControl.Output.FlexFlow
{
public enum WebApi
{
REST,
SOAP,
}
/// <summary>
/// Holds FlexFlow.Rest configuration.
/// </summary>
public class FlexFlowCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlexFlowCfg) })[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 string BaseUrl;
public WebApi GetUnitInfoApi;
public string GetUnitInfoUrl;
public WebApi SaveResultsApi;
public string SaveResultsUrl;
public bool CheckPreviousRecords;
public bool SaveResults;
public bool SendUserId;
/// Private parameterless constructor invoked by all other (public) constructors
FlexFlowCfg() { }
public FlexFlowCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
BaseUrl = "http://gdlm02205:4450/?wsdl";
GetUnitInfoUrl = string.Empty;
SaveResultsUrl = string.Empty;
CheckPreviousRecords = true;
SaveResults = true;
SendUserId = true;
}
string[] paramNames = new string[]
{
"Base URL", /// 0
"Get unit info", /// 1
"GetUnitInfo Web API", /// 2
"GetUnitInfo URL relative to base URL", /// 3
"Save result", /// 4
"SaveResult Web API", /// 5
"SaveResult URL relative to base URL", /// 6
"Send user ID", /// 7
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 1:
case 4:
case 7:
return new string[] { Strings.yes, Strings.no };
case 2:
case 5:
return new string[] { WebApi.REST.ToString(), WebApi.SOAP.ToString() };
default:
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case 0: return BaseUrl;
case 1: return CheckPreviousRecords ? Strings.yes : Strings.no;
case 2: return GetUnitInfoApi.ToString();
case 3: return GetUnitInfoUrl;
case 4: return SaveResults ? Strings.yes : Strings.no;
case 5: return SaveResultsApi.ToString();
case 6: return SaveResultsUrl;
case 7: return SendUserId ? Strings.yes : Strings.no;
default:
return string.Format("{0} CheckPrev.={1}, SaveResults={2}, URL={3}, URL2={4}",
Name,
CheckPreviousRecords,
SaveResults,
BaseUrl,
GetUnitInfoUrl);
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0: BaseUrl = str; return CfgUpdateFlags.RestartRqrd;
case 1: CheckPreviousRecords = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd;
case 2:
foreach (var wa in new WebApi[] { WebApi.REST, WebApi.SOAP })
if (str == wa.ToString())
{
GetUnitInfoApi = wa;
return CfgUpdateFlags.RestartRqrd;
}
return CfgUpdateFlags.None;
case 3: GetUnitInfoUrl = str; return CfgUpdateFlags.RestartRqrd;
case 4: SaveResults = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd;
case 5:
foreach (var wa in new WebApi[] { WebApi.REST, WebApi.SOAP })
if (str == wa.ToString())
{
SaveResultsApi = wa;
return CfgUpdateFlags.RestartRqrd;
}
return CfgUpdateFlags.None;
case 6: SaveResultsUrl = str; return CfgUpdateFlags.RestartRqrd;
case 7: SendUserId = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
switch (i)
{
case 0:
case 3:
case 6:
return true;
case 1:
case 2:
case 4:
case 5:
case 7:
if (ParamValues(i).Contains(strValue)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(FlexFlowCfg prms)
{
prms.BaseUrl = this.BaseUrl;
prms.CheckPreviousRecords = this.CheckPreviousRecords;
prms.GetUnitInfoApi = this.GetUnitInfoApi;
prms.GetUnitInfoUrl = this.GetUnitInfoUrl;
prms.SaveResults = this.SaveResults;
prms.SaveResultsApi = this.SaveResultsApi;
prms.SaveResultsUrl = this.SaveResultsUrl;
prms.SendUserId = this.SendUserId;
}
public Config.Entities.IParamsProvider Clone()
{
FlexFlowCfg pars = new FlexFlowCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}

View File

@ -1,323 +0,0 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using Config.Entities;
namespace TBF.BenchControl.Output.FlexFlow.Rest
{
public class FlexFlow : ComponentBase, IOperation, GenericDevices.IResultsWriter, GenericDevices.IStartInfoReader, Generic.IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(FlexFlow));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
FlexFlowCfg flexFlowCfg;
public string StationName
{
get
{
var benchInfo = TBF.BenchControl.Sequences.ProcessData.BenchInfo;
return (benchInfo != null) ? benchInfo.TestBenchName : "TestBench";
}
}
public string UserID { get { return Users.GlobalData.GetCurrentUserName(); } }
enum Retv
{
OK,
Error,
}
enum OpState
{
None,
GetUnitInfosScheduled,
GetUnitInfosRunning,
SaveResultsScheduled,
SaveResultsRunning,
}
///
OpState currentOpState;
bool opCompleted;
bool anyError;
/// <summary>
/// Watermeters to check at the beginning of the cycle
/// </summary>
IList<Results.Entities.WaterMeter> waterMeters;
/// <summary>
/// Data (tracing records) to write at the end of cycle
/// </summary>
Results.Entities.Batch batch;
public FlexFlow() {}
public FlexFlow(Generic.IComponentCfg cfg)
: base(cfg)
{
flexFlowCfg = cfg as FlexFlowCfg;
}
public override void Initialize()
{
currentOpState = OpState.None;
if (flexFlowCfg.DebugLevel == DebugMode.Normal)
{
/// TODO: Initialize FlexFlow
log.FatalFormat("{0} initialized: {1}", Name, this);
}
else
{
log.FatalFormat("{0} simulated: {1}", Name, this);
}
}
///
/// IDevice interface implementation
///
public void RunDeviceBefore() { }
public void RunDeviceAfter() { }
///
public void StopDevice()
{
if (flexFlowCfg.DebugLevel != DebugMode.Normal) return;
/// TODO: Close FlexFlow
}
public void StopDevice2() {}
/// <summary>
/// Reads information on start of a cycle, Events: Event.InfoRead
/// </summary>
/// <param name="waterMeters">Results of water meters</param>
/// <returns>Reference to the operation</returns>
public IOperation ReadStartInfoOp(IList<Results.Entities.WaterMeter> waterMeters)
{
if (!flexFlowCfg.CheckPreviousRecords)
{
return null;
}
else if ((currentOpState == OpState.GetUnitInfosRunning) || (currentOpState == OpState.SaveResultsRunning))
{
throw new Exception("Sequence error");
}
else
{
this.waterMeters = waterMeters;
currentOpState = OpState.GetUnitInfosScheduled;
return this;
}
}
/// <summary>
/// Writes the test cycle results into a file, Events: Event.ResultsWritten
/// </summary>
/// <param name="procedure">Procedure to print the results of</param>
/// <param name="unsortedResults">Results to write into the file</param>
/// <returns>Reference to the operation</returns>
public IOperation ProcessResultsOp(Results.Entities.Batch batch)
{
if (!flexFlowCfg.SaveResults)
{
return null;
}
else if ((currentOpState == OpState.GetUnitInfosRunning) || (currentOpState == OpState.SaveResultsRunning))
{
throw new Exception("Sequence error");
}
else
{
this.batch = batch;
currentOpState = OpState.SaveResultsScheduled;
return this;
}
}
/// <summary>Start this operation</summary>
public void Start()
{
if (currentOpState == OpState.GetUnitInfosScheduled)
{
currentOpState = OpState.GetUnitInfosRunning;
}
else if (currentOpState == OpState.SaveResultsScheduled)
{
currentOpState = OpState.SaveResultsRunning;
}
opCompleted = false;
anyError = false;
}
/// <summary>Run this operation</summary>
/// <returns>Event.ResultsWritten or Event.Error</returns>
public Event Run()
{
if (currentOpState == OpState.GetUnitInfosRunning)
{
if (flexFlowCfg.DebugLevel == DebugMode.Simulate)
{
return Event.InfoRead;
}
else if (!opCompleted)
{
log.WarnFormat("{0} : Run() : currentOp = {1}", Name, currentOpState);
opCompleted = true;
if (GetUnitInfos(waterMeters) != Retv.OK)
{
anyError = true;
}
return anyError ? Event.InfoNotRead : Event.InfoRead;
}
else
{
return anyError ? Event.InfoNotRead : Event.InfoRead;
}
}
else if (currentOpState == OpState.SaveResultsRunning)
{
if (flexFlowCfg.DebugLevel == DebugMode.Simulate || batch.WaterMeters.Count == 0)
{
return Event.ResultsWritten;
}
else if (!opCompleted)
{
log.WarnFormat("{0} : Run() : currentOp = {1}", Name, currentOpState);
opCompleted = true;
if (SaveResults(batch) != Retv.OK)
{
anyError = true;
}
return anyError ? Event.ErrorProcessingResults : Event.ResultsWritten;
}
else
{
return anyError ? Event.ErrorProcessingResults : Event.ResultsWritten;
}
}
else
{
return Event.None;
}
}
/// <summary>Stop this operation</summary>
public void Stop()
{
currentOpState = OpState.None;
}
Retv GetUnitInfos(IList<Results.Entities.WaterMeter> waterMeters)
{
bool allOK = true;
foreach (var wm in waterMeters)
{
if (wm != null && !wm.Disabled)
{
GetOneUnitInfo(wm);
if (wm.LastRecordIsNok)
{
allOK = false;
}
}
}
return allOK ? Retv.OK : Retv.Error;
}
Retv GetOneUnitInfo(Results.Entities.WaterMeter wm)
{
if (string.IsNullOrEmpty(wm.SerialNr))
{
/// S/N is missing
wm.LastRecordIsNok = false; /// OK, this is an RFID comm. error, not a production tracing error
return Retv.OK;
}
string request;
if (flexFlowCfg.DoNotSendUserId || string.IsNullOrEmpty(UserID))
{
request = '{'
+ string.Format("{0}\"serialNumber\": \"{1}\",{0}\"stationName\": \"{2}\"{0}",
Environment.NewLine, wm.SerialNr, StationName)
+ '}';
}
else
{
request = '{'
+ string.Format("{0}\"serialNumber\": \"{1}\",{0}\"stationName\": \"{2}\",{0}\"userId\": \"{3}\"{0}",
Environment.NewLine, wm.SerialNr, StationName, UserID)
+ '}';
}
/// TODO: Invoke GetUnitInfo
return Retv.OK;
}
/// <summary>
/// Write results of a batch of water meters to the DB
/// </summary>
/// <param name="batch">Batch entity</param>
Retv SaveResults(Results.Entities.Batch batch)
{
try
{
int writtenRecordsCount = 0;
foreach (var wMtr in batch.WaterMeters)
{
if (wMtr.SessionId == 1)
{
writtenRecordsCount += SaveOneUnitResult(wMtr);
}
}
log.ErrorFormat("Batch {0}: {1} of {2} watermeters written to the regular production tracing DB",
batch.BatchNr, writtenRecordsCount, batch.WaterMeters.Count);
}
catch (Exception exc)
{
log.WarnFormat("Failed to write results of batch {0} to production tracing DB: {1}",
batch.BatchNr, exc.Message);
return Retv.Error;
}
return Retv.OK;
}
/// <summary>
/// Write one meter results to the DB
/// </summary>
/// <param name="wm">Watermeter entity</param>
/// <returns>Number of written water meters (0 or 1)</returns>
int SaveOneUnitResult(Results.Entities.WaterMeter wm)
{
if (string.IsNullOrEmpty(wm.SerialNr) || (wm.ProcessId == 0))
{
/// Without PCB number there is no DB activity
return 0;
}
else
{
/// TODO: Invoke SaveResult
return 1;
}
}
}
}

View File

@ -1,172 +0,0 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Resources;
namespace TBF.BenchControl.Output.FlexFlow.Rest
{
/// <summary>
/// Holds FlexFlow.Rest configuration.
/// </summary>
public class FlexFlowCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlexFlowCfg) })[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 string Url;
public string Url2;
public bool CheckPreviousRecords;
public bool SaveResults;
public bool DoNotSendUserId;
/// Private parameterless constructor invoked by all other (public) constructors
FlexFlowCfg() { }
public FlexFlowCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
Url = "http://gdlm02205:4450/?wsdl";
Url2 = string.Empty;
CheckPreviousRecords = true;
SaveResults = true;
DoNotSendUserId = true;
}
string[] paramNames = new string[]
{
"URL",
"URL2",
"Get Unit Info",
"Save Result",
"Do not send UserId",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 2:
case 3:
case 4:
return new List<string>() { Strings.yes, Strings.no };
default:
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case 0:
return Url;
case 1:
return Url2;
case 2:
return CheckPreviousRecords ? Strings.yes : Strings.no;
case 3:
return SaveResults ? Strings.yes : Strings.no;
case 4:
return DoNotSendUserId ? Strings.yes : Strings.no;
default:
return string.Format("{0} CheckPrev.={1}, SaveResults={2}, URL={3}, URL2={4}",
Name,
CheckPreviousRecords,
SaveResults,
Url,
Url2);
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0:
Url = strValue;
return CfgUpdateFlags.RestartRqrd;
case 1:
Url2 = strValue;
return CfgUpdateFlags.RestartRqrd;
case 2:
CheckPreviousRecords = (strValue == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
case 3:
SaveResults = (strValue == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
case 4:
DoNotSendUserId = (strValue == Strings.yes);
return CfgUpdateFlags.RestartRqrd;
default:
return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
switch (i)
{
case 0:
case 1:
return true;
case 2:
case 3:
case 4:
if (ParamValues(i).Contains(strValue)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(FlexFlowCfg prms)
{
prms.Url = this.Url;
prms.Url2 = this.Url2;
prms.CheckPreviousRecords = this.CheckPreviousRecords;
prms.SaveResults = this.SaveResults;
prms.DoNotSendUserId = this.DoNotSendUserId;
}
public Config.Entities.IParamsProvider Clone()
{
FlexFlowCfg pars = new FlexFlowCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}

View File

@ -0,0 +1,22 @@
using System;
namespace TBF.BenchControl.Output.FlexFlow
{
public class ResultsData
{
public string SerialNr;
public string StationName;
public string UserId;
public int Id;
public ResultsData(string serialNr, string stationName, string userId)
{
SerialNr = serialNr;
StationName = stationName;
UserId = userId;
Id = 9999;
}
}
}

View File

@ -0,0 +1,27 @@
using System;
namespace TBF.BenchControl.Output.FlexFlow
{
public class UnitInfoData
{
public string SerialNr;
public string StationName;
public string UserId;
public int Id;
public string Value;
public long FFUnitId;
public long FFTestId;
public long FFPartId;
public UnitInfoData(string serialNr, string stationName, string userId)
{
SerialNr = serialNr;
StationName = stationName;
UserId = userId;
Id = 9999;
Value = string.Empty;
}
}
}

View File

@ -1599,7 +1599,7 @@ namespace TBF.BenchControl.Sequences
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
{
float errorPct = 0;
double errorPct = Convert.ToDouble((i % 10) - 5) / 2.0;
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.Single);
IRegReader regReader = sensPath.RegisterReaders[i];
@ -1618,7 +1618,7 @@ namespace TBF.BenchControl.Sequences
meterRslt.TimestampEnd = tstRslt.TargetTime();
meterRslt.TestTime = tstRslt.TargetTime();
meterRslt.Error = errorPct;
meterRslt.Passed = true;
meterRslt.Passed = errorPct >= test.ErrLimLo + test.Uncertainty && errorPct <= test.ErrLimHi - test.Uncertainty;
meterRslt.TestDone = true;
tstRslt.TestDone = true;
}

View File

@ -155,7 +155,7 @@ namespace TBF.BenchControl
Factories.Add(new Output.FileWriters.Xml.FactoryCompound());
Factories.Add(new Output.FileWriters.Xml.FactoryHeatMeters());
Factories.Add(new Output.FileWriters.XmlBatch.FactorySingle());
Factories.Add(new Output.FlexFlow.Rest.Factory());
Factories.Add(new Output.FlexFlow.Factory());
Factories.Add(new Output.Printers.Enhanced.FactorySingle());
Factories.Add(new Output.Printers.Enhanced.FactoryCompound());
Factories.Add(new Output.Printers.Enhanced.FactoryHeatMeters());

View File

@ -141,6 +141,7 @@
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Numerics" />
<Reference Include="System.Security" />
<Reference Include="System.Web" />
@ -1107,9 +1108,11 @@
<Compile Include="BenchControl\Output\FileWriters\Xml\WriterCfgCtrl.designer.cs">
<DependentUpon>WriterCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="BenchControl\Output\FlexFlow\Rest\Factory.cs" />
<Compile Include="BenchControl\Output\FlexFlow\Rest\FlexFlow.cs" />
<Compile Include="BenchControl\Output\FlexFlow\Rest\FlexFlowCfg.cs" />
<Compile Include="BenchControl\Output\FlexFlow\Factory.cs" />
<Compile Include="BenchControl\Output\FlexFlow\FlexFlow.cs" />
<Compile Include="BenchControl\Output\FlexFlow\FlexFlowCfg.cs" />
<Compile Include="BenchControl\Output\FlexFlow\ResultsData.cs" />
<Compile Include="BenchControl\Output\FlexFlow\UnitInfoData.cs" />
<Compile Include="BenchControl\Output\HeaderFooterDlg.cs">
<SubType>Form</SubType>
</Compile>