Poseidon - merge project
This commit is contained in:
@@ -41,6 +41,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
|
|
||||||
|
|
||||||
System.Windows.Forms.Form modelessDlg;
|
System.Windows.Forms.Form modelessDlg;
|
||||||
|
bool modelessDialogOpening;
|
||||||
|
bool modelessDialogWaitLogged;
|
||||||
public bool Completed { get { return (modelessDlg is IHasCompleted) ? (modelessDlg as IHasCompleted).Completed : true; } }
|
public bool Completed { get { return (modelessDlg is IHasCompleted) ? (modelessDlg as IHasCompleted).Completed : true; } }
|
||||||
|
|
||||||
double refVolume;
|
double refVolume;
|
||||||
@@ -70,6 +72,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
}
|
}
|
||||||
ReadDataOp readDataOp;
|
ReadDataOp readDataOp;
|
||||||
|
|
||||||
|
// Keep the CLI phase between state-machine ticks. Blocking here prevents
|
||||||
|
// the state machine from processing a UI STOP request.
|
||||||
|
PoseidonReadPhaseRunner poseidonPhaseRunner;
|
||||||
|
List<IPoseidonReadOperation> poseidonPhaseReaders;
|
||||||
|
DateTime poseidonPhaseStartedAt;
|
||||||
|
DateTime poseidonNextProgressLogAt;
|
||||||
|
bool sendStartPhaseInitialized;
|
||||||
|
int sendStartPhaseIterations;
|
||||||
|
|
||||||
|
|
||||||
public EntryForm() { }
|
public EntryForm() { }
|
||||||
|
|
||||||
@@ -126,6 +137,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
//entryFormCfg.Direction = Direction.S640;
|
//entryFormCfg.Direction = Direction.S640;
|
||||||
//currentOp = CurrentOp.EnterTestStartStates;
|
//currentOp = CurrentOp.EnterTestStartStates;
|
||||||
this.regReaders = regReaders;
|
this.regReaders = regReaders;
|
||||||
|
log.InfoFormat("Poseidon data-entry requested START; operation={0}, batchWMs={1}, readers=[{2}]",
|
||||||
|
currentOp, waterMeters == null ? -1 : waterMeters.Count, DescribeReaders(regReaders));
|
||||||
int iterator = 0;
|
int iterator = 0;
|
||||||
foreach (IRegReader reader in regReaders)
|
foreach (IRegReader reader in regReaders)
|
||||||
{
|
{
|
||||||
@@ -167,35 +180,105 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
this.refVolume = refVolume;
|
this.refVolume = refVolume;
|
||||||
this.errLimLo = errLimLo;
|
this.errLimLo = errLimLo;
|
||||||
this.errLimHi = errLimHi;
|
this.errLimHi = errLimHi;
|
||||||
|
log.InfoFormat("Poseidon data-entry requested END; operation={0}, batchWMs={1}, refVolume={2}, errLow={3}, errHigh={4}, readers=[{5}]",
|
||||||
|
currentOp, waterMeters == null ? -1 : waterMeters.Count, refVolume, errLimLo, errLimHi,
|
||||||
|
DescribeReaders(regReaders));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate void EntryFormDlgt(EntryForm myRef);
|
delegate void EntryFormDlgt(EntryForm myRef);
|
||||||
|
|
||||||
|
string DescribeReaders(IRegReader[] readers)
|
||||||
|
{
|
||||||
|
if (readers == null) return "<null>";
|
||||||
|
|
||||||
|
var descriptions = new List<string>();
|
||||||
|
for (int index = 0; index < readers.Length; index++)
|
||||||
|
{
|
||||||
|
IRegReader reader = readers[index];
|
||||||
|
if (reader == null)
|
||||||
|
{
|
||||||
|
descriptions.Add(index + ":<null>");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoseidonReader poseidonReader = reader as PoseidonReader;
|
||||||
|
descriptions.Add(poseidonReader == null
|
||||||
|
? index + ":" + reader.GetType().Name
|
||||||
|
: string.Format("{0}:{1}(COM{2},state={3})", index, poseidonReader.Name,
|
||||||
|
poseidonReader.ComPortNr, poseidonReader.CurrentOp));
|
||||||
|
}
|
||||||
|
return string.Join("; ", descriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
int EnabledWaterMetersCount()
|
||||||
|
{
|
||||||
|
if (disabled == null) return TBF.Data.WMsCount;
|
||||||
|
int count = 0;
|
||||||
|
for (int index = 0; index < disabled.Length; index++)
|
||||||
|
if (!disabled[index]) count++;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
///
|
///
|
||||||
void OpenBeginningDlg(EntryForm myRef)
|
void OpenBeginningDlg(EntryForm myRef)
|
||||||
{
|
{
|
||||||
if (ShowForm == 0)
|
if (ShowForm == 0)
|
||||||
return;
|
return;
|
||||||
|
log.DebugFormat("Poseidon data-entry: creating CycleBeginningForm; configuredWMs={0}, batchWMs={1}",
|
||||||
|
TBF.Data.WMsCount, waterMeters == null ? -1 : waterMeters.Count);
|
||||||
myRef.modelessDlg = new CycleBeginningForm(TBF.Data.WMsCount, myRef.entryFormCfg,
|
myRef.modelessDlg = new CycleBeginningForm(TBF.Data.WMsCount, myRef.entryFormCfg,
|
||||||
ProcessData.SelectedProcedure.OrderInfo != null ? ProcessData.SelectedProcedure.OrderInfo.POName : string.Empty);
|
ProcessData.SelectedProcedure.OrderInfo != null ? ProcessData.SelectedProcedure.OrderInfo.POName : string.Empty);
|
||||||
(myRef.modelessDlg as CycleBeginningForm)?.AutoClickOkAfterDelay();
|
(myRef.modelessDlg as CycleBeginningForm)?.AutoClickOkAfterDelay();
|
||||||
modelessDlg.Show();
|
modelessDlg.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The state machine runs on a worker thread. A synchronous Invoke can
|
||||||
|
// deadlock it while the UI is waiting for the next state-machine tick.
|
||||||
|
void BeginOpenDialog(string dialogName, EntryFormDlgt openDialog)
|
||||||
|
{
|
||||||
|
modelessDialogOpening = true;
|
||||||
|
modelessDialogWaitLogged = false;
|
||||||
|
log.InfoFormat("Poseidon data-entry: queueing dialog={0}, operation={1}, showForm={2}, readers=[{3}]",
|
||||||
|
dialogName, currentOp, ShowForm, DescribeReaders(regReaders));
|
||||||
|
Program.MainWnd.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log.DebugFormat("Poseidon data-entry: opening dialog={0}, operation={1}", dialogName, currentOp);
|
||||||
|
openDialog(this);
|
||||||
|
log.InfoFormat("Poseidon data-entry: dialog opened={0}, operation={1}, formType={2}",
|
||||||
|
dialogName, currentOp, modelessDlg == null ? "<null>" : modelessDlg.GetType().Name);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
modelessDialogOpening = false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
///
|
///
|
||||||
void OpenTestStartStatesDlg(EntryForm myRef)
|
void OpenTestStartStatesDlg(EntryForm myRef)
|
||||||
{
|
{
|
||||||
if (ShowForm == 0)
|
if (ShowForm == 0)
|
||||||
return;
|
return;
|
||||||
|
log.DebugFormat("Poseidon data-entry: creating TestStartEndForm START; configuredWMs={0}, enabledWMs={1}, batchWMs={2}, readers=[{3}]",
|
||||||
|
TBF.Data.WMsCount, EnabledWaterMetersCount(), waterMeters == null ? -1 : waterMeters.Count, DescribeReaders(regReaders));
|
||||||
myRef.modelessDlg = new TestStartEndForm(myRef.waterMeters.Count, myRef.regReaders, disabled);
|
myRef.modelessDlg = new TestStartEndForm(myRef.waterMeters.Count, myRef.regReaders, disabled);
|
||||||
modelessDlg.Show();
|
modelessDlg.Show();
|
||||||
|
log.DebugFormat("Poseidon data-entry: TestStartEndForm START visible={0}, handleCreated={1}",
|
||||||
|
modelessDlg.Visible, modelessDlg.IsHandleCreated);
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
void OpenTestEndStatesDlg(EntryForm myRef)
|
void OpenTestEndStatesDlg(EntryForm myRef)
|
||||||
{
|
{
|
||||||
if (ShowForm == 0)
|
if (ShowForm == 0)
|
||||||
return;
|
return;
|
||||||
|
log.DebugFormat("Poseidon data-entry: creating TestStartEndForm END; configuredWMs={0}, enabledWMs={1}, batchWMs={2}, refVolume={3}, errLow={4}, errHigh={5}, readers=[{6}]",
|
||||||
|
TBF.Data.WMsCount, EnabledWaterMetersCount(), waterMeters == null ? -1 : waterMeters.Count,
|
||||||
|
refVolume, errLimLo, errLimHi, DescribeReaders(regReaders));
|
||||||
myRef.modelessDlg = new TestStartEndForm(TBF.Data.WMsCount, myRef.regReaders, wmStartStateStr, disabled, refVolume, errLimLo, errLimHi);
|
myRef.modelessDlg = new TestStartEndForm(TBF.Data.WMsCount, myRef.regReaders, wmStartStateStr, disabled, refVolume, errLimLo, errLimHi);
|
||||||
modelessDlg.Show();
|
modelessDlg.Show();
|
||||||
|
log.DebugFormat("Poseidon data-entry: TestStartEndForm END visible={0}, handleCreated={1}",
|
||||||
|
modelessDlg.Visible, modelessDlg.IsHandleCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Start this operation</summary>
|
/// <summary>Start this operation</summary>
|
||||||
@@ -204,6 +287,12 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
readDataOp = ReadDataOp.None;
|
readDataOp = ReadDataOp.None;
|
||||||
readAndSetDataToMeters = false;
|
readAndSetDataToMeters = false;
|
||||||
filedDataToMeters = false;
|
filedDataToMeters = false;
|
||||||
|
poseidonPhaseRunner = null;
|
||||||
|
poseidonPhaseReaders = null;
|
||||||
|
sendStartPhaseInitialized = false;
|
||||||
|
sendStartPhaseIterations = 0;
|
||||||
|
modelessDialogOpening = false;
|
||||||
|
modelessDialogWaitLogged = false;
|
||||||
|
|
||||||
if (ShowForm == 0)
|
if (ShowForm == 0)
|
||||||
return ;
|
return ;
|
||||||
@@ -215,7 +304,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
//ReadAndSetDataToMeters();
|
//ReadAndSetDataToMeters();
|
||||||
if (ProcessData.SelectedProcedure.OrderInfo == null)
|
if (ProcessData.SelectedProcedure.OrderInfo == null)
|
||||||
{
|
{
|
||||||
Program.MainWnd.Invoke(new EntryFormDlgt(OpenBeginningDlg), this);
|
BeginOpenDialog("CycleBeginningForm", OpenBeginningDlg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -225,10 +314,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CurrentOp.ReadDatastream_StartStates:
|
case CurrentOp.ReadDatastream_StartStates:
|
||||||
Program.MainWnd.Invoke(new EntryFormDlgt(OpenTestStartStatesDlg), this);
|
BeginOpenDialog("TestStartEndForm.START", OpenTestStartStatesDlg);
|
||||||
break;
|
break;
|
||||||
case CurrentOp.ReadDatastream_EndStates:
|
case CurrentOp.ReadDatastream_EndStates:
|
||||||
Program.MainWnd.Invoke(new EntryFormDlgt(OpenTestEndStatesDlg), this);
|
BeginOpenDialog("TestStartEndForm.END", OpenTestEndStatesDlg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,6 +329,17 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
/// <returns>Event.ResultsPrinted</returns>
|
/// <returns>Event.ResultsPrinted</returns>
|
||||||
public Event Run()
|
public Event Run()
|
||||||
{
|
{
|
||||||
|
if (modelessDialogOpening)
|
||||||
|
{
|
||||||
|
if (!modelessDialogWaitLogged)
|
||||||
|
{
|
||||||
|
log.WarnFormat("Poseidon data-entry: state machine waiting for dialog open; operation={0}, readers=[{1}]",
|
||||||
|
currentOp, DescribeReaders(regReaders));
|
||||||
|
modelessDialogWaitLogged = true;
|
||||||
|
}
|
||||||
|
return Event.ModelessFormIsOpen;
|
||||||
|
}
|
||||||
|
|
||||||
if (!readAndSetDataToMeters) // run until not finished
|
if (!readAndSetDataToMeters) // run until not finished
|
||||||
readAndSetDataToMeters = ReadAndSetDataToMeters();
|
readAndSetDataToMeters = ReadAndSetDataToMeters();
|
||||||
|
|
||||||
@@ -352,7 +452,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultSaved = true;
|
resultSaved = true;
|
||||||
modelessDlg = null;
|
modelessDlg = null;
|
||||||
|
modelessDialogOpening = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Event.ModelessFormClosed; /// Form closed
|
return Event.ModelessFormClosed; /// Form closed
|
||||||
@@ -369,6 +470,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
currentOp = CurrentOp.None;
|
currentOp = CurrentOp.None;
|
||||||
readAndSetDataToMeters = false;
|
readAndSetDataToMeters = false;
|
||||||
filedDataToMeters = false;
|
filedDataToMeters = false;
|
||||||
|
sendStartPhaseInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ShowForm
|
public int ShowForm
|
||||||
@@ -389,93 +491,108 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
bool bOperationSuccess = false;
|
bool bOperationSuccess = false;
|
||||||
if (currentOp == CurrentOp.SendStartDataStream)
|
if (currentOp == CurrentOp.SendStartDataStream)
|
||||||
{
|
{
|
||||||
bool finishedReading = regReaders == null; // we can work only with register readers
|
if (!sendStartPhaseInitialized)
|
||||||
while (!finishedReading) //TODO BUMI lock - fuck ?
|
|
||||||
{
|
{
|
||||||
bool bAllReadersFinished = true;
|
sendStartPhaseInitialized = true;
|
||||||
foreach (var iRegReader in regReaders )
|
sendStartPhaseIterations = 0;
|
||||||
|
poseidonPhaseStartedAt = DateTime.UtcNow;
|
||||||
|
poseidonNextProgressLogAt = poseidonPhaseStartedAt.AddSeconds(5);
|
||||||
|
log.InfoFormat("Poseidon send-start phase started; readers=[{0}]", DescribeReaders(regReaders));
|
||||||
|
if (regReaders != null)
|
||||||
{
|
{
|
||||||
if (iRegReader is PoseidonReader)
|
foreach (IRegReader regReader in regReaders)
|
||||||
{
|
{
|
||||||
PoseidonReader poseidonReader = (iRegReader as PoseidonReader);
|
PoseidonReader poseidonReader = regReader as PoseidonReader;
|
||||||
|
if (poseidonReader == null) continue;
|
||||||
poseidonReader.SetCliLogging(CliLogging);
|
poseidonReader.SetCliLogging(CliLogging);
|
||||||
|
poseidonReader.SetCurrentOp(PoseidonReader.CurrentPoseidonOp.SendStartDataStream);
|
||||||
if (poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.SendStartDataStream_Done
|
log.DebugFormat("Poseidon send-start: armed reader={0}, COM={1}, state={2}",
|
||||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.SendStartDataStream_Runing)
|
poseidonReader.Name, poseidonReader.ComPortNr, poseidonReader.CurrentOp);
|
||||||
{
|
|
||||||
poseidonReader.SetCurrentOp(PoseidonReader.CurrentPoseidonOp.SendStartDataStream);
|
|
||||||
}
|
|
||||||
/// Send start data stream
|
|
||||||
poseidonReader.Run();
|
|
||||||
readDataOp = ReadDataOp.Start;
|
|
||||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|
|
||||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
|
||||||
{
|
|
||||||
bAllReadersFinished = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Wait for all readers to finish
|
|
||||||
if (bAllReadersFinished)
|
|
||||||
{
|
|
||||||
finishedReading = true;
|
|
||||||
readDataOp = ReadDataOp.Done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
System.Threading.Thread.Sleep(10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bOperationSuccess = true;
|
sendStartPhaseIterations++;
|
||||||
|
bool allReadersFinished = true;
|
||||||
|
if (regReaders != null)
|
||||||
|
{
|
||||||
|
foreach (IRegReader regReader in regReaders)
|
||||||
|
{
|
||||||
|
PoseidonReader poseidonReader = regReader as PoseidonReader;
|
||||||
|
if (poseidonReader == null) continue;
|
||||||
|
poseidonReader.Run();
|
||||||
|
readDataOp = ReadDataOp.Start;
|
||||||
|
if (poseidonReader.CurrentOp != PoseidonReader.CurrentPoseidonOp.Done
|
||||||
|
&& poseidonReader.CurrentOp != PoseidonReader.CurrentPoseidonOp.Error)
|
||||||
|
allReadersFinished = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allReadersFinished)
|
||||||
|
{
|
||||||
|
readDataOp = ReadDataOp.Done;
|
||||||
|
log.InfoFormat("Poseidon send-start phase completed; iterations={0}, elapsedMs={1}",
|
||||||
|
sendStartPhaseIterations, (long)(DateTime.UtcNow - poseidonPhaseStartedAt).TotalMilliseconds);
|
||||||
|
sendStartPhaseInitialized = false;
|
||||||
|
bOperationSuccess = true;
|
||||||
|
}
|
||||||
|
else if (DateTime.UtcNow >= poseidonNextProgressLogAt)
|
||||||
|
{
|
||||||
|
log.WarnFormat("Poseidon send-start phase waiting; iterations={0}, elapsedMs={1}, readers=[{2}]",
|
||||||
|
sendStartPhaseIterations, (long)(DateTime.UtcNow - poseidonPhaseStartedAt).TotalMilliseconds,
|
||||||
|
DescribeReaders(regReaders));
|
||||||
|
poseidonNextProgressLogAt = DateTime.UtcNow.AddSeconds(5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ((currentOp == CurrentOp.ReadDatastream_StartStates)
|
else if ((currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||||
|| (currentOp == CurrentOp.ReadDatastream_EndStates))
|
|| (currentOp == CurrentOp.ReadDatastream_EndStates))
|
||||||
{
|
{
|
||||||
bool finishedReading = regReaders == null; // we can work only with register readers
|
if (poseidonPhaseRunner == null)
|
||||||
while (!finishedReading) //TODO BUMI lock - fuck ?
|
|
||||||
{
|
{
|
||||||
bool bAllReadersFinished = true;
|
poseidonPhaseReaders = new List<IPoseidonReadOperation>();
|
||||||
foreach (var iRegReader in regReaders )
|
if (regReaders != null)
|
||||||
{
|
{
|
||||||
if (iRegReader is PoseidonReader)
|
foreach (IRegReader regReader in regReaders)
|
||||||
{
|
{
|
||||||
PoseidonReader poseidonReader = (iRegReader as PoseidonReader);
|
PoseidonReader poseidonReader = regReader as PoseidonReader;
|
||||||
if(poseidonReader == null)
|
if (poseidonReader == null) continue;
|
||||||
continue;
|
|
||||||
poseidonReader.SetCliLogging(CliLogging);
|
poseidonReader.SetCliLogging(CliLogging);
|
||||||
// A terminal reader must not be armed again. Re-starting Error/Done
|
poseidonPhaseReaders.Add(new PoseidonReaderOperation(poseidonReader));
|
||||||
// launched the CLI on every polling iteration and kept the dialog loading.
|
|
||||||
if (poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.None)
|
|
||||||
{
|
|
||||||
log.DebugFormat("Poseidon read: starting {0} for {1}", currentOp, poseidonReader.Name);
|
|
||||||
poseidonReader.SetCurrentOp((currentOp == CurrentOp.ReadDatastream_StartStates)?
|
|
||||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start :
|
|
||||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
|
||||||
}
|
|
||||||
/// Send start data stream
|
|
||||||
poseidonReader.Run();
|
|
||||||
if (poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error)
|
|
||||||
log.ErrorFormat("Poseidon read: {0} completed with Error during {1}", poseidonReader.Name, currentOp);
|
|
||||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|
|
||||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
|
||||||
{
|
|
||||||
bAllReadersFinished = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bAllReadersFinished)
|
poseidonPhaseRunner = new PoseidonReadPhaseRunner(
|
||||||
{
|
currentOp == CurrentOp.ReadDatastream_StartStates);
|
||||||
log.DebugFormat("Poseidon read: all readers finished for {0}", currentOp);
|
poseidonPhaseStartedAt = DateTime.UtcNow;
|
||||||
finishedReading = true;
|
poseidonNextProgressLogAt = poseidonPhaseStartedAt.AddSeconds(5);
|
||||||
}
|
log.InfoFormat("Poseidon phase started: phase={0}, readers={1}, detail=[{2}]",
|
||||||
else
|
currentOp, poseidonPhaseReaders.Count, DescribeReaders(regReaders));
|
||||||
{
|
|
||||||
System.Threading.Thread.Sleep(10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bOperationSuccess = true;
|
bool allReadersFinished = poseidonPhaseRunner.RunIteration(poseidonPhaseReaders);
|
||||||
|
foreach (IPoseidonReadOperation poseidonReader in poseidonPhaseReaders)
|
||||||
|
if (poseidonReader.HasError)
|
||||||
|
log.ErrorFormat("Poseidon read: {0} completed with Error during {1}", poseidonReader.Name, currentOp);
|
||||||
|
|
||||||
|
if (allReadersFinished)
|
||||||
|
{
|
||||||
|
log.InfoFormat("Poseidon phase completed: phase={0}, iterations={1}, elapsedMs={2}",
|
||||||
|
currentOp, poseidonPhaseRunner.IterationCount,
|
||||||
|
(long)(DateTime.UtcNow - poseidonPhaseStartedAt).TotalMilliseconds);
|
||||||
|
poseidonPhaseRunner = null;
|
||||||
|
poseidonPhaseReaders = null;
|
||||||
|
bOperationSuccess = true;
|
||||||
|
}
|
||||||
|
else if (DateTime.UtcNow >= poseidonNextProgressLogAt)
|
||||||
|
{
|
||||||
|
var pendingReaders = new List<string>();
|
||||||
|
foreach (IPoseidonReadOperation poseidonReader in poseidonPhaseReaders)
|
||||||
|
if (!poseidonReader.IsFinished) pendingReaders.Add(poseidonReader.Name);
|
||||||
|
log.WarnFormat("Poseidon phase waiting: phase={0}, iterations={1}, elapsedMs={2}, pending={3}",
|
||||||
|
currentOp, poseidonPhaseRunner.IterationCount,
|
||||||
|
(long)(DateTime.UtcNow - poseidonPhaseStartedAt).TotalMilliseconds,
|
||||||
|
string.Join(",", pendingReaders));
|
||||||
|
poseidonNextProgressLogAt = DateTime.UtcNow.AddSeconds(5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bOperationSuccess;
|
return bOperationSuccess;
|
||||||
|
|||||||
@@ -300,6 +300,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
|
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
|
||||||
{
|
{
|
||||||
|
log?.Debug($"CLI queued: file='{fileName}', args='{args}'");
|
||||||
ResetStartTime();
|
ResetStartTime();
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
@@ -334,6 +335,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
log?.Debug($"CLI starting: file='{psi.FileName}', args='{psi.Arguments}', workingDirectory='{psi.WorkingDirectory}', exists={System.IO.File.Exists(psi.FileName)}");
|
||||||
process.Start();
|
process.Start();
|
||||||
|
|
||||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||||
@@ -363,6 +365,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
info.StandardError = stderrTask.Result ?? "";
|
info.StandardError = stderrTask.Result ?? "";
|
||||||
string allOutput = info.StandardOutput + info.StandardError;
|
string allOutput = info.StandardOutput + info.StandardError;
|
||||||
log?.Debug(allOutput);
|
log?.Debug(allOutput);
|
||||||
|
log?.Debug($"CLI completed: name='{info.Name}', exitCode={info.ExitCode}, stdoutLength={info.StandardOutput.Length}, stderrLength={info.StandardError.Length}");
|
||||||
|
|
||||||
if (info.ExitCode != 0)
|
if (info.ExitCode != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,4 +46,39 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
return allReadersFinished;
|
return allReadersFinished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Owns one dialog phase (START or STOP). A reader is armed once per phase,
|
||||||
|
/// independently of its terminal state from a preceding phase.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PoseidonReadPhaseRunner
|
||||||
|
{
|
||||||
|
private readonly bool readStart;
|
||||||
|
private readonly HashSet<IPoseidonReadOperation> startedReaders =
|
||||||
|
new HashSet<IPoseidonReadOperation>();
|
||||||
|
|
||||||
|
public int IterationCount { get; private set; }
|
||||||
|
|
||||||
|
public PoseidonReadPhaseRunner(bool readStart)
|
||||||
|
{
|
||||||
|
this.readStart = readStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RunIteration(IEnumerable<IPoseidonReadOperation> readers)
|
||||||
|
{
|
||||||
|
if (readers == null) return true;
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
bool allReadersFinished = true;
|
||||||
|
foreach (IPoseidonReadOperation reader in readers)
|
||||||
|
{
|
||||||
|
if (reader == null) continue;
|
||||||
|
if (startedReaders.Add(reader)) reader.Start(readStart);
|
||||||
|
reader.Run();
|
||||||
|
if (!reader.IsFinished) allReadersFinished = false;
|
||||||
|
}
|
||||||
|
return allReadersFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,9 +294,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
if ((DebugLevel == DebugMode.Normal)||(DebugLevel == DebugMode.Simulate))
|
if ((DebugLevel == DebugMode.Normal)||(DebugLevel == DebugMode.Simulate))
|
||||||
{
|
{
|
||||||
/// Prepare serial port
|
/// Prepare serial port
|
||||||
serialPort = new SerialPortData(string.Format("COM{0}", registerReaderCfg.ComPortNr),
|
if (registerReaderCfg.MeterType <= 0)
|
||||||
registerReaderCfg.CliFileName,
|
{
|
||||||
registerReaderCfg.MeterType);
|
log.WarnFormat(
|
||||||
|
"{0}: configured Poseidon MeterType={1}; using CLI default MeterType={2}.",
|
||||||
|
Name,
|
||||||
|
registerReaderCfg.MeterType,
|
||||||
|
SerialPortData.DefaultPoseidonMeterType);
|
||||||
|
}
|
||||||
|
serialPort = new SerialPortData(string.Format("COM{0}", registerReaderCfg.ComPortNr),
|
||||||
|
registerReaderCfg.CliFileName,
|
||||||
|
registerReaderCfg.MeterType);
|
||||||
|
|
||||||
|
|
||||||
//TODO BUMI prepare serial port - for us do nothing
|
//TODO BUMI prepare serial port - for us do nothing
|
||||||
@@ -438,6 +446,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||||
incommingTime = CliRunner.IncommingTime;
|
incommingTime = CliRunner.IncommingTime;
|
||||||
|
log.DebugFormat("{0}: CLI task completed for {1}; incomingTime={2}", Name,
|
||||||
|
_isReadingStart ? "START" : "STOP", incommingTime);
|
||||||
}
|
}
|
||||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||||
{
|
{
|
||||||
@@ -445,6 +455,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||||
incommingTime = CliRunner.IncommingTime;
|
incommingTime = CliRunner.IncommingTime;
|
||||||
|
log.ErrorFormat("{0}: CLI timeout for {1}; timeoutMs={2}", Name,
|
||||||
|
_isReadingStart ? "START" : "STOP", SafetyTimeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Event.Busy;
|
return Event.Busy;
|
||||||
@@ -468,6 +480,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
lastCliReadFailureReason = _lastOpTimedOut
|
||||||
|
? "CLI read timed out."
|
||||||
|
: "No completed JsonDataFromPoseidon task was available.";
|
||||||
|
log.ErrorFormat("{0}: Poseidon {1} read failed: {2}", Name,
|
||||||
|
_isReadingStart ? "START" : "STOP", lastCliReadFailureReason);
|
||||||
if (_lastOpTimedOut)
|
if (_lastOpTimedOut)
|
||||||
{
|
{
|
||||||
log.Warn($"PoseidonReader {Name}: ReadDatastream timed out, no completed result available.");
|
log.Warn($"PoseidonReader {Name}: ReadDatastream timed out, no completed result available.");
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
public class SerialPortData
|
public class SerialPortData
|
||||||
{
|
{
|
||||||
public const string CliDirectory = @"C:\TBF\Cli";
|
public const string CliDirectory = @"C:\TBF\Cli";
|
||||||
|
// HatCliDemo identifies Poseidon with the numeric meter type 74.
|
||||||
|
// Older persisted configurations can contain the uninitialized value 0.
|
||||||
|
public const int DefaultPoseidonMeterType = 74;
|
||||||
|
|
||||||
private Boolean? _cliExists;
|
private Boolean? _cliExists;
|
||||||
public bool CliExists { get {
|
public bool CliExists { get {
|
||||||
@@ -30,6 +33,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
public string PortName { get; set; }
|
public string PortName { get; set; }
|
||||||
public int MeterType { get; set; }
|
public int MeterType { get; set; }
|
||||||
|
|
||||||
|
public static int NormalizeMeterType(int meterType)
|
||||||
|
{
|
||||||
|
return meterType > 0 ? meterType : DefaultPoseidonMeterType;
|
||||||
|
}
|
||||||
|
|
||||||
public enum EMeterArg {
|
public enum EMeterArg {
|
||||||
Calibration = 0,
|
Calibration = 0,
|
||||||
AllParams = 2,
|
AllParams = 2,
|
||||||
@@ -59,7 +67,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
PortName = portName;
|
PortName = portName;
|
||||||
CmdClientName = cmdClientName;
|
CmdClientName = cmdClientName;
|
||||||
MeterType = meterType;
|
MeterType = NormalizeMeterType(meterType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,6 +246,17 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SerialPortData_ZeroMeterType_UsesPoseidonCliDefault()
|
||||||
|
{
|
||||||
|
var serialPort = new SerialPortData("COM3", "HatCliDemo.exe", 0);
|
||||||
|
|
||||||
|
Assert.AreEqual(SerialPortData.DefaultPoseidonMeterType, serialPort.MeterType);
|
||||||
|
Assert.AreEqual(
|
||||||
|
"-p COM3 -m 74 --operation readall",
|
||||||
|
serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task CliProcess_ExitErrorWithoutJson_RecordsDiagnosticsAndReturnsNoReading()
|
public async Task CliProcess_ExitErrorWithoutJson_RecordsDiagnosticsAndReturnsNoReading()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,27 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
foreach (FakeReader reader in readers) Assert.AreEqual(1, reader.StartCount, reader.Name);
|
foreach (FakeReader reader in readers) Assert.AreEqual(1, reader.StartCount, reader.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void StartThenStop_PhasesArmTheSameReaderOncePerPhase()
|
||||||
|
{
|
||||||
|
var reader = new FakeReader("Pos1", 1);
|
||||||
|
var readers = new List<IPoseidonReadOperation> { reader };
|
||||||
|
var startPhase = new PoseidonReadPhaseRunner(true);
|
||||||
|
|
||||||
|
// START phase completes.
|
||||||
|
startPhase.RunIteration(readers);
|
||||||
|
startPhase.RunIteration(readers);
|
||||||
|
Assert.AreEqual(CmdPoseidonReader.CurrentPoseidonOp.Done, reader.CurrentOp);
|
||||||
|
|
||||||
|
// A new STOP phase re-arms the terminal reader exactly once.
|
||||||
|
var stopPhase = new PoseidonReadPhaseRunner(false);
|
||||||
|
stopPhase.RunIteration(readers);
|
||||||
|
stopPhase.RunIteration(readers);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, reader.StartCount);
|
||||||
|
Assert.AreEqual(CmdPoseidonReader.CurrentPoseidonOp.Done, reader.CurrentOp);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void InputJson_ZeroReading_WithDecimalCommaOrDot_IsValid()
|
public void InputJson_ZeroReading_WithDecimalCommaOrDot_IsValid()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user