Poseidon move from feature/morisville/fix_cli_timeout
This commit is contained in:
parent
e4d4d75642
commit
8d42232589
@ -444,15 +444,19 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
if(poseidonReader == null)
|
if(poseidonReader == null)
|
||||||
continue;
|
continue;
|
||||||
poseidonReader.SetCliLogging(CliLogging);
|
poseidonReader.SetCliLogging(CliLogging);
|
||||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Done
|
// A terminal reader must not be armed again. Re-starting Error/Done
|
||||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Running))
|
// 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.SetCurrentOp((currentOp == CurrentOp.ReadDatastream_StartStates)?
|
||||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start :
|
PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start :
|
||||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
||||||
}
|
}
|
||||||
/// Send start data stream
|
/// Send start data stream
|
||||||
poseidonReader.Run();
|
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
|
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|
||||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
||||||
{
|
{
|
||||||
@ -462,6 +466,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
|||||||
}
|
}
|
||||||
if (bAllReadersFinished)
|
if (bAllReadersFinished)
|
||||||
{
|
{
|
||||||
|
log.DebugFormat("Poseidon read: all readers finished for {0}", currentOp);
|
||||||
finishedReading = true;
|
finishedReading = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -222,6 +222,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = args,
|
Arguments = args,
|
||||||
|
WorkingDirectory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(fileName)),
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
@ -258,9 +259,18 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
|
info.ExitCode = process.ExitCode;
|
||||||
|
info.StandardOutput = stdOutTask.Result ?? "";
|
||||||
|
info.StandardError = stdErrTask.Result ?? "";
|
||||||
|
string allOutput = info.StandardOutput + info.StandardError;
|
||||||
log?.Debug(allOutput);
|
log?.Debug(allOutput);
|
||||||
|
|
||||||
|
if (info.ExitCode != 0)
|
||||||
|
{
|
||||||
|
info.FailureReason = $"CLI exited with exit code {info.ExitCode}.";
|
||||||
|
log?.Error($"{info.Name}: {info.FailureReason} stderr='{info.StandardError}'");
|
||||||
|
}
|
||||||
|
|
||||||
info.State = CliTaskState.Completed;
|
info.State = CliTaskState.Completed;
|
||||||
return allOutput;
|
return allOutput;
|
||||||
}
|
}
|
||||||
@ -311,6 +321,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = args,
|
Arguments = args,
|
||||||
|
WorkingDirectory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(fileName)),
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
@ -347,9 +358,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
|
info.ExitCode = process.ExitCode;
|
||||||
|
info.StandardOutput = stdoutTask.Result ?? "";
|
||||||
|
info.StandardError = stderrTask.Result ?? "";
|
||||||
|
string allOutput = info.StandardOutput + info.StandardError;
|
||||||
log?.Debug(allOutput);
|
log?.Debug(allOutput);
|
||||||
|
|
||||||
|
if (info.ExitCode != 0)
|
||||||
|
{
|
||||||
|
info.FailureReason = $"CLI exited with exit code {info.ExitCode}.";
|
||||||
|
log?.Error($"{info.Name}: {info.FailureReason} stderr='{info.StandardError}'");
|
||||||
|
info.State = CliTaskState.Completed;
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
string json = ExtractJson(allOutput);
|
string json = ExtractJson(allOutput);
|
||||||
T result;
|
T result;
|
||||||
if (TryJsonStringDeserialize(json, out result))
|
if (TryJsonStringDeserialize(json, out result))
|
||||||
@ -358,6 +380,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info.FailureReason = "CLI completed without a valid JSON response.";
|
||||||
|
log?.Error($"{info.Name}: {info.FailureReason} stdout='{info.StandardOutput}' stderr='{info.StandardError}'");
|
||||||
info.State = CliTaskState.Completed;
|
info.State = CliTaskState.Completed;
|
||||||
return default(T);
|
return default(T);
|
||||||
}
|
}
|
||||||
@ -380,18 +404,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
public bool TryJsonStringDeserialize<T>(string json, out T value) where T : new()
|
public bool TryJsonStringDeserialize<T>(string json, out T value) where T : new()
|
||||||
{
|
{
|
||||||
if (json != null)
|
if (!string.IsNullOrWhiteSpace(json))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
value = JsonConvert.DeserializeObject<T>(json);
|
value = JsonConvert.DeserializeObject<T>(json);
|
||||||
return true;
|
return value != null;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log?.Debug(ex.Message);
|
log?.Debug(ex.Message);
|
||||||
value = TryConvert<T>(json);
|
return TryConvert(json, out value);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +422,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T TryConvert<T>(string json) where T : new()
|
private static bool TryConvert<T>(string json, out T value) where T : new()
|
||||||
{
|
{
|
||||||
T obj = new T();
|
T obj = new T();
|
||||||
|
|
||||||
@ -417,21 +440,24 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
object value = token.ToObject(prop.PropertyType);
|
object propertyValue = token.ToObject(prop.PropertyType);
|
||||||
prop.SetValue(obj, value);
|
prop.SetValue(obj, propertyValue);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value = obj;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||||
|
value = default(T);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ExtractJson(string text)
|
public string ExtractJson(string text)
|
||||||
|
|||||||
@ -11,6 +11,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
public Process Process { get; set; }
|
public Process Process { get; set; }
|
||||||
public CliTaskState State { get; set; } = CliTaskState.Running;
|
public CliTaskState State { get; set; } = CliTaskState.Running;
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public int? ExitCode { get; set; }
|
||||||
|
public string StandardOutput { get; set; }
|
||||||
|
public string StandardError { get; set; }
|
||||||
|
public string FailureReason { get; set; }
|
||||||
|
|
||||||
public bool UseResult
|
public bool UseResult
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using TBF.Rig;
|
||||||
|
|
||||||
|
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||||
|
{
|
||||||
|
public interface IPoseidonReadOperation
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
bool IsNotStarted { get; }
|
||||||
|
bool IsFinished { get; }
|
||||||
|
bool HasError { get; }
|
||||||
|
void Start(bool readStart);
|
||||||
|
Event Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PoseidonReaderOperation : IPoseidonReadOperation
|
||||||
|
{
|
||||||
|
private readonly PoseidonReader reader;
|
||||||
|
public PoseidonReaderOperation(PoseidonReader reader)
|
||||||
|
{
|
||||||
|
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
public string Name { get { return reader.Name; } }
|
||||||
|
public bool IsNotStarted { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.None; } }
|
||||||
|
public bool IsFinished { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done || reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error; } }
|
||||||
|
public bool HasError { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error; } }
|
||||||
|
public void Start(bool readStart) { reader.SetCurrentOp(readStart ? PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start : PoseidonReader.CurrentPoseidonOp.ReadDataStream_End); }
|
||||||
|
public Event Run() { return reader.Run(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PoseidonReadCycle
|
||||||
|
{
|
||||||
|
public static bool RunIteration(IEnumerable<IPoseidonReadOperation> readers, bool readStart)
|
||||||
|
{
|
||||||
|
if (readers == null) return true;
|
||||||
|
bool allReadersFinished = true;
|
||||||
|
foreach (IPoseidonReadOperation reader in readers)
|
||||||
|
{
|
||||||
|
if (reader == null) continue;
|
||||||
|
if (reader.IsNotStarted) reader.Start(readStart);
|
||||||
|
reader.Run();
|
||||||
|
if (!reader.IsFinished) allReadersFinished = false;
|
||||||
|
}
|
||||||
|
return allReadersFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@
|
|||||||
///
|
///
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@ -62,12 +63,19 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
CurrentPoseidonOp _currentOp;
|
CurrentPoseidonOp _currentOp;
|
||||||
private bool _isReadingStart = true;
|
private bool _isReadingStart = true;
|
||||||
private bool? _isCliLogging;
|
private bool? _isCliLogging;
|
||||||
|
private bool lastCliReadingParsed;
|
||||||
|
private string lastCliReadFailureReason;
|
||||||
|
private bool lastCliReadSucceeded;
|
||||||
|
|
||||||
public CurrentPoseidonOp CurrentOp
|
public CurrentPoseidonOp CurrentOp
|
||||||
{
|
{
|
||||||
get { return _currentOp; }
|
get { return _currentOp; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool LastCliReadingParsed { get { return lastCliReadingParsed; } }
|
||||||
|
public string LastCliReadFailureReason { get { return lastCliReadFailureReason; } }
|
||||||
|
public bool LastCliReadSucceeded { get { return lastCliReadSucceeded; } }
|
||||||
|
|
||||||
public void SetCurrentOp(CurrentPoseidonOp operation = CurrentPoseidonOp.None)
|
public void SetCurrentOp(CurrentPoseidonOp operation = CurrentPoseidonOp.None)
|
||||||
{
|
{
|
||||||
_currentOp = operation ;
|
_currentOp = operation ;
|
||||||
@ -407,12 +415,18 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||||
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
||||||
{
|
{
|
||||||
|
lastCliReadingParsed = false;
|
||||||
|
lastCliReadFailureReason = null;
|
||||||
|
lastCliReadSucceeded = false;
|
||||||
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
incommingTime = -1;
|
incommingTime = -1;
|
||||||
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
|
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
|
||||||
|
|
||||||
CliRunner.Clear();
|
CliRunner.Clear();
|
||||||
_lastOpTimedOut = false;
|
_lastOpTimedOut = false;
|
||||||
|
log.DebugFormat("{0}: starting CLI read, direction={1}, path='{2}', args='{3}'",
|
||||||
|
Name, _isReadingStart ? "start" : "end", serialPort.SerialPortCmdClientPath,
|
||||||
|
serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams));
|
||||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
||||||
SerialPortData.EMeterArg.AllParams);
|
SerialPortData.EMeterArg.AllParams);
|
||||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
|
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
|
||||||
@ -449,6 +463,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
var task = (Task<JsonDataFromPoseidon>)firstTaskInfo.Task;
|
var task = (Task<JsonDataFromPoseidon>)firstTaskInfo.Task;
|
||||||
data = task.Result;
|
data = task.Result;
|
||||||
|
if (data == null)
|
||||||
|
lastCliReadFailureReason = firstTaskInfo.FailureReason ?? "CLI returned no Poseidon JSON data.";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -464,6 +480,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
if (data != null)
|
if (data != null)
|
||||||
{
|
{
|
||||||
|
string validationError;
|
||||||
|
if (!TryValidateCliReadResponse(data, out validationError))
|
||||||
|
{
|
||||||
|
lastCliReadFailureReason = validationError;
|
||||||
|
log.ErrorFormat("{0}: Poseidon {1} read rejected. {2}", Name,
|
||||||
|
_isReadingStart ? "Begin" : "End", validationError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (string.IsNullOrEmpty(wmSerialNr))
|
if (string.IsNullOrEmpty(wmSerialNr))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -477,14 +502,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
}
|
}
|
||||||
|
|
||||||
double volume;
|
double volume;
|
||||||
if (Double.TryParse(data.Reading, out volume))
|
if (TryParseCliReading(data.Reading, out volume))
|
||||||
{
|
{
|
||||||
|
lastCliReadingParsed = true;
|
||||||
|
lastCliReadSucceeded = true;
|
||||||
double volumeLi = Units.ConvertFrom(Unit.USgal, volume);
|
double volumeLi = Units.ConvertFrom(Unit.USgal, volume);
|
||||||
|
|
||||||
if (_isReadingStart)
|
if (_isReadingStart)
|
||||||
beginWMState = volumeLi;
|
beginWMState = volumeLi;
|
||||||
else
|
else
|
||||||
endWMState = volumeLi;
|
endWMState = volumeLi;
|
||||||
|
log.InfoFormat("{0}: Poseidon {1} value stored. deviceId={2}, rawReading='{3}', gallons={4}, litres={5}, Begin={6}, End={7}",
|
||||||
|
Name, _isReadingStart ? "Begin" : "End", data.DeviceId, data.Reading, volume, volumeLi, beginWMState, endWMState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lastCliReadFailureReason = "Reading could not be parsed: '" + data.Reading + "'.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,6 +529,24 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool TryParseCliReading(string reading, out double value)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
if (String.IsNullOrWhiteSpace(reading)) return false;
|
||||||
|
return Double.TryParse(reading.Trim().Replace(',', '.'), NumberStyles.Float,
|
||||||
|
CultureInfo.InvariantCulture, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryValidateCliReadResponse(JsonDataFromPoseidon data, out string failureReason)
|
||||||
|
{
|
||||||
|
if (data == null) { failureReason = "CLI returned no JSON data."; return false; }
|
||||||
|
if (data.NfcTagDetected != true) { failureReason = "NfcTagDetected is false or missing."; return false; }
|
||||||
|
if (data.ReadingComplete != true) { failureReason = "ReadingComplete is false or missing."; return false; }
|
||||||
|
if (String.IsNullOrWhiteSpace(data.Reading)) { failureReason = "Reading is empty."; return false; }
|
||||||
|
failureReason = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Stop this operation</summary>
|
/// <summary>Stop this operation</summary>
|
||||||
public void Stop()
|
public void Stop()
|
||||||
|
|||||||
@ -5,6 +5,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
public class SerialPortData
|
public class SerialPortData
|
||||||
{
|
{
|
||||||
|
public const string CliDirectory = @"C:\TBF\Cli";
|
||||||
|
|
||||||
private Boolean? _cliExists;
|
private Boolean? _cliExists;
|
||||||
public bool CliExists { get {
|
public bool CliExists { get {
|
||||||
if (_cliExists == null || !_cliExists.HasValue)
|
if (_cliExists == null || !_cliExists.HasValue)
|
||||||
@ -13,12 +15,16 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
}
|
}
|
||||||
return _cliExists.Value;
|
return _cliExists.Value;
|
||||||
} }
|
} }
|
||||||
public string SerialPortCmdClientPath {
|
public string SerialPortCmdClientPath
|
||||||
#if DEBUG
|
{
|
||||||
get { return Path.Combine("C:\\","TBF","Cli", CmdClientName);}
|
get
|
||||||
#else
|
{
|
||||||
get { return Path.Combine("..","Cli", CmdClientName);}
|
string cliFileName = Path.GetFileName(CmdClientName);
|
||||||
#endif
|
if (String.IsNullOrWhiteSpace(cliFileName))
|
||||||
|
cliFileName = "HalCli.exe";
|
||||||
|
|
||||||
|
return Path.Combine(CliDirectory, cliFileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public string CmdClientName { get; set; } = "HalCli.exe";
|
public string CmdClientName { get; set; } = "HalCli.exe";
|
||||||
public string PortName { get; set; }
|
public string PortName { get; set; }
|
||||||
|
|||||||
@ -0,0 +1,175 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using TBF.Rig.GenericDevices;
|
||||||
|
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||||
|
|
||||||
|
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves persisted smart-reader selections. The visual dialog may have a
|
||||||
|
/// fixed number of controls, but the persisted model contains only configured
|
||||||
|
/// readers in each family.
|
||||||
|
/// </summary>
|
||||||
|
public static class SmartReaderSelection
|
||||||
|
{
|
||||||
|
private const string LegacyIPerlFamilyKey = "iperl";
|
||||||
|
|
||||||
|
public static void EnsureConfiguredReaders(LocalSettings settings, IEnumerable<ISmartReader> readers)
|
||||||
|
{
|
||||||
|
if (settings == null || readers == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<ISmartReader> configuredReaders = readers.Where(reader => reader != null).ToList();
|
||||||
|
if (configuredReaders.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SmartReaderSelectionSettings selections = GetOrCreateSettings(settings);
|
||||||
|
bool migrateLegacyMask = !selections.LegacyOptoHeadsEnabledMigrated;
|
||||||
|
string legacyFamily = configuredReaders.Any(reader => GetFamilyKey(reader) == LegacyIPerlFamilyKey)
|
||||||
|
? LegacyIPerlFamilyKey
|
||||||
|
: GetFamilyKey(configuredReaders[0]);
|
||||||
|
|
||||||
|
foreach (IGrouping<string, ISmartReader> family in configuredReaders.GroupBy(GetFamilyKey))
|
||||||
|
{
|
||||||
|
SmartReaderFamilySelection storedFamily = GetOrCreateFamily(selections, family.Key);
|
||||||
|
int ordinal = 0;
|
||||||
|
foreach (ISmartReader reader in family)
|
||||||
|
{
|
||||||
|
SmartReaderSelectionItem item = storedFamily.Readers
|
||||||
|
.FirstOrDefault(candidate => candidate.ReaderKey == GetReaderKey(reader));
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
item = new SmartReaderSelectionItem
|
||||||
|
{
|
||||||
|
ReaderKey = GetReaderKey(reader),
|
||||||
|
Enabled = !migrateLegacyMask || family.Key != legacyFamily ||
|
||||||
|
IsLegacyMaskEnabled(settings.OptoHeadsEnabled, reader, ordinal)
|
||||||
|
};
|
||||||
|
storedFamily.Readers.Add(item);
|
||||||
|
}
|
||||||
|
ordinal++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrateLegacyMask)
|
||||||
|
selections.LegacyOptoHeadsEnabledMigrated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long GetMask(LocalSettings settings, IEnumerable<ISmartReader> readers)
|
||||||
|
{
|
||||||
|
List<ISmartReader> familyReaders = ToReaderList(readers);
|
||||||
|
if (familyReaders.Count == 0)
|
||||||
|
return 0L;
|
||||||
|
|
||||||
|
EnsureConfiguredReaders(settings, familyReaders);
|
||||||
|
long result = 0L;
|
||||||
|
for (int index = 0; index < familyReaders.Count && index < 63; index++)
|
||||||
|
{
|
||||||
|
if (IsEnabled(settings, familyReaders[index]))
|
||||||
|
result |= 1L << index;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetMask(LocalSettings settings, IEnumerable<ISmartReader> readers, long state)
|
||||||
|
{
|
||||||
|
List<ISmartReader> familyReaders = ToReaderList(readers);
|
||||||
|
if (settings == null || familyReaders.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EnsureConfiguredReaders(settings, familyReaders);
|
||||||
|
for (int index = 0; index < familyReaders.Count; index++)
|
||||||
|
SetEnabled(settings, familyReaders[index], index < 63 && (state & (1L << index)) != 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsEnabled(LocalSettings settings, IRegReader reader)
|
||||||
|
{
|
||||||
|
if (settings == null || reader == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
SmartReaderSelectionSettings selections = settings.SmartReaderSelections;
|
||||||
|
if (selections == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
SmartReaderFamilySelection family = selections.Families == null
|
||||||
|
? null
|
||||||
|
: selections.Families.FirstOrDefault(item => item.FamilyKey == GetFamilyKey(reader));
|
||||||
|
SmartReaderSelectionItem item = family == null || family.Readers == null
|
||||||
|
? null
|
||||||
|
: family.Readers.FirstOrDefault(candidate => candidate.ReaderKey == GetReaderKey(reader));
|
||||||
|
|
||||||
|
// A newly configured reader is enabled until the user explicitly
|
||||||
|
// changes it in SmartCommunicationForm.
|
||||||
|
return item == null || item.Enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFamilyKey(IRegReader reader)
|
||||||
|
{
|
||||||
|
string typeName = reader == null ? string.Empty : reader.GetType().FullName ?? string.Empty;
|
||||||
|
if (typeName.IndexOf(".AllyReader.", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
return "ally";
|
||||||
|
if (typeName.IndexOf(".GenesisRegReader.", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
return "genesis";
|
||||||
|
if (typeName.IndexOf(".iPerlASICReader.", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
return "iperl-asic";
|
||||||
|
if (typeName.IndexOf(".Poseidon", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
return "poseidon";
|
||||||
|
return LegacyIPerlFamilyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetReaderKey(IRegReader reader)
|
||||||
|
{
|
||||||
|
if (reader == null)
|
||||||
|
return string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(reader.Name))
|
||||||
|
return reader.Name;
|
||||||
|
return string.Format("{0}#{1}", reader.GetType().FullName, reader.Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetEnabled(LocalSettings settings, IRegReader reader, bool enabled)
|
||||||
|
{
|
||||||
|
SmartReaderFamilySelection family = GetOrCreateFamily(GetOrCreateSettings(settings), GetFamilyKey(reader));
|
||||||
|
SmartReaderSelectionItem item = family.Readers.FirstOrDefault(candidate => candidate.ReaderKey == GetReaderKey(reader));
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
item = new SmartReaderSelectionItem { ReaderKey = GetReaderKey(reader) };
|
||||||
|
family.Readers.Add(item);
|
||||||
|
}
|
||||||
|
item.Enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SmartReaderSelectionSettings GetOrCreateSettings(LocalSettings settings)
|
||||||
|
{
|
||||||
|
if (settings.SmartReaderSelections == null)
|
||||||
|
settings.SmartReaderSelections = new SmartReaderSelectionSettings();
|
||||||
|
if (settings.SmartReaderSelections.Families == null)
|
||||||
|
settings.SmartReaderSelections.Families = new List<SmartReaderFamilySelection>();
|
||||||
|
return settings.SmartReaderSelections;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SmartReaderFamilySelection GetOrCreateFamily(SmartReaderSelectionSettings settings, string familyKey)
|
||||||
|
{
|
||||||
|
SmartReaderFamilySelection family = settings.Families.FirstOrDefault(item => item.FamilyKey == familyKey);
|
||||||
|
if (family == null)
|
||||||
|
{
|
||||||
|
family = new SmartReaderFamilySelection { FamilyKey = familyKey };
|
||||||
|
settings.Families.Add(family);
|
||||||
|
}
|
||||||
|
if (family.Readers == null)
|
||||||
|
family.Readers = new List<SmartReaderSelectionItem>();
|
||||||
|
return family;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsLegacyMaskEnabled(long legacyMask, IRegReader reader, int ordinal)
|
||||||
|
{
|
||||||
|
int index = reader.Position > 0 && reader.Position <= 63 ? reader.Position - 1 : ordinal;
|
||||||
|
return index >= 0 && index < 63 && (legacyMask & (1L << index)) != 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ISmartReader> ToReaderList(IEnumerable<ISmartReader> readers)
|
||||||
|
{
|
||||||
|
return readers == null ? new List<ISmartReader>() : readers.Where(reader => reader != null).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
TBF/SmartReaderSelectionSettings.cs
Normal file
28
TBF/SmartReaderSelectionSettings.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace TBF
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// User selection of smart register readers. The selection is deliberately
|
||||||
|
/// kept per reader family because reader positions are only meaningful inside
|
||||||
|
/// one configured family.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SmartReaderSelectionSettings
|
||||||
|
{
|
||||||
|
public bool LegacyOptoHeadsEnabledMigrated;
|
||||||
|
public List<SmartReaderFamilySelection> Families = new List<SmartReaderFamilySelection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class SmartReaderFamilySelection
|
||||||
|
{
|
||||||
|
public string FamilyKey;
|
||||||
|
public List<SmartReaderSelectionItem> Readers = new List<SmartReaderSelectionItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class SmartReaderSelectionItem
|
||||||
|
{
|
||||||
|
/// <summary>Stable configured component name; not a visual row index.</summary>
|
||||||
|
public string ReaderKey;
|
||||||
|
public bool Enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1758,6 +1758,7 @@
|
|||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\JsonDataFromPoseidon.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\JsonDataFromPoseidon.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCfg.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCfg.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonProcParams.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonProcParams.cs" />
|
||||||
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReadCycle.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReader.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReader.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\ProcessExtensions.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\ProcessExtensions.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\ScopedLoggerFactory.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\ScopedLoggerFactory.cs" />
|
||||||
|
|||||||
@ -245,5 +245,23 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
"Invalid JSON should not produce a valid DeviceId.");
|
"Invalid JSON should not produce a valid DeviceId.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task CliProcess_ExitErrorWithoutJson_RecordsDiagnosticsAndReturnsNoReading()
|
||||||
|
{
|
||||||
|
string cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? @"C:\Windows\System32\cmd.exe";
|
||||||
|
var cliRunner = new CliRunner(false);
|
||||||
|
var info = new CliTaskInfo { Name = "missing-dependency-simulation" };
|
||||||
|
|
||||||
|
JsonDataFromPoseidon result = await cliRunner.RunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||||
|
cmdExe,
|
||||||
|
"/d /c \"echo Could not load file or assembly 'log4net' 1>&2 & exit /b 17\"",
|
||||||
|
info);
|
||||||
|
|
||||||
|
Assert.IsNull(result);
|
||||||
|
Assert.AreEqual(17, info.ExitCode);
|
||||||
|
StringAssert.Contains(info.FailureReason, "exit code 17");
|
||||||
|
StringAssert.Contains(info.StandardError, "log4net");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using TBF.Rig;
|
||||||
|
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||||
|
using CmdPoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader;
|
||||||
|
|
||||||
|
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
[TestSubject(typeof(PoseidonReadCycle))]
|
||||||
|
public class PoseidonReadCycleTest
|
||||||
|
{
|
||||||
|
private sealed class FakeReader : IPoseidonReadOperation
|
||||||
|
{
|
||||||
|
private readonly int iterationsToComplete;
|
||||||
|
private int iterations;
|
||||||
|
public FakeReader(string name, int iterationsToComplete) { Name = name; this.iterationsToComplete = iterationsToComplete; }
|
||||||
|
public string Name { get; private set; }
|
||||||
|
public int StartCount { get; private set; }
|
||||||
|
public CmdPoseidonReader.CurrentPoseidonOp CurrentOp { get; private set; }
|
||||||
|
public bool IsNotStarted { get { return CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.None; } }
|
||||||
|
public bool IsFinished { get { return CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.Done || CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.Error; } }
|
||||||
|
public bool HasError { get { return CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.Error; } }
|
||||||
|
public void Start(bool readStart) { StartCount++; CurrentOp = readStart ? CmdPoseidonReader.CurrentPoseidonOp.ReadDataStream_Start : CmdPoseidonReader.CurrentPoseidonOp.ReadDataStream_End; }
|
||||||
|
public Event Run()
|
||||||
|
{
|
||||||
|
if (CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.ReadDataStream_Start || CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.ReadDataStream_End)
|
||||||
|
{ CurrentOp = CmdPoseidonReader.CurrentPoseidonOp.ReadDatastream_Running; return Event.Busy; }
|
||||||
|
if (CurrentOp == CmdPoseidonReader.CurrentPoseidonOp.ReadDatastream_Running && ++iterations >= iterationsToComplete)
|
||||||
|
{ CurrentOp = CmdPoseidonReader.CurrentPoseidonOp.Done; return Event.Done; }
|
||||||
|
return Event.Busy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RunIteration_FullBench_ArmsEachReaderOnce()
|
||||||
|
{
|
||||||
|
var readers = new List<IPoseidonReadOperation>();
|
||||||
|
for (int i = 1; i <= 48; i++) readers.Add(new FakeReader("PoseidonPos" + i, 1 + i % 3));
|
||||||
|
for (int i = 0; i < 5; i++) PoseidonReadCycle.RunIteration(readers, true);
|
||||||
|
foreach (FakeReader reader in readers) Assert.AreEqual(1, reader.StartCount, reader.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RunIteration_ReducedBench_DoesNotRestartCompletedReader()
|
||||||
|
{
|
||||||
|
var readers = new List<IPoseidonReadOperation> { new FakeReader("Pos1", 1), new FakeReader("Pos2", 3) };
|
||||||
|
for (int i = 0; i < 5; i++) PoseidonReadCycle.RunIteration(readers, false);
|
||||||
|
foreach (FakeReader reader in readers) Assert.AreEqual(1, reader.StartCount, reader.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void InputJson_ZeroReading_WithDecimalCommaOrDot_IsValid()
|
||||||
|
{
|
||||||
|
foreach (string reading in new[] { "00000,0", "00000.0" })
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
Assert.IsTrue(CmdPoseidonReader.TryParseCliReading(reading, out value));
|
||||||
|
Assert.AreEqual(0d, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CliReadResponse_RequiresNfcAndCompletedReading()
|
||||||
|
{
|
||||||
|
string reason;
|
||||||
|
var data = new JsonDataFromPoseidon { NfcTagDetected = true, ReadingComplete = true, Reading = "00000.0" };
|
||||||
|
Assert.IsTrue(CmdPoseidonReader.TryValidateCliReadResponse(data, out reason));
|
||||||
|
data.ReadingComplete = false;
|
||||||
|
Assert.IsFalse(CmdPoseidonReader.TryValidateCliReadResponse(data, out reason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,5 +37,20 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
Assert.IsTrue(tryGetDeviceId);
|
Assert.IsTrue(tryGetDeviceId);
|
||||||
Assert.AreEqual("1000000267", strOut);
|
Assert.AreEqual("1000000267", strOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TryParseCliReading_ShouldAcceptZeroWithDotAndComma()
|
||||||
|
{
|
||||||
|
double dotValue;
|
||||||
|
double commaValue;
|
||||||
|
|
||||||
|
Assert.IsTrue(TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader
|
||||||
|
.TryParseCliReading("00000.0", out dotValue));
|
||||||
|
Assert.IsTrue(TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader
|
||||||
|
.TryParseCliReading("00000,0", out commaValue));
|
||||||
|
|
||||||
|
Assert.AreEqual(0d, dotValue);
|
||||||
|
Assert.AreEqual(0d, commaValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||||
|
using CmdPoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader;
|
||||||
|
|
||||||
|
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
[TestCategory("Integration")]
|
||||||
|
public class PoseidonSingleMeterIntegrationTest
|
||||||
|
{
|
||||||
|
// Set this only when a real Poseidon meter is connected to the selected hat.
|
||||||
|
private const int RealPoseidonComPort = 0;
|
||||||
|
private const string RealPoseidonCliFile = "HatCliDemo.exe";
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[TestCategory("Manual")]
|
||||||
|
public void RealMeter_ReadStartValueThroughCli()
|
||||||
|
{
|
||||||
|
if (RealPoseidonComPort <= 0)
|
||||||
|
Assert.Inconclusive("Set RealPoseidonComPort before running this manual Poseidon integration test.");
|
||||||
|
|
||||||
|
string cliPath = Path.Combine(SerialPortData.CliDirectory, RealPoseidonCliFile);
|
||||||
|
if (!File.Exists(cliPath))
|
||||||
|
Assert.Inconclusive("Poseidon CLI was not found: " + cliPath);
|
||||||
|
|
||||||
|
var cfg = new PoseidonCfg("PoseidonIntegration", new Factory())
|
||||||
|
{
|
||||||
|
ComPortNr = RealPoseidonComPort,
|
||||||
|
CliFileName = RealPoseidonCliFile
|
||||||
|
};
|
||||||
|
var reader = new CmdPoseidonReader(cfg, null);
|
||||||
|
reader.DebugLevel = Common.DebugMode.Normal;
|
||||||
|
reader.Initialize();
|
||||||
|
reader.SetCurrentOp(CmdPoseidonReader.CurrentPoseidonOp.ReadDataStream_Start);
|
||||||
|
|
||||||
|
for (int iteration = 0; iteration < 3500 &&
|
||||||
|
reader.CurrentOp != CmdPoseidonReader.CurrentPoseidonOp.Done &&
|
||||||
|
reader.CurrentOp != CmdPoseidonReader.CurrentPoseidonOp.Error; iteration++)
|
||||||
|
{
|
||||||
|
reader.Run();
|
||||||
|
Thread.Sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(CmdPoseidonReader.CurrentPoseidonOp.Done, reader.CurrentOp);
|
||||||
|
Assert.IsTrue(reader.LastCliReadingParsed,
|
||||||
|
"CLI returned no parseable reading. Inspect the Poseidon CLI and TBF logs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -119,6 +119,7 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonReader
|
|||||||
Name = "PoseidonCfg",
|
Name = "PoseidonCfg",
|
||||||
OptoComPortNr = 6,
|
OptoComPortNr = 6,
|
||||||
RfidComPortNr = 5,
|
RfidComPortNr = 5,
|
||||||
|
DebugLevel = Common.DebugMode.Simulate,
|
||||||
};
|
};
|
||||||
|
|
||||||
config = poseidonCfg;
|
config = poseidonCfg;
|
||||||
@ -156,7 +157,8 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonReader
|
|||||||
string allText = string.Join(", ", listBox.Items.Cast<object>().Select(i => i.ToString()));
|
string allText = string.Join(", ", listBox.Items.Cast<object>().Select(i => i.ToString()));
|
||||||
|
|
||||||
Console.WriteLine(allText);
|
Console.WriteLine(allText);
|
||||||
Assert.IsTrue(allText.Contains("ReadSerialNo: 1000000267"));
|
Assert.IsTrue(allText.Contains("ReadSerialNo: 1111"),
|
||||||
|
"The UI unit test must use the deterministic simulated serial number, not physical hardware.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -215,10 +217,6 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonReader
|
|||||||
string allText = string.Join(", ", listBox.Items.Cast<object>().Select(i => i.ToString()));
|
string allText = string.Join(", ", listBox.Items.Cast<object>().Select(i => i.ToString()));
|
||||||
Console.WriteLine(allText);
|
Console.WriteLine(allText);
|
||||||
Assert.IsTrue(allText.Contains("SetTestMode: OK"));
|
Assert.IsTrue(allText.Contains("SetTestMode: OK"));
|
||||||
//some input from the meter
|
|
||||||
|
|
||||||
|
|
||||||
Thread.Sleep(50000);
|
|
||||||
//SET OPTOTEST MODE OFF
|
//SET OPTOTEST MODE OFF
|
||||||
comboBox.SelectedIndex = (int)PoseidonImplHeadTestCtrl.Operations.SetTestModeOff;
|
comboBox.SelectedIndex = (int)PoseidonImplHeadTestCtrl.Operations.SetTestModeOff;
|
||||||
uniHeadTestCtrl.CommandTestButtonClick(commandTestButton, eventArgs);
|
uniHeadTestCtrl.CommandTestButtonClick(commandTestButton, eventArgs);
|
||||||
@ -226,22 +224,6 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonReader
|
|||||||
allText = string.Join(", ", listBox.Items.Cast<object>().Select(i => i.ToString()));
|
allText = string.Join(", ", listBox.Items.Cast<object>().Select(i => i.ToString()));
|
||||||
Console.WriteLine(allText);
|
Console.WriteLine(allText);
|
||||||
Assert.IsTrue(allText.Contains("SetActiveMode: OK"));
|
Assert.IsTrue(allText.Contains("SetActiveMode: OK"));
|
||||||
|
|
||||||
|
|
||||||
/////////////// results of OptoHead
|
|
||||||
// Get the private ListBox field via reflection
|
|
||||||
var fieldOpto = uniHeadTestCtrl.GetType()
|
|
||||||
.GetField("optoListBox", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
|
||||||
// Read its value from the control instance (not Text!)
|
|
||||||
var listBoxOpto = fieldOpto?.GetValue(uniHeadTestCtrl) as System.Windows.Forms.ListBox;
|
|
||||||
// Verify we found it
|
|
||||||
Assert.IsNotNull(listBoxOpto, "optoListBox not found in UniHeadTestCtrl");
|
|
||||||
|
|
||||||
//check if the test mode is set OFF
|
|
||||||
allText = string.Join(", ", listBoxOpto.Items.Cast<object>().Select(i => i.ToString()));
|
|
||||||
Console.WriteLine(allText);
|
|
||||||
Assert.IsTrue(allText.Contains("Status: OptoHeadC7"));
|
|
||||||
Assert.IsTrue(allText.Contains("C7Data: C7"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,6 +135,8 @@
|
|||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutTest.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutUnitTest.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutUnitTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
|
||||||
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReadCycleTest.cs" />
|
||||||
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonSingleMeterIntegrationTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
||||||
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadBatchIntegrationTest.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadBatchIntegrationTest.cs" />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user