833 lines
37 KiB
C#
833 lines
37 KiB
C#
///
|
|
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.Windows.Forms;
|
|
using log4net;
|
|
using Common;
|
|
using Config.Entities;
|
|
using TBF.Resources;
|
|
using TBF.BenchControl.Sequences;
|
|
using System.IO;
|
|
|
|
namespace TBF.BenchControl.TestMethods.S640Communication
|
|
{
|
|
public enum CommErr
|
|
{
|
|
None = 0,
|
|
CommFailed, /// 1
|
|
HeadDisabledByUser, /// 2
|
|
}
|
|
|
|
///
|
|
/// (Program.LocalSettings.OptoHeadsEnabled & (1L << ix))) == 0 . . opto head is disabled in configuration
|
|
/// optoheads[ix] == null . . . . . . . . . . . . . . . . . . . . . opto head is not part of the selected sensors path
|
|
/// optoHeads[ix].Disabled == true . . . . . . . . . . . . . . . . opto head was disabled by the user
|
|
///
|
|
public partial class S640CommForm : Form, GenericDevices.IHasCompleted
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(S640CommForm));
|
|
protected static readonly ILog sirtDataLogger = LogManager.GetLogger("SirtData");
|
|
|
|
public const int UIBoxesCount = 40;
|
|
public static Color DisabledColor = Color.DarkGray;
|
|
public static Color OptoOKColor = Color.Green;
|
|
public static Color OptoNokColor = Color.Red;
|
|
public const string StartFileName = "Start.pro";
|
|
public const string EndFileName = "Ende.pro";
|
|
public const string ErrorFileName = "Error.dat";
|
|
|
|
enum Step
|
|
{
|
|
/// Start
|
|
WatchOptoHeads,
|
|
SaveStartPro,
|
|
AwaitResponseToStartPro,
|
|
|
|
/// End
|
|
SaveEndePro,
|
|
AwaitResponseToEndePro,
|
|
ConfirmError,
|
|
Idle,
|
|
}
|
|
|
|
DateTime startTime;
|
|
int startTimeSec;
|
|
|
|
|
|
// Set to 'true' when the form closes
|
|
public bool Completed { get { return formCompleted; } }
|
|
bool formCompleted;
|
|
|
|
bool forcedClose; /// Set in the forced close handler
|
|
|
|
|
|
/// <summary> Number of text boxes for serial numbers </summary>
|
|
public int WaterMetersCount;
|
|
|
|
|
|
int textBoxesCount;
|
|
///
|
|
Label[] labels;
|
|
PictureBox[] pictures;
|
|
TextBox[] messages;
|
|
CheckBoxImage[] checkBoxes;
|
|
|
|
int[] ckbIndex; /// Initialized by ShuffleTextBoxes() ... to be used in the future in case of test benches with two lines
|
|
|
|
|
|
RegisterReaders.S640Stream.S640Stream[] optoHeads;
|
|
|
|
|
|
///
|
|
/// Parameters and current state of activities
|
|
///
|
|
DebugMode debugLevel;
|
|
int optoDataTimeout;
|
|
string fileExchangePath;
|
|
int fileExchangeTimeout;
|
|
ProcParams pPars;
|
|
///
|
|
IList<S640Activity> activities;
|
|
IList<Test> tests;
|
|
///
|
|
int currentActivityIx;
|
|
///
|
|
Step step;
|
|
DateTime savedTimestamp;
|
|
|
|
|
|
System.Windows.Forms.Timer timer;
|
|
|
|
///
|
|
/// Used in Step.WatchOptoHeads, initially all zeros
|
|
///
|
|
int[] commOkLoopsCount;
|
|
|
|
|
|
/// <summary>
|
|
/// Parameterless constructor (without watermeters, threads)
|
|
/// </summary>
|
|
public S640CommForm()
|
|
{
|
|
InitializeComponent();
|
|
|
|
labels = new Label[UIBoxesCount]
|
|
{
|
|
wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7,
|
|
wmLabel8, wmLabel9, wmLabel10, wmLabel11, wmLabel12, wmLabel13, wmLabel14,
|
|
wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20, wmLabel21,
|
|
wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28,
|
|
wmLabel29, wmLabel30, wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35,
|
|
wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40,
|
|
};
|
|
pictures = new PictureBox[UIBoxesCount]
|
|
{
|
|
pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6,
|
|
pictureBox7, pictureBox8, pictureBox9, pictureBox10, pictureBox11, pictureBox12,
|
|
pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18,
|
|
pictureBox19, pictureBox20, pictureBox21, pictureBox22, pictureBox23, pictureBox24,
|
|
pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30,
|
|
pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36,
|
|
pictureBox37, pictureBox38, pictureBox39, pictureBox40,
|
|
};
|
|
messages = new TextBox[UIBoxesCount]
|
|
{
|
|
wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6,
|
|
wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10, wmTextBox11, wmTextBox12,
|
|
wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18,
|
|
wmTextBox19, wmTextBox20, wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24,
|
|
wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30,
|
|
wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36,
|
|
wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40,
|
|
};
|
|
checkBoxes = new CheckBoxImage[UIBoxesCount]
|
|
{
|
|
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5,
|
|
checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
|
|
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15,
|
|
checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
|
|
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25,
|
|
checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
|
|
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35,
|
|
checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
|
|
};
|
|
|
|
ckbIndex = new int[UIBoxesCount]; /// Initialized by ShuffleTextBoxes() ... to be used in the future in case of test benches with two lines
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for one S640Communication test
|
|
/// </summary>
|
|
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
|
|
public S640CommForm(S640Activity activity, I640Cfg config, Generic.IProcedureParams procParams, Test test)
|
|
: this(new List<S640Activity> { activity }, config, procParams, new List<Test> { test })
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for multiple S640Communication tests
|
|
/// </summary>
|
|
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
|
|
public S640CommForm(IList<S640Activity> activities, I640Cfg config, Generic.IProcedureParams procParams, IList<Test> tests)
|
|
: this()
|
|
{
|
|
this.activities = activities;
|
|
debugLevel = config.DebugLevel;
|
|
optoDataTimeout = config.OptoDataTimeout;
|
|
fileExchangePath = string.IsNullOrEmpty(config.FileExchangePath) ? string.Empty : config.FileExchangePath;
|
|
fileExchangeTimeout = config.FileExchangeTimeout;
|
|
this.tests = tests;
|
|
this.pPars = procParams as ProcParams;
|
|
|
|
if (activities.Count != tests.Count)
|
|
{
|
|
throw new Exception("Something strange: activities.Count != tests.Count");
|
|
}
|
|
|
|
if (ProcessData.RegisterReaders.Length != ProcessData.BatchRslts.Batch.WaterMeters.Count)
|
|
{
|
|
throw new Exception("Something strange: RegisterReaders.Length != WaterMeters.Count");
|
|
}
|
|
|
|
if (activities.Count > 0)
|
|
{
|
|
ProcessData.RegisterReaders = StateMachine.GetMetersPath(tests[0]).RegisterReaders;
|
|
}
|
|
|
|
optoHeads = new RegisterReaders.S640Stream.S640Stream[ProcessData.RegisterReaders.Length];
|
|
///
|
|
for (int wmPos = 0; wmPos < ProcessData.RegisterReaders.Length; wmPos++)
|
|
{
|
|
optoHeads[wmPos] = ProcessData.RegisterReaders[wmPos] as RegisterReaders.S640Stream.S640Stream;
|
|
}
|
|
|
|
WaterMetersCount = ProcessData.RegisterReaders.Length;
|
|
ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize);
|
|
|
|
formCompleted = false;
|
|
StartForceCloseHandler();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Make sure the layout of labels/text boxes on the screen
|
|
/// corresponds to the layout of watermeters of the test bench.
|
|
/// </summary>
|
|
/// <param name="wmsCount">Number of watermeters</param>
|
|
/// <param name="lineSize">Number of watermeters in one line</param>
|
|
void ShuffleTextBoxes(int wmsCount, int lineSize)
|
|
{
|
|
textBoxesCount = UIBoxesCount;
|
|
///
|
|
if (wmsCount < textBoxesCount && lineSize > 0)
|
|
{
|
|
int nrLines = (wmsCount + lineSize - 1) / lineSize;
|
|
int gap = (textBoxesCount - wmsCount) / nrLines;
|
|
|
|
int dest = 0;
|
|
for (int l = 0; l < nrLines; l++)
|
|
{
|
|
for (int i = 0; i < lineSize; i++)
|
|
{
|
|
labels[dest] = labels[l * lineSize + l * gap + i];
|
|
pictures[dest] = pictures[l * lineSize + l * gap + i];
|
|
messages[dest] = messages[l * lineSize + l * gap + i];
|
|
checkBoxes[dest] = checkBoxes[l * lineSize + l * gap + i];
|
|
ckbIndex[l * lineSize + l * gap + i] = dest;
|
|
dest++;
|
|
}
|
|
}
|
|
|
|
textBoxesCount = wmsCount;
|
|
}
|
|
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
labels[i].Visible = pictures[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
|
|
|
|
if (optoHeads[i] != null) labels[i].Text = (i + 1).ToString();
|
|
}
|
|
|
|
///
|
|
/// Resize this form to fit enabled controls
|
|
///
|
|
int xMax = 0;
|
|
int yMax = 0;
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
if (messages[i].Left + messages[i].Width > xMax) xMax = messages[i].Left + messages[i].Width;
|
|
if (messages[i].Top + messages[i].Height > yMax) yMax = messages[i].Top + messages[i].Height;
|
|
}
|
|
///Width = xMax + 30;
|
|
Height = yMax + 50;
|
|
}
|
|
|
|
|
|
private void S640CommForm_Load(object sender, EventArgs e)
|
|
{
|
|
Localize();
|
|
|
|
///
|
|
/// Set location and checkbox states to values stored in local settings
|
|
///
|
|
TBF.LocalSettings ls = Program.LocalSettings;
|
|
Left = (ls.S640CommFormLeft != 0) ? ls.S640CommFormLeft : 150;
|
|
Top = (ls.S640CommFormTop != 0) ? ls.S640CommFormTop : 150;
|
|
|
|
|
|
///
|
|
/// Set checkbox states accroding to optoHeads[i].Disabled states
|
|
///
|
|
long optoHeadsConfig = Program.LocalSettings.OptoHeadsEnabled;
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
if ((optoHeadsConfig & (1L << i)) == 0 || optoHeads[i] == null)
|
|
{
|
|
/// Opto head is disabled in configuration
|
|
checkBoxes[i].Checked = false;
|
|
checkBoxes[i].Enabled = false;
|
|
pictures[i].BackColor = DisabledColor;
|
|
messages[i].Text = Strings.Opto_head_is_disabled_in_configuration;
|
|
}
|
|
else if ((i >= ProcessData.BatchRslts.Batch.WaterMeters.Count) ||
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i] == null ||
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled)
|
|
{
|
|
/// Opto head was disabled by an operator
|
|
checkBoxes[i].Checked = false;
|
|
checkBoxes[i].Enabled = false;
|
|
pictures[i].BackColor = DisabledColor;
|
|
messages[i].Text = Strings.Head_was_disabled_by_the_user;
|
|
}
|
|
else
|
|
{
|
|
/// Opto head is enabled
|
|
checkBoxes[i].Checked = true;
|
|
checkBoxes[i].Enabled = true;
|
|
messages[i].Text = "---";
|
|
}
|
|
|
|
/// Reset opto-data indication
|
|
pictures[i].BackColor = OptoNokColor;
|
|
}
|
|
|
|
startTimeSec = StateMachine.Time;
|
|
|
|
StartActivity(0);
|
|
|
|
timer = new System.Windows.Forms.Timer();
|
|
timer.Interval = 300; // ms
|
|
timer.Tick += new EventHandler(timer_Tick);
|
|
timer.Start();
|
|
}
|
|
|
|
|
|
void Localize()
|
|
{
|
|
Text = Strings.Water_Meter_States;
|
|
closeButton.Text = Strings.CloseBtnText;
|
|
retryButton.Text = Strings.RetryBtnText;
|
|
sampleLabel1.Text = Strings.Optical_head_is_placed_correctly;
|
|
sampleLabel2.Text = Strings.Missing_opto_pulses;
|
|
samplePictureBox1.BackColor = OptoOKColor;
|
|
samplePictureBox2.BackColor = OptoNokColor;
|
|
}
|
|
|
|
|
|
void StartActivity(int activityIx)
|
|
{
|
|
startTime = DateTime.Now;
|
|
activityLabel.Text = activities[activityIx].ToString();
|
|
currentActivityIx = activityIx;
|
|
step = (activities[activityIx] == S640Activity.Start) ? Step.WatchOptoHeads : Step.SaveEndePro;
|
|
|
|
closeButton.Visible = false;
|
|
retryButton.Visible = false;
|
|
responseTextBox.Text = string.Empty;
|
|
|
|
if (step == Step.WatchOptoHeads)
|
|
{
|
|
/// Start watching optical heads --> reset OK loop counters
|
|
if (commOkLoopsCount == null || commOkLoopsCount.Length != textBoxesCount)
|
|
{
|
|
commOkLoopsCount = new int[textBoxesCount];
|
|
}
|
|
for (int i = 0; i < textBoxesCount; i++) commOkLoopsCount[i] = 0;
|
|
|
|
progressBar1.Visible = (optoDataTimeout != 0);
|
|
progressBar1.Minimum = 0;
|
|
progressBar1.Maximum = Math.Max(optoDataTimeout, 1);
|
|
progressBar1.Value = 0;
|
|
}
|
|
|
|
TBF.UiBridge.TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 10, 0, 140, 0, 0, 0 });
|
|
TBF.UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[activityIx], Progress.JustStarted));
|
|
|
|
sirtDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data
|
|
sirtDataLogger.WarnFormat("Activity = {0}", activities[activityIx]);
|
|
sirtDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Invoked every 0.5 sec.
|
|
/// </summary>
|
|
void timer_Tick(object sender, EventArgs args)
|
|
{
|
|
///--------------------------------------------------------------------------
|
|
if (step == Step.WatchOptoHeads)
|
|
{
|
|
long optoHeadsConfig = Program.LocalSettings.OptoHeadsEnabled;
|
|
|
|
bool allOK = true;
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
if ((optoHeadsConfig & (1L << i)) == 0 || optoHeads[i] == null)
|
|
{
|
|
/// Opto head is disabled in configuration
|
|
checkBoxes[i].Checked = false;
|
|
checkBoxes[i].Enabled = false;
|
|
pictures[i].BackColor = DisabledColor;
|
|
messages[i].Text = Strings.Opto_head_is_disabled_in_configuration;
|
|
}
|
|
else if (!checkBoxes[i].Checked)
|
|
{
|
|
/// Opto head was disabled by the user
|
|
pictures[i].BackColor = DisabledColor;
|
|
messages[i].Text = Strings.Head_was_disabled_by_the_user;
|
|
}
|
|
else
|
|
{
|
|
/// Opto head is enabled
|
|
checkBoxes[i].Checked = true;
|
|
checkBoxes[i].Enabled = true;
|
|
|
|
if (optoHeads[i].PcbNumber == 0)
|
|
{
|
|
/// Communication is NOK right now
|
|
pictures[i].BackColor = OptoNokColor;
|
|
messages[i].Text = "---";
|
|
commOkLoopsCount[i] = 0;
|
|
allOK = false;
|
|
}
|
|
else
|
|
{
|
|
/// Communication is OK right now
|
|
messages[i].Text = string.Format("pcb={0} radio={1}", optoHeads[i].PcbNumber, optoHeads[i].RadioAddress);
|
|
pictures[i].BackColor = OptoOKColor;
|
|
|
|
/// increment commOkLoopsCount[i] and check its value, considered OK just after 5 repeats
|
|
commOkLoopsCount[i] = commOkLoopsCount[i] + 1;
|
|
if (commOkLoopsCount[i] < 5) allOK = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (allOK)
|
|
{
|
|
log.WarnFormat("allOk");
|
|
|
|
/// Update water meter properties
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
if (i < ProcessData.BatchRslts.Batch.WaterMeters.Count &&
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i] != null &&
|
|
!ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled)
|
|
{
|
|
if ((optoHeadsConfig & (1L << i)) != 0 && checkBoxes[i].Checked && optoHeads[i] != null)
|
|
{
|
|
/// Save PCB Number of the water meter
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNr = optoHeads[i].PcbNumber.ToString(); /// PCB number (640) or body number (620)
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i].RadioAddress = optoHeads[i].RadioAddress.ToString(); /// Radio address (640)
|
|
}
|
|
else
|
|
{
|
|
/// Disable the water meter
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
step = Step.SaveStartPro;
|
|
}
|
|
else if (optoDataTimeout != 0 && DateTime.Now - startTime > new TimeSpan(0, 0, optoDataTimeout))
|
|
{
|
|
activityLabel.Text = String.Format("{0}: {1} {2}", Strings.Start, Strings.Optical_heads, Strings.Timeout);
|
|
log.Error("Start: Optical heads timeout");
|
|
step = Step.ConfirmError;
|
|
}
|
|
else if (optoDataTimeout != 0)
|
|
{
|
|
progressBar1.Value = (int)Math.Round((DateTime.Now - startTime).TotalSeconds);
|
|
}
|
|
}
|
|
///--------------------------------------------------------------------------
|
|
else if (step == Step.SaveStartPro)
|
|
{
|
|
activityLabel.Text = string.Format("Start: SIRT Communication");
|
|
|
|
int count = 0;
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
if (optoHeads[i] != null && optoHeads[i].PcbNumber != 0 && ProcessData.BatchRslts.Batch.WaterMeters[i] != null) count++;
|
|
}
|
|
|
|
log.DebugFormat("Saving '{0}' file: {1} water meters found", StartFileName, count);
|
|
if (debugLevel == DebugMode.Normal)
|
|
{
|
|
SaveProFile(Path.Combine(fileExchangePath, StartFileName), S640Activity.Start, optoHeads);
|
|
}
|
|
SaveProFile(Path.Combine(Constants.SirtLogDir,
|
|
string.Format("{0:yyMMdd-HHmmss}-b{1}-{2}", DateTime.Now, ProcessData.BatchRslts.Batch.BatchNr, StartFileName)),
|
|
S640Activity.Start, optoHeads);
|
|
|
|
savedTimestamp = DateTime.Now;
|
|
|
|
progressBar1.Visible = (fileExchangeTimeout != 0);
|
|
progressBar1.Minimum = 0;
|
|
progressBar1.Maximum = Math.Max(fileExchangeTimeout, 1);
|
|
progressBar1.Value = 0;
|
|
|
|
step = Step.AwaitResponseToStartPro;
|
|
}
|
|
///--------------------------------------------------------------------------
|
|
else if (step == Step.AwaitResponseToStartPro)
|
|
{
|
|
if (!File.Exists(Path.Combine(fileExchangePath, StartFileName)))
|
|
{
|
|
/// File disappeared in time
|
|
UpdateFirstTestResult(tests);
|
|
UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[currentActivityIx], Progress.Completed));
|
|
step = Step.Idle;
|
|
NormalClose();
|
|
}
|
|
else if (File.Exists(Path.Combine(fileExchangePath, ErrorFileName)))
|
|
{
|
|
/// Error file detected
|
|
string destination = Path.Combine(Constants.SirtLogDir,
|
|
string.Format("{0:yyMMdd-HHmmss}-b{1}-{2}", DateTime.Now, ProcessData.BatchRslts.Batch.BatchNr, ErrorFileName));
|
|
File.Move(Path.Combine(fileExchangePath, ErrorFileName), destination);
|
|
ParseFileAndDisplayErrors(destination);
|
|
File.Delete(Path.Combine(fileExchangePath, StartFileName));
|
|
activityLabel.Text = String.Format("{0}: SIRT {1}", Strings.Start, Strings.Error);
|
|
step = Step.ConfirmError;
|
|
}
|
|
else if (fileExchangeTimeout != 0 && DateTime.Now - savedTimestamp > new TimeSpan(0, 0, fileExchangeTimeout))
|
|
{
|
|
activityLabel.Text = String.Format("{0}: SIRT {1}", Strings.Start, Strings.Timeout);
|
|
log.Error("Start: SIRT timeout");
|
|
step = Step.ConfirmError;
|
|
}
|
|
else if (fileExchangeTimeout != 0)
|
|
{
|
|
progressBar1.Value = (int)Math.Round((DateTime.Now - savedTimestamp).TotalSeconds);
|
|
}
|
|
else
|
|
{
|
|
progressBar1.Visible = false;
|
|
closeButton.Visible = true;
|
|
retryButton.Visible = true;
|
|
}
|
|
}
|
|
///--------------------------------------------------------------------------
|
|
else if (step == Step.SaveEndePro)
|
|
{
|
|
activityLabel.Text = string.Format("End: SIRT Communication");
|
|
|
|
log.DebugFormat("Saving '{0}' file", EndFileName);
|
|
if (debugLevel == DebugMode.Normal)
|
|
{
|
|
SaveProFile(Path.Combine(fileExchangePath, EndFileName), S640Activity.End, optoHeads);
|
|
}
|
|
SaveProFile(Path.Combine(Constants.SirtLogDir,
|
|
string.Format("{0:yyMMdd-HHmmss}-b{1}-{2}", DateTime.Now, ProcessData.BatchRslts.Batch.BatchNr, EndFileName)),
|
|
S640Activity.Start, optoHeads);
|
|
|
|
savedTimestamp = DateTime.Now;
|
|
|
|
progressBar1.Visible = (fileExchangeTimeout != 0);
|
|
progressBar1.Minimum = 0;
|
|
progressBar1.Maximum = Math.Max(fileExchangeTimeout, 1);
|
|
progressBar1.Value = 0;
|
|
|
|
step = Step.AwaitResponseToEndePro;
|
|
}
|
|
///--------------------------------------------------------------------------
|
|
else if (step == Step.AwaitResponseToEndePro)
|
|
{
|
|
if (!File.Exists(Path.Combine(fileExchangePath, EndFileName)))
|
|
{
|
|
/// File disappeared in time
|
|
UpdateFirstTestResult(tests);
|
|
UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[currentActivityIx], Progress.Completed));
|
|
step = Step.Idle;
|
|
NormalClose();
|
|
}
|
|
else if (File.Exists(Path.Combine(fileExchangePath, ErrorFileName)))
|
|
{
|
|
/// Error.dat file detected
|
|
string destination = Path.Combine(Constants.SirtLogDir,
|
|
string.Format("{0:yyMMdd-HHmmss}-b{1}-{2}", DateTime.Now, ProcessData.BatchRslts.Batch.BatchNr, ErrorFileName));
|
|
File.Move(Path.Combine(fileExchangePath, ErrorFileName), destination);
|
|
ParseFileAndDisplayErrors(destination);
|
|
File.Delete(Path.Combine(fileExchangePath, EndFileName));
|
|
activityLabel.Text = String.Format("{0}: SIRT {1}", Strings.End, Strings.Error);
|
|
step = Step.ConfirmError;
|
|
}
|
|
else if (fileExchangeTimeout != 0 && DateTime.Now - savedTimestamp > new TimeSpan(0, 0, fileExchangeTimeout))
|
|
{
|
|
activityLabel.Text = String.Format("{0}: SIRT {1}", Strings.End, Strings.Timeout);
|
|
log.Error("End: SIRT timeout");
|
|
step = Step.ConfirmError;
|
|
}
|
|
else if (fileExchangeTimeout != 0)
|
|
{
|
|
progressBar1.Value = (int)Math.Round((DateTime.Now - savedTimestamp).TotalSeconds);
|
|
}
|
|
else
|
|
{
|
|
closeButton.Visible = true;
|
|
}
|
|
}
|
|
///--------------------------------------------------------------------------
|
|
else if (step == Step.ConfirmError)
|
|
{
|
|
progressBar1.Visible = false;
|
|
closeButton.Visible = true;
|
|
retryButton.Visible = true;
|
|
}
|
|
///--------------------------------------------------------------------------
|
|
else if (step == Step.Idle)
|
|
{
|
|
/// Just wait until this form is closed
|
|
}
|
|
else
|
|
{
|
|
/// Invalid step
|
|
log.ErrorFormat("Unexpected step: activity = {0} step = {1}", activities[currentActivityIx], step);
|
|
}
|
|
}
|
|
|
|
|
|
void SaveProFile(string filename, S640Activity activity, IList<RegisterReaders.S640Stream.S640Stream> optoHeads)
|
|
{
|
|
string variant = string.IsNullOrEmpty(ProcessData.BatchRslts.Batch.WatermetersStr) ? string.Empty : ProcessData.BatchRslts.Batch.WatermetersStr;
|
|
|
|
int count = 0;
|
|
string purchaseOrder = null;
|
|
for (int i = 0; i < optoHeads.Count; i++)
|
|
{
|
|
if (optoHeads[i] != null && optoHeads[i].PcbNumber != 0 && ProcessData.BatchRslts.Batch.WaterMeters[i] != null)
|
|
{
|
|
count++;
|
|
|
|
if (purchaseOrder == null && !string.IsNullOrEmpty(ProcessData.BatchRslts.Batch.WaterMeters[i].PurchaseOrder))
|
|
{
|
|
purchaseOrder = ProcessData.BatchRslts.Batch.WaterMeters[i].PurchaseOrder;
|
|
}
|
|
}
|
|
}
|
|
|
|
using (StreamWriter file = new StreamWriter(filename))
|
|
{
|
|
file.WriteLine("<?xml version=\"1.0\" ?>");
|
|
file.WriteLine("<Batch xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
|
|
file.WriteLine(string.Format(" <TimeStamp>{0}</TimeStamp>", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz")));
|
|
file.WriteLine(string.Format(" <Bench Mode=\"{0}\" Count=\"{1}\" TestBenchID=\"{2}\" TestBenchName=\"{3}\" EncyptionKeyMode=\"{4}\" />",
|
|
(activity == S640Activity.Start) ? "Start" : "End",
|
|
count,
|
|
ProcessData.BenchInfo.TestBenchId,
|
|
ProcessData.BenchInfo.TestBenchName,
|
|
"SensusKey"));
|
|
file.WriteLine(string.Format(" <OrderData Variantencode=\"{0}\" OrderNo=\"{1}\" ModulParameter=\"{2}\" />",
|
|
variant, (purchaseOrder != null) ? purchaseOrder : string.Empty, pPars.ModuleParameter));
|
|
file.WriteLine(" <Meters>");
|
|
for (int i = 0; i < optoHeads.Count; i++)
|
|
{
|
|
if (optoHeads[i] != null && optoHeads[i].PcbNumber != 0 && ProcessData.BatchRslts.Batch.WaterMeters[i] != null)
|
|
{
|
|
if (activity == S640Activity.Start)
|
|
{
|
|
file.WriteLine(string.Format(" <Meter RadioAddress=\"{0}\" MeterNumber=\"{0}\" CustomerText=\"\" NewRadioAddress=\"{0}\" PCBNumber=\"{1}\" EncyptionKey=\"\" />",
|
|
optoHeads[i].RadioAddress.ToString(),
|
|
optoHeads[i].PcbNumber.ToString()));
|
|
}
|
|
else if (activity == S640Activity.End)
|
|
{
|
|
file.WriteLine(string.Format(" <Meter RadioAddress=\"{0}\" MeterNumber=\"{1}\" CustomerText=\"{1}\" NewRadioAddress=\"{2}\" PCBNumber=\"{3}\" EncyptionKey=\"\" />",
|
|
optoHeads[i].RadioAddress.ToString(),
|
|
optoHeads[i].RadioAddress.ToString(), /// TODO: Here should be the assigned serial number
|
|
optoHeads[i].RadioAddress.ToString(), /// TODO: Here should be the new radio address
|
|
optoHeads[i].PcbNumber.ToString()));
|
|
}
|
|
}
|
|
}
|
|
file.WriteLine(" </Meters>");
|
|
file.WriteLine(string.Format(" <Metro Enable=\"{0}\" PulseRatePiston=\"{1}\" PulseRateLED=\"{2}\" OffsetFactor=\"{3}\" FactoryCalibration=\"{4}\" Units=\"{5}\" MeterSize=\"{6}\" OffsetTime=\"{7}\" />",
|
|
B2S(pPars.MetroEnable),
|
|
pPars.PulseRatePiston.ToString("F3", CultureInfo.InvariantCulture),
|
|
pPars.PulseRateLed.ToString(CultureInfo.InvariantCulture),
|
|
pPars.OffsetFactor.ToString(CultureInfo.InvariantCulture),
|
|
pPars.FactoryCalibration,
|
|
pPars.Units,
|
|
pPars.MeterSize,
|
|
pPars.OffsetTime));
|
|
file.WriteLine(string.Format(" <NewRead Enable=\"{0}\" NewRead=\"{1}\" />", B2S(pPars.NewReadEnable), pPars.NewRead));
|
|
file.WriteLine(string.Format(" <TransInterval Enable=\"{0}\" Interval=\"{1}\" />", B2S(pPars.TransIntervalEnable), pPars.TransInterval));
|
|
file.WriteLine(string.Format(" <LatInterval Enable=\"{0}\" Interval=\"{1}\" />", B2S(pPars.LatIntervalEnable), pPars.LatInterval));
|
|
file.WriteLine(string.Format(" <ResetAlarm Enable=\"{0}\" />", B2S(pPars.ResetAlarmEnable)));
|
|
file.WriteLine(string.Format(" <MetrologyTestMode Enable=\"{0}\" Hours=\"{1}\" />", B2S(pPars.MetrologyTestModeEnable), pPars.MetrologyTestModeHours));
|
|
file.WriteLine(string.Format(" <OpticalTeleg Enable=\"{0}\" Minutes=\"{1}\" />", B2S(pPars.OpticalTelegramEnable), pPars.OpticalTelegramMinutes));
|
|
file.WriteLine(string.Format(" <ChangeRadio Enable=\"{0}\" />", B2S(pPars.ChangeRadioEnable)));
|
|
file.WriteLine(string.Format(" <ChangeMeterID Enable=\"{0}\" />", B2S(pPars.ChangeMeterIDEnable)));
|
|
file.WriteLine(string.Format(" <SoftSeal Enable=\"false\" />", B2S(pPars.SoftSealEnable)));
|
|
file.WriteLine(string.Format(" <GoToSleep Enable=\"{0}\" />", B2S(pPars.GoToSleepEnable)));
|
|
file.WriteLine(string.Format(" <SaveDB Enable=\"{0}\" />", B2S(pPars.SaveDBEnable)));
|
|
file.WriteLine("</Batch>");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Boolean to lowercase string
|
|
/// </summary>
|
|
string B2S(bool b)
|
|
{
|
|
return b ? "true" : "false";
|
|
}
|
|
|
|
void ParseFileAndDisplayErrors(string fileName)
|
|
{
|
|
log.ErrorFormat("ParseFileAndDisplayErrors(\"{0}\")", fileName);
|
|
string message = File.ReadAllText(fileName);
|
|
responseTextBox.Text = message;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Update test result representing RFID communication success/failure
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
void UpdateFirstTestResult(IList<Config.Entities.Test> tests, bool commFailed = false)
|
|
{
|
|
DateTime endTime = DateTime.Now;
|
|
int testTime = StateMachine.Time - startTimeSec;
|
|
|
|
if (!tests.Contains(StateMachine.TestInstances[0].Test))
|
|
{
|
|
tests.Insert(0, StateMachine.TestInstances[0].Test); /// Add RFID test as the 1st item
|
|
}
|
|
|
|
foreach (var test in tests)
|
|
{
|
|
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(test.Name, test.Part);
|
|
|
|
if (tstRslt != null)
|
|
{
|
|
Results.Utils.GetCounterStates(tstRslt, Program.LocalSettings.Counters);
|
|
|
|
/// Auxiliary results ... not required
|
|
|
|
/// Main results
|
|
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
|
|
tstRslt.TestDone = true;
|
|
tstRslt.StartTime = tstRslt.Batch.StartTime;
|
|
tstRslt.EndTime = endTime;
|
|
tstRslt.FlowSetTime = 0;
|
|
tstRslt.MassOfEvapWater = 0;
|
|
tstRslt.TestTime += testTime; /// [s] total communication time of all tests
|
|
|
|
for (int i = 0; i < textBoxesCount; i++)
|
|
{
|
|
Results.Entities.MeterTestRslt meterRslt =
|
|
ProcessData.BatchRslts.GetMeterTestRslt(test.Name, i, Common.CompoundMeterId.Single);
|
|
|
|
if (meterRslt != null && (i < ProcessData.BatchRslts.Batch.WaterMeters.Count) &&
|
|
ProcessData.BatchRslts.Batch.WaterMeters[i] != null &&
|
|
!ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled)
|
|
{
|
|
if ((Program.LocalSettings.OptoHeadsEnabled & (1L << i)) != 0 &&
|
|
optoHeads[i] != null &&
|
|
!commFailed)
|
|
{
|
|
meterRslt.TestDone = true;
|
|
meterRslt.Passed = true;
|
|
}
|
|
else
|
|
{
|
|
meterRslt.TestDone = true;
|
|
meterRslt.Passed = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void closeButton_Click(object sender, EventArgs e)
|
|
{
|
|
log.Error("User is closing this form, communication failed");
|
|
UpdateFirstTestResult(tests, true);
|
|
UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[currentActivityIx], Progress.Aborted));
|
|
NormalClose();
|
|
}
|
|
|
|
private void NormalClose()
|
|
{
|
|
if (Program.LocalSettings.S640CommFormLeft != Location.X ||
|
|
Program.LocalSettings.S640CommFormTop != Location.Y)
|
|
{
|
|
/// Update local settings
|
|
Program.LocalSettings.S640CommFormLeft = Location.X;
|
|
Program.LocalSettings.S640CommFormTop = Location.Y;
|
|
Program.LocalSettings.Save();
|
|
}
|
|
|
|
formCompleted = true;
|
|
|
|
DialogResult = DialogResult.OK;
|
|
Close();
|
|
}
|
|
|
|
#region Forced close handling
|
|
|
|
public void StartForceCloseHandler()
|
|
{
|
|
UiBridge.Bridge.CloseModelessFormHandler += delegate(object sender, EventArgs args)
|
|
{
|
|
if (InvokeRequired) { Invoke(new EventHandler<EventArgs>(OnForceClose), sender, args); }
|
|
else OnForceClose(sender, args);
|
|
};
|
|
}
|
|
|
|
void OnForceClose(object sender, EventArgs args)
|
|
{
|
|
forcedClose = true;
|
|
DialogResult = DialogResult.Cancel;
|
|
Close();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void S640CommForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (!forcedClose && !formCompleted)
|
|
{
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
|
|
private void retryButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (step == Step.ConfirmError)
|
|
{
|
|
StartActivity(0);
|
|
}
|
|
}
|
|
}
|
|
}
|