Ally multy reg readers implementation in SmartCommunicationForm.cs

This commit is contained in:
Michal Buzik 2026-08-25 10:26:15 +02:00
parent c966a7034c
commit 8157a752bd
17 changed files with 879 additions and 159 deletions

View File

@ -144,6 +144,7 @@ namespace TBF.Rig
new RegisterReaders.PoseidonReader.Factory(),
new RegisterReaders.IPerlReader.Factory(), /// the same functionality as TestMethods.iPerlCommunication.iPerlHead.Factory(),
new RegisterReaders.iPerlASICReader.Factory(), /// ASIC IPerl, C4 communication
new RegisterReaders.AllyReader.Factory(), // ALLY IPerl, communication
new RegisterReaders.GenesisRegReader.Factory(), /// Genesis RegisterReader - dirrect communication with the head
new RegisterReaders.PulsesFromUniCB.Factory(), /// 'RegisterReader'
new RegisterReaders.StandingStartStop.Factory(), /// 'RegisterReader for standing start/stop'
@ -201,6 +202,7 @@ namespace TBF.Rig
//new TestMethods.GenesisCommunication.GenesisHead.Factory(),
new TestMethods.GrabImage.Factory(),
new TestMethods.iPerlCommunication.TestMethodFactory(), /// iPerlCommunication
new TestMethods.AllyCalibration.Factory(), // Ally meter test
new TestMethods.LeakTest.Factory(),
new TestMethods.LiveStream.Factory(),
new TestMethods.ManualEntry.Factory(),

View File

@ -103,6 +103,9 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
/// RFID multiplexer PCB / RFID serial port and worker thread related variables
///
private static List<ICorrections> _corrections;
// Setting the initial combobox item raises SelectedIndexChanged before the
// constructor has finished preparing the form and its local settings.
private bool initializingMeterTypeItems;
private static ICorrections Correction
{
get
@ -169,68 +172,38 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
}
private static List<ICorrections> GetNewCorrectionList(SmartCommunicationForm form)
{
List<ICorrections> correctionsList = new List<ICorrections>();
// Manual communication is extended by registering a correction adapter here.
// An adapter is included only when at least one configured reader belongs to it.
// This keeps unsupported protocols out of the type selector and context menu.
List<ICorrections> candidates = new List<ICorrections>
{
new IPerlCorrections(form),
new IPerlASICCorrections(form),
new GenesisCorrections(form),
new AllyCorrections(form),
new PoseidonCorrections(form)
};
foreach (var smartHead in ProcessData.SmartHeadsUni)
{
try{
if (smartHead is IperlHead iperlHead)
{
if (correctionsList.Any(x => x is IPerlCorrections))
continue;
correctionsList.Add(new IPerlCorrections(form));
continue;
}
if (smartHead is SmartReader smartReader)
{
if (correctionsList.Any(x => x is SmartReader))
continue;
correctionsList.Add(new PoseidonCorrections(form));
continue;
}
throw new Exception("Unknown smart head type");
}
catch (Exception e)
{
log.Error("IdentifyReaderTypes()", e);
}
}
return correctionsList;
if (ProcessData.SmartHeadsUni == null)
return new List<ICorrections>();
return candidates
.Where(correction => ProcessData.SmartHeadsUni.Any(correction.IsFamilyOfSmartReader))
.ToList();
}
public static List<string> IdentifyReaderTypes()
{
List<string> typeReaders = new List<string>();
foreach (var smartHead in ProcessData.SmartHeadsUni)
{
try
{
if (typeReaders.Contains(smartHead.ClassName))
continue;
if (_corrections == null || ProcessData.SmartHeadsUni == null)
return typeReaders;
if (smartHead is IperlHead iperlHead)
{
typeReaders.Add(iperlHead.ClassName);
continue;
}
if (smartHead is SmartReader smartReader)
{
typeReaders.Add(smartReader.ClassName);
continue;
}
throw new Exception("Unknown smart head type");
}
catch (Exception e)
{
log.Error("IdentifyReaderTypes()", e);
}
}
foreach (ICorrections correction in _corrections)
{
if (ProcessData.SmartHeadsUni.Any(correction.IsFamilyOfSmartReader))
typeReaders.Add(correction.TypeIdentificatorName());
}
return typeReaders;
}
@ -411,33 +384,27 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
waterMeterPositions0?.Clear();
if (waterMeterPositions0 == null) waterMeterPositions0 = new List<int>();
//iperlHeads = ProcessData.SmartHeadsUni;
string comparedTypeReader = SelectedTypeReader;
ICorrections corre = null;
if (string.IsNullOrEmpty(SelectedTypeReader))
{
comparedTypeReader = ProcessData.SmartHeadsUni?.First()?.GetType().Name;
ISmartReader firstReader = ProcessData.SmartHeadsUni?.FirstOrDefault();
corre = _corrections.FirstOrDefault(correction => correction.IsFamilyOfSmartReader(firstReader));
}
ICorrections corre = null;
foreach (ICorrections correction in _corrections)
else
{
if (correction.TypeIdentificatorName() == SelectedTypeReader)
{
corre = correction;
break;
}
corre = _corrections.FirstOrDefault(
correction => correction.TypeIdentificatorName() == SelectedTypeReader);
}
if (corre != null)
{
int wmPos = 0;
foreach (var smartHead in ProcessData.SmartHeadsUni)
for (int wmPos = 0; wmPos < ProcessData.SmartHeadsUni.Count; wmPos++)
{
ISmartReader smartHead = ProcessData.SmartHeadsUni[wmPos];
if (corre.IsFamilyOfSmartReader(smartHead))
{
iperlHeads.Add(smartHead);
waterMeterPositions0.Add(wmPos);
wmPos++;
if (wmPos >= ProcessData.WMsCount) break;
}
}
@ -448,8 +415,8 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
WaterMetersCount = iperlHeads.Count;
ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize);
this.ContextMenu = Correction.GetContextMenu();
Correction.PrepareForTestsActivities(WaterMetersCount);
this.ContextMenu = corre.GetContextMenu();
corre.PrepareForTestsActivities(WaterMetersCount);
}
else
{
@ -458,35 +425,53 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
}
}
private void InitializeMeterTypeItems()
{
if (_corrections.Count >= 0)
{
meterTypeComboBox.Items.Clear();
int iItem = 0;
foreach (ICorrections correction in _corrections)
{
string name = correction?.TypeIdentificatorName();
if (string.IsNullOrEmpty(name))
{
name = iItem.ToString();
}
meterTypeComboBox.Items.Add(name);
if (iItem == 0)
SelectedTypeReader = name;
iItem++;
}
meterTypeComboBox.Visible = true;
meterTypeComboBox.Enabled = true;
meterTypeComboBox.SelectedIndex = 0;
}
}
private void InitializeMeterTypeItems()
{
if (_corrections != null && _corrections.Count > 0)
{
initializingMeterTypeItems = true;
try
{
meterTypeComboBox.Items.Clear();
int iItem = 0;
foreach (ICorrections correction in _corrections)
{
string name = correction?.TypeIdentificatorName();
if (string.IsNullOrEmpty(name))
{
name = iItem.ToString();
}
meterTypeComboBox.Items.Add(name);
if (iItem == 0)
SelectedTypeReader = name;
iItem++;
}
meterTypeComboBox.Visible = true;
meterTypeComboBox.Enabled = true;
meterTypeComboBox.SelectedIndex = 0;
}
finally
{
initializingMeterTypeItems = false;
}
}
}
private void InitializeWaterMeterData()
{
InitializeSmartReaderLists();
if (iperlHeads.Count <= 0)
if (checkBoxesEditMode)
{
// In manual mode the selected family must determine the displayed heads.
// Do not preload all smart readers and overwrite the combobox selection.
UpdateHeads();
}
else
{
InitializeSmartReaderLists();
if (iperlHeads.Count <= 0)
UpdateHeads();
}
WaterMetersCount = iperlHeads.Count;
ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize);
@ -674,6 +659,13 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
samplePictureBox3.Visible = false;
}
if (_corrections == null || _corrections.Count == 0 || Correction == null)
{
ContextMenu = null;
log.Warn("SmartCommunicationForm opened without a registered manual communication adapter.");
return;
}
if (_corrections.Count > 0)//enable combo for choose SmartMeter
{
meterTypeComboBox.Visible = true;
@ -684,9 +676,19 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
/// Set location and checkbox states to values stored in local settings
///
TBF.LocalSettings ls = Program.LocalSettings;
Left = (ls.iPerlCommunicationsFormLeft != 0) ? ls.iPerlCommunicationsFormLeft : 150;
Top = (ls.iPerlCommunicationsFormTop != 0) ? ls.iPerlCommunicationsFormTop : 150;
SetCheckBoxStates(ls.OptoHeadsEnabled);
if (ls == null)
{
log.Warn("SmartCommunicationForm loaded before LocalSettings were initialized; using default window and checkbox state.");
Left = 150;
Top = 150;
SetCheckBoxStates(0);
}
else
{
Left = (ls.iPerlCommunicationsFormLeft != 0) ? ls.iPerlCommunicationsFormLeft : 150;
Top = (ls.iPerlCommunicationsFormTop != 0) ? ls.iPerlCommunicationsFormTop : 150;
SetCheckBoxStates(ls.OptoHeadsEnabled);
}
if (!checkBoxesEditMode)
{
@ -919,7 +921,8 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
private void meterTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCombo = sender as ComboBox;
if (initializingMeterTypeItems) return;
ComboBox senderCombo = sender as ComboBox;
if (senderCombo == null) return;
SelectedTypeReader = senderCombo.SelectedItem?.ToString();
UpdateHeads();

View File

@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Windows.Forms;
using TBF.Rig.RegisterReaders.AllyReader;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
internal sealed class AllyCorrections : ManualSmartCorrectionsBase<AllyMeterReader>
{
private const int CommandTimeoutMs = 5000;
public AllyCorrections(SmartCommunicationForm parent) : base(parent) { }
public override string TypeIdentificatorName() => "ALLY";
public override bool IsFamilyOfSmartReader(ISmartReader smartHead) => smartHead is AllyMeterReader;
protected override IEnumerable<MenuItem> CreateMenuItems()
{
yield return new MenuItem("Read Serial Number") { Tag = "ReadSerialNumber" };
yield return new MenuItem("Read Version and Type") { Tag = "ReadVersion" };
yield return new MenuItem("Set RFID mode") { Tag = "SetRfid" };
yield return new MenuItem("Set NFC mode") { Tag = "SetNfc" };
}
protected override string ExecuteManualCommand(AllyMeterReader reader, string command)
{
switch (command)
{
case "ReadSerialNumber": return reader.ReadSerialNumber(CommandTimeoutMs);
case "ReadVersion": return reader.ReadVersionAndType(CommandTimeoutMs).ToString();
case "SetRfid": reader.SetRfidInterface(); return "OK";
case "SetNfc": reader.SetNfcInterface(); return "OK";
default: return "Unsupported ALLY operation";
}
}
}
}

View File

@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Windows.Forms;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
internal sealed class GenesisCorrections : ManualSmartCorrectionsBase<GenesisSmartReader>
{
public GenesisCorrections(SmartCommunicationForm parent) : base(parent) { }
public override string TypeIdentificatorName() => "Genesis";
public override bool IsFamilyOfSmartReader(ISmartReader smartHead) => smartHead is GenesisSmartReader;
protected override IEnumerable<MenuItem> CreateMenuItems()
{
yield return new MenuItem("Read PCB Number") { Tag = "ReadPcb" };
yield return new MenuItem("Set RFID mode") { Tag = "SetRfid" };
yield return new MenuItem("Set NFC mode") { Tag = "SetNfc" };
}
protected override string ExecuteManualCommand(GenesisSmartReader reader, string command)
{
switch (command)
{
case "ReadPcb": return reader.OptoHeadTest.ReadRequest_PCB();
case "SetRfid": reader.SetRfidInterface(); return "OK";
case "SetNfc": reader.SetNfcInterface(); return "OK";
default: return "Unsupported Genesis operation";
}
}
}
}

View File

@ -13,10 +13,9 @@ using Sensus.iPerl.NfcHandler;
using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
using TBF.Rig.RegisterReaders.IPerlReader.implementations;
using TBF.Rig.RegisterReaders.iPerlASICReader.implementations;
using TBF.Rig.Sequences;
using TBF.Rig.TestMethods.iPerlCommunication;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using CalibrationStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStruct;
using CalibrationStructV4 = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStructV4;
@ -24,7 +23,7 @@ using CheckBoxImage = TBF.Boxes.CheckBoxImage;
using Command = TBF.Rig.RegisterReaders.CommonRR.Command;
using CommunicationInterface = TBF.Rig.RegisterReaders.CommonRR.CommunicationInterface;
using ConfigStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.ConfigStruct;
using Factory = TBF.Rig.RegisterReaders.iPerlReaderUNI.Factory;
using Factory = TBF.Rig.RegisterReaders.iPerlASICReader.Factory;
using MessageID = TBF.Rig.RegisterReaders.CommonRR.MessageID;
using MeterState = TBF.Rig.RegisterReaders.CommonRR.MeterState;
using MeterType = TBF.Rig.RegisterReaders.CommonRR.MeterType;
@ -228,7 +227,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
{
IperlHead ihead = iperlHeads[wmNr0] as IperlHead;
SmartReader ihead = iperlHeads[wmNr0] as SmartReader;
if ((ihead.Group == group) && (threadIx < muxBrdOrGroup14Nrs.Count) &&
(ihead.MuxBoardNrOrGroup14 == muxBrdOrGroup14Nrs[threadIx]))
{
@ -306,14 +305,13 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
activityLabel.Text = menuItem.Text;
List<Task> tasks = new List<Task>();
foreach (var iSmartReader in ProcessData.SmartHeadsUni)
for (int position = 0; position < iperlHeads.Count; position++)
{
if (!(iSmartReader is IperlHead iHead))
if (!(iperlHeads[position] is SmartReader iHead))
{
continue;//ignore different types of heads
}
int position = iHead.Position - 1;
if (position < 0 || position >= checkBoxes.Length || position >= messages.Length)
{
continue; // Skip this head if position is out of range
@ -342,37 +340,39 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
await Task.WhenAll(tasks);
}
private async Task<string> ProcessTask(IperlHead head, object tag)
private async Task<string> ProcessTask(SmartReader head, object tag)
{
string txt = "";
switch (tag)
{
case "ReadPCB":
txt = OpticalHeadTest.ReadRequest_PCB(head);
txt = IPerlASICOpticalHeadTest.ReadPcb(head);
break;
case "WriteRequestPort_u8_Customer_Text":
txt = OpticalHeadTest.WriteRequestPort_u8_Customer_Text(head);
txt = "Unsupported ASIC operation";
break;
case "OpenSealing":
txt = OpticalHeadTest.OpenSealing(head);
txt = "Unsupported ASIC operation";
break;
case "StartTestMode":
txt = OpticalHeadTest.SetTestMode(head);
txt = IPerlASICOpticalHeadTest.SetTestMode(head);
break;
case "TurnOffTestMode":
txt = OpticalHeadTest.SetActiveMode(head);
txt = IPerlASICOpticalHeadTest.SetActiveMode(head);
break;
case "TurnOffRadio":
txt = OpticalHeadTest.TurnOffRadio(head);
txt = IPerlASICOpticalHeadTest.TurnOffRadio(head);
break;
case "SetProductionMode":
txt = OpticalHeadTest.SetProductionMode(head);
txt = IPerlASICOpticalHeadTest.SetProductionMode(head);
break;
case "SetRFID":
txt = OpticalHeadTest.SetRfidMode(head);
head.SetRfidInterface();
txt = "OK";
break;
case "SetNFC":
txt = OpticalHeadTest.SetNfcMode(head);
head.SetNfcInterface();
txt = "OK";
break;
}
@ -399,10 +399,12 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
///
for (int i = 0; i < textBoxesCount; i++)
{
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
bool hasHead = i < iperlHeads.Count;
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = hasHead;
if (!hasHead) continue;
IperlHead iperlHead = iperlHeads[i] as IperlHead;
SmartReader iperlHead = iperlHeads[i] as SmartReader;
if (!checkBoxesEditMode && (iperlHead == null || iperlHead.Disabled))
{
/// iPerl position i+1 is disabled
@ -441,7 +443,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
try
{
var iPerl = iSmartReader as IperlHead;
var iPerl = iSmartReader as SmartReader;
if (iPerl != null && iPerl.Group > lastGroup) lastGroup = iPerl.Group;
}
catch (Exception E)
@ -468,7 +470,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
foreach (ISmartReader iPerl in iperlHeads)
{
if (iPerl is IperlHead ihead)
if (iPerl is SmartReader ihead)
{
if (!muxBrdOrGroup14Nrs.Contains(ihead.MuxBoardNrOrGroup14))
muxBrdOrGroup14Nrs.Add(ihead.MuxBoardNrOrGroup14);
@ -2591,8 +2593,8 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
private static readonly List<Type> SupportedReaders = new List<Type>()
{
typeof(IperlHead),
typeof(TestMethods.iPerlCommunication.iPerlHead.Factory)
typeof(SmartReader),
typeof(TBF.Rig.RegisterReaders.iPerlASICReader.Factory)
};
public bool IsFamilyOfSmartReader(ISmartReader smartHead)
{
@ -2814,7 +2816,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
}
else
{
IperlHead iperlHead = (iperlHeads[i] as IperlHead);
SmartReader iperlHead = (iperlHeads[i] as SmartReader);
OptoHeadState checkFlowDirection =
((iperlHead == null) ? OptoHeadState.Disabled : iperlHead.CheckFlowDirection());

View File

@ -0,0 +1,105 @@
using System;
using Config.Resources;
using log4net;
using Sensus.iPerl.RfidCom.Helper;
using TBF.Rig.RegisterReaders.CommonRR;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
using TBF.Rig.RegisterReaders.iPerlASICReader.implementations;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using static Sensus.iPerl.NfcHandler.MCI_Protocol;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
/// <summary>
/// Manual commands for ASIC readers. They intentionally use the ASIC correction
/// transport path and never fall back to the old Sensus iPerl implementation.
/// </summary>
internal static class IPerlASICOpticalHeadTest
{
private static readonly ILog RfidDataLogger = LogManager.GetLogger("RfidData");
internal static string ReadPcb(SmartReader reader)
{
try
{
byte[] pcb;
int result = IPerlASICCorrections.ReadRequestPort(
SmartCommunicationForm.TestMethodCfg,
reader,
MessageID.Configuration,
StructName.Configuration,
16,
5,
out pcb);
if (result == 0 && pcb != null)
{
return RfidHelper.HexLiteral2Unsigned(
RfidHelper.SwapHexcode(BitConverter.ToString(pcb).Replace("-", string.Empty))).ToString();
}
RfidDataLogger.ErrorFormat("COM{0}: ASIC Read PCB failed ({1}).", reader.RfidComPortNr, result);
return "Error";
}
catch (Exception ex)
{
return ex.Message;
}
}
internal static string SetActiveMode(SmartReader reader)
{
return WriteCommand(reader, Command.SetActiveMode, "Error Set Active Mode");
}
internal static string SetTestMode(SmartReader reader)
{
return WriteCommand(reader, Command.SetTestMode, "Error Set Test Mode");
}
internal static string TurnOffRadio(SmartReader reader)
{
return WriteRadioValue(reader, MessageID.RadioPassthrough, StructName.RadioParams, 0x1898, 3);
}
internal static string SetProductionMode(SmartReader reader)
{
return WriteRadioValue(reader, MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, 1);
}
private static string WriteCommand(SmartReader reader, Command command, string errorText)
{
int result = IPerlASICCorrections.WriteRequestPort(
SmartCommunicationForm.TestMethodCfg,
reader,
MessageID.Command,
StructName.Command,
0,
1,
new[] { (byte)command });
return result == 0 ? "OK" : errorText;
}
private static string WriteRadioValue(SmartReader reader, MessageID messageId,
StructName structName, int offset, byte value)
{
try
{
int result = IPerlASICCorrections.WriteRequestPort(
SmartCommunicationForm.TestMethodCfg,
reader,
messageId,
structName,
offset,
1,
new[] { value });
return result == 0 ? "OK" : "Error";
}
catch (Exception ex)
{
return ex.Message;
}
}
}
}

View File

@ -14,9 +14,9 @@ using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
using TBF.Rig.RegisterReaders.IPerlReader.implementations;
using LegacyOpticalHeadTest = TBF.Rig.RegisterReaders.iPerlReaderUNI.test.OpticalHeadTest;
using TBF.Rig.Sequences;
using TBF.Rig.TestMethods.iPerlCommunication;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using CalibrationStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStruct;
using CalibrationStructV4 = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStructV4;
@ -24,7 +24,7 @@ using CheckBoxImage = TBF.Boxes.CheckBoxImage;
using Command = TBF.Rig.RegisterReaders.CommonRR.Command;
using CommunicationInterface = TBF.Rig.RegisterReaders.CommonRR.CommunicationInterface;
using ConfigStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.ConfigStruct;
using Factory = TBF.Rig.RegisterReaders.iPerlReaderUNI.Factory;
using Factory = TBF.Rig.RegisterReaders.IPerlReader.Factory;
using MessageID = TBF.Rig.RegisterReaders.CommonRR.MessageID;
using MeterState = TBF.Rig.RegisterReaders.CommonRR.MeterState;
using MeterType = TBF.Rig.RegisterReaders.CommonRR.MeterType;
@ -139,7 +139,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
public IPerlCorrections(SmartCommunicationForm parent)
{
this.ParentFrom = parent;
TBF.Rig.RegisterReaders.iPerlReaderUNI.Factory factory = new Factory();
Factory factory = new Factory();
TestMethod method = new TestMethod(factory.DefaultConfig());
this.testMethod = method;
this.Cfg = method.testMethodCfg;
@ -228,7 +228,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
{
IperlHead ihead = iperlHeads[wmNr0] as IperlHead;
SmartReader ihead = iperlHeads[wmNr0] as SmartReader;
if ((ihead.Group == group) && (threadIx < muxBrdOrGroup14Nrs.Count) &&
(ihead.MuxBoardNrOrGroup14 == muxBrdOrGroup14Nrs[threadIx]))
{
@ -306,14 +306,13 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
activityLabel.Text = menuItem.Text;
List<Task> tasks = new List<Task>();
foreach (var iSmartReader in ProcessData.SmartHeadsUni)
for (int position = 0; position < iperlHeads.Count; position++)
{
if (!(iSmartReader is IperlHead iHead))
if (!(iperlHeads[position] is SmartReader iHead))
{
continue;//ignore different types of heads
}
int position = iHead.Position - 1;
if (position < 0 || position >= checkBoxes.Length || position >= messages.Length)
{
continue; // Skip this head if position is out of range
@ -342,37 +341,39 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
await Task.WhenAll(tasks);
}
private async Task<string> ProcessTask(IperlHead head, object tag)
private async Task<string> ProcessTask(SmartReader head, object tag)
{
string txt = "";
switch (tag)
{
case "ReadPCB":
txt = OpticalHeadTest.ReadRequest_PCB(head);
txt = LegacyOpticalHeadTest.ReadRequest_PCB(head);
break;
case "WriteRequestPort_u8_Customer_Text":
txt = OpticalHeadTest.WriteRequestPort_u8_Customer_Text(head);
txt = "Unsupported old iPerl operation";
break;
case "OpenSealing":
txt = OpticalHeadTest.OpenSealing(head);
txt = LegacyOpticalHeadTest.OpenSealing(head);
break;
case "StartTestMode":
txt = OpticalHeadTest.SetTestMode(head);
txt = LegacyOpticalHeadTest.SetTestMode(head);
break;
case "TurnOffTestMode":
txt = OpticalHeadTest.SetActiveMode(head);
txt = LegacyOpticalHeadTest.SetActiveMode(head);
break;
case "TurnOffRadio":
txt = OpticalHeadTest.TurnOffRadio(head);
txt = LegacyOpticalHeadTest.TurnOffRadio(head);
break;
case "SetProductionMode":
txt = OpticalHeadTest.SetProductionMode(head);
txt = LegacyOpticalHeadTest.SetProductionMode(head);
break;
case "SetRFID":
txt = OpticalHeadTest.SetRfidMode(head);
head.SetRfidInterface();
txt = "OK";
break;
case "SetNFC":
txt = OpticalHeadTest.SetNfcMode(head);
head.SetNfcInterface();
txt = "OK";
break;
}
@ -399,10 +400,12 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
///
for (int i = 0; i < textBoxesCount; i++)
{
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
bool hasHead = i < iperlHeads.Count;
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = hasHead;
if (!hasHead) continue;
IperlHead iperlHead = iperlHeads[i] as IperlHead;
SmartReader iperlHead = iperlHeads[i] as SmartReader;
if (!checkBoxesEditMode && (iperlHead == null || iperlHead.Disabled))
{
/// iPerl position i+1 is disabled
@ -441,7 +444,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
try
{
var iPerl = iSmartReader as IperlHead;
var iPerl = iSmartReader as SmartReader;
if (iPerl != null && iPerl.Group > lastGroup) lastGroup = iPerl.Group;
}
catch (Exception E)
@ -468,7 +471,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
foreach (ISmartReader iPerl in iperlHeads)
{
if (iPerl is IperlHead ihead)
if (iPerl is SmartReader ihead)
{
if (!muxBrdOrGroup14Nrs.Contains(ihead.MuxBoardNrOrGroup14))
muxBrdOrGroup14Nrs.Add(ihead.MuxBoardNrOrGroup14);
@ -2591,8 +2594,8 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
private static readonly List<Type> SupportedReaders = new List<Type>()
{
typeof(IperlHead),
typeof(TestMethods.iPerlCommunication.iPerlHead.Factory)
typeof(SmartReader),
typeof(TBF.Rig.RegisterReaders.IPerlReader.Factory)
};
public bool IsFamilyOfSmartReader(ISmartReader smartHead)
{
@ -2814,7 +2817,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
}
else
{
IperlHead iperlHead = (iperlHeads[i] as IperlHead);
SmartReader iperlHead = (iperlHeads[i] as SmartReader);
OptoHeadState checkFlowDirection =
((iperlHead == null) ? OptoHeadState.Disabled : iperlHead.CheckFlowDirection());

View File

@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Config.Entities;
using Results.Entities;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using CheckBoxImage = TBF.Boxes.CheckBoxImage;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
/// <summary>
/// Common manual-only adapter for smart-meter reader families.
/// Test execution is deliberately not implemented here; each protocol must provide
/// its own test adapter before it is enabled for SmartCommunication test activities.
/// </summary>
internal abstract class ManualSmartCorrectionsBase<TReader> : ICorrections
where TReader : class, ISmartReader
{
protected ManualSmartCorrectionsBase(SmartCommunicationForm parent)
{
ParentFrom = parent;
}
public abstract string TypeIdentificatorName();
public abstract bool IsFamilyOfSmartReader(ISmartReader smartHead);
protected abstract IEnumerable<MenuItem> CreateMenuItems();
protected abstract string ExecuteManualCommand(TReader reader, string command);
public DateTime StartTime { get; set; }
public int StartTimeSec { get; set; }
public SmartCommunicationForm ParentFrom { get; set; }
public ITestMethodCfg Cfg { get; set; }
public IList<ITestParams> MultiTestParams { get; private set; }
public IList<Test> Tests { get; set; }
public IList<ISmartReader> iperlHeads => ParentFrom.Heads;
public ContextMenu GetContextMenu()
{
ContextMenu menu = new ContextMenu();
foreach (MenuItem item in CreateMenuItems())
{
item.Click += OnManualCommand;
menu.MenuItems.Add(item);
}
return menu;
}
private async void OnManualCommand(object sender, EventArgs e)
{
MenuItem item = sender as MenuItem;
if (item == null || item.Tag == null)
return;
ParentFrom.ActivityLabel.Text = item.Text;
string command = item.Tag.ToString();
IList<ISmartReader> heads = ParentFrom.Heads;
List<Task<string>> operations = heads
.Select(head => head as TReader)
.Select(reader => reader == null
? Task.FromResult("Unsupported reader")
: Task.Run(() => ExecuteSafely(reader, command)))
.ToList();
string[] results = await Task.WhenAll(operations);
for (int index = 0; index < results.Length && index < ParentFrom.Messages.Length; index++)
ParentFrom.Messages[index].Text = results[index];
}
private string ExecuteSafely(TReader reader, string command)
{
try
{
return ExecuteManualCommand(reader, command) ?? "OK";
}
catch (Exception exception)
{
ParentFrom.Log.Error($"{TypeIdentificatorName()} manual command '{command}' failed for {reader.Name}.", exception);
return $"Error: {exception.Message}";
}
}
public void Load(Label[] labels, PictureBox[] counters, TextBox[] messages, CheckBoxImage[] checkBoxes,
int[] ckbIndex, bool[] ckbState, IList<ISmartReader> heads, int textBoxesCount, bool checkBoxesEditMode)
{
for (int index = 0; index < textBoxesCount; index++)
{
bool visible = heads != null && index < heads.Count;
labels[index].Visible = counters[index].Visible = messages[index].Visible = checkBoxes[index].Visible = visible;
if (!visible)
continue;
ISmartReader reader = heads[index];
bool enabled = reader != null && (!reader.Disabled || checkBoxesEditMode);
checkBoxes[index].Enabled = checkBoxes[index].Checked = ckbState[index] = enabled;
counters[index].BackColor = enabled ? SystemColors.Control : iPerlCommunicationConstants.DisabledColor;
messages[index].Text = enabled ? "---" : "Disabled by user";
}
}
public int GetHeadsCount() => ParentFrom?.Heads?.Count ?? 0;
public void PrepareForTestsActivities(int waterMeterPositions0) { }
public void StartDataStreamProcessingForActiveMeters(int iMultiTestParamsItem) { }
public void StopWorkerThreads(bool bStopAllThreads) { }
public bool GetStopWorkerThreads() => false;
public IList<Thread> GetAllThreads() => new List<Thread>();
public ICorrections GetNewCorrection() => throw new NotSupportedException("Manual adapter cannot create a test adapter.");
public void GetGroup() { }
public void Worker(object threadData) => throw new NotSupportedException($"{TypeIdentificatorName()} test communication is not implemented.");
public bool WorkerActivity(string currentActivity, ISmartReader iHead, WaterMeter wm, Test currentTest,
int wmNr0, ref CommErr error, ref string resultStr, bool[] ckbState, int threadID, int currentActivityStep)
{
error = CommErr.WrongIPerlType;
resultStr = $"{TypeIdentificatorName()} test communication is not implemented.";
return false;
}
public void ProcessResultOfWorkerActivity(int iMultiTestParamsItem, string currentActivity, int currentGroup,
ISmartReader iHead, WaterMeter wm, int wmNr0, CommErr error, string resultStr, bool[] ckbState, int threadID) { }
public void DoOnCommCompleted(object sender, CommCompletedEventArgs data, IList<int> waterMeterPositions0) { }
public void NormalClose(IList<int> waterMeterPositions0) { }
}
}

View File

@ -294,7 +294,9 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
///
for (int i = 0; i < textBoxesCount; i++)
{
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
bool hasHead = i < iperlHeads.Count;
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = hasHead;
if (!hasHead) continue;
ISmartReader iperlHead = iperlHeads[i];
@ -516,14 +518,13 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
activityLabel.Text = menuItem.Text;
List<Task> tasks = new List<Task>();
foreach (var iSmartReader in ProcessData.SmartHeadsUni)
for (int position = 0; position < iperlHeads.Count; position++)
{
if (!(iSmartReader is SmartReader iHead))
if (!(iperlHeads[position] is SmartReader iHead))
{
continue;//ignore different types of heads
}
int position = iHead.Position;
if (position < 0 || position >= checkBoxes.Length || position >= messages.Length)
{
continue; // Skip this head if position is out of range

View File

@ -2558,7 +2558,11 @@
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ICorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ISmartReader.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\EnumExtensions.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\ManualSmartCorrectionsBase.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\GenesisCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\AllyCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\IPerlASICCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\IPerlASICOpticalHeadTest.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\IPerlCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\SmartComponentBase.cs" />

View File

@ -1199,7 +1199,7 @@ namespace TBF.UI
private void optoHeadsToolStripMenuItem_Click(object sender, EventArgs e)
{
new iPerlCommunicationForm(true).ShowDialog();
new SmartCommunicationForm(true).ShowDialog();
}
private void statusStrip1_DoubleClick(object sender, EventArgs e)

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
@ -14,13 +15,30 @@ using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.protocol
{
[TestClass]
public class CordonelProtocolTests
[TestCategory("HardwareIntegration")]
public class CordonelProtocolIntegrationTests
{
private const string ComPort = "COM3"; // CHANGE THIS
private const int BaudRate = 9600;
private const int BaudRateOpto = 38400;
private const int ReadTimeoutMs = 2000;
[TestInitialize]
public void RequireExplicitHardwareConfiguration()
{
if (!string.Equals(Environment.GetEnvironmentVariable("GENESIS_HW_TESTS"), "1",
StringComparison.Ordinal))
{
Assert.Inconclusive("Set GENESIS_HW_TESTS=1 to run Genesis serial hardware integration tests.");
}
if (!SerialPort.GetPortNames().Any(port =>
string.Equals(port, ComPort, StringComparison.OrdinalIgnoreCase)))
{
Assert.Inconclusive($"Genesis hardware integration requires configured port {ComPort}.");
}
}
//...MF
[TestMethod]

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
@ -14,6 +15,7 @@ using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHatProtocol
{
[TestClass]
[TestCategory("HardwareIntegration")]
public class IperlHatIntegrationTests
{
private const string ComPort = "COM12"; // CHANGE THIS
@ -22,6 +24,23 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
private const int BaudRateOpto = 38400;
private const int ReadTimeoutMs = 2000;
[TestInitialize]
public void RequireExplicitHardwareConfiguration()
{
if (!string.Equals(Environment.GetEnvironmentVariable("IPERL_ASIC_HW_TESTS"), "1",
StringComparison.Ordinal))
{
Assert.Inconclusive("Set IPERL_ASIC_HW_TESTS=1 to run iPerl ASIC serial hardware integration tests.");
}
string[] ports = SerialPort.GetPortNames();
if (!ports.Any(port => string.Equals(port, ComPort, StringComparison.OrdinalIgnoreCase)) ||
!ports.Any(port => string.Equals(port, ComPortOptho, StringComparison.OrdinalIgnoreCase)))
{
Assert.Inconclusive($"iPerl ASIC hardware integration requires configured ports {ComPort} and {ComPortOptho}.");
}
}
[TestMethod]
[TestCategory("Hardware")]
[TestCategory("Serial")]
@ -454,7 +473,7 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
/// </summary>
[TestMethod]
[TestCategory("Hardware")]
public void Serial_OptoRawSniff_Standalone()
public void Integration_Serial_OptoRawSniff_Standalone()
{
Serial_OptoRawSniff();
}
@ -503,7 +522,7 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
}
catch (TimeoutException)
{
Assert.Fail("Serial read timeout");
Assert.Inconclusive("No optical packet was received within 10 seconds. Enable optical test mode before running this sniff integration test.");
}
}

View File

@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.RegisterReaders.AllyReader;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
using TBF.Rig.Sequences;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations;
namespace TBFTests.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
[TestClass]
public class SmartCommunicationFormTests
{
private static readonly object ProcessDataLock = new object();
[TestMethod]
public void ManualForm_PopulatesAvailableFamiliesFromRegisterReaders()
{
RunInSta(() =>
{
WithSmartReaders(new ISmartReader[] { CreateGenesisReader(), CreateAllyReader() }, () =>
{
using (var form = new SmartCommunicationForm(true))
{
CollectionAssert.AreEqual(
new[] { "Genesis", "ALLY" },
SmartCommunicationForm.IdentifyReaderTypes());
}
});
});
}
[TestMethod]
public void ManualForm_SelectedFamilyPopulatesOnlyMatchingReaderAndCorrection()
{
RunInSta(() =>
{
GenesisSmartReader genesis = CreateGenesisReader();
AllyMeterReader ally = CreateAllyReader();
WithSmartReaders(new ISmartReader[] { genesis, ally }, () =>
{
using (var form = new SmartCommunicationForm(true))
{
SelectFamily(form, "ALLY");
Assert.AreEqual(1, form.Heads.Count);
Assert.AreSame(ally, form.Heads[0]);
Assert.IsInstanceOfType(CurrentCorrection(), typeof(AllyCorrections));
SelectFamily(form, "Genesis");
Assert.AreEqual(1, form.Heads.Count);
Assert.AreSame(genesis, form.Heads[0]);
Assert.IsInstanceOfType(CurrentCorrection(), typeof(GenesisCorrections));
}
});
});
}
[TestMethod]
public void ManualForm_LoadsReaderRowsAndCheckboxTogglesSelectionState()
{
RunInSta(() =>
{
AllyMeterReader first = CreateAllyReader();
AllyMeterReader second = CreateAllyReader();
WithSmartReaders(new ISmartReader[] { first, second }, () =>
{
using (var form = new SmartCommunicationForm(true))
{
SelectFamily(form, "ALLY");
form.CkbIndex[0] = 0;
form.CkbIndex[1] = 1;
ICorrections correction = CurrentCorrection();
correction.Load(form.Labels, form.Counters, form.Messages, form.CheckBoxes,
form.CkbIndex, form.CkbState, form.Heads, form.CheckBoxes.Length, true);
Assert.AreEqual(2, form.Heads.Count);
Assert.AreSame(first, form.Heads[0]);
Assert.AreSame(second, form.Heads[1]);
Assert.IsTrue(form.CheckBoxes[0].Checked);
Assert.IsTrue(form.CheckBoxes[1].Checked);
Assert.AreEqual("---", form.Messages[0].Text);
Assert.AreEqual("---", form.Messages[1].Text);
form.CheckBoxes[0].Checked = false;
InvokePrivate(form, "checkBoxImage1_Click", form.CheckBoxes[0], EventArgs.Empty);
Assert.IsFalse(form.CkbState[0]);
form.CheckBoxes[0].Checked = true;
InvokePrivate(form, "checkBoxImage1_Click", form.CheckBoxes[0], EventArgs.Empty);
Assert.IsTrue(form.CkbState[0]);
Assert.IsTrue((form.GetCheckBoxStates() & 1L) != 0L);
}
});
});
}
[TestMethod]
public void SelectedCorrection_ProvidesCommandsForTheSelectedRegisterReaderFamily()
{
RunInSta(() =>
{
WithSmartReaders(new ISmartReader[] { CreateGenesisReader(), CreateAllyReader() }, () =>
{
using (var form = new SmartCommunicationForm(true))
{
SelectFamily(form, "ALLY");
CollectionAssert.Contains(
CurrentCorrection().GetContextMenu().MenuItems.Cast<System.Windows.Forms.MenuItem>()
.Select(item => item.Text).ToArray(),
"Read Serial Number");
SelectFamily(form, "Genesis");
CollectionAssert.Contains(
CurrentCorrection().GetContextMenu().MenuItems.Cast<System.Windows.Forms.MenuItem>()
.Select(item => item.Text).ToArray(),
"Read PCB Number");
}
});
});
}
private static AllyMeterReader CreateAllyReader()
{
return new AllyMeterReader(new AllyReaderCfg(new TBF.Rig.RegisterReaders.AllyReader.Factory()));
}
private static GenesisSmartReader CreateGenesisReader()
{
return new GenesisSmartReader(new TBF.Rig.RegisterReaders.GenesisRegReader.GenesisCfg(
new TBF.Rig.RegisterReaders.GenesisRegReader.Factory()));
}
private static void SelectFamily(SmartCommunicationForm form, string family)
{
SmartCommunicationForm.SelectedTypeReader = family;
InvokePrivate(form, "UpdateHeads");
}
private static ICorrections CurrentCorrection()
{
PropertyInfo property = typeof(SmartCommunicationForm).GetProperty(
"Correction", BindingFlags.NonPublic | BindingFlags.Static);
return (ICorrections)property.GetValue(null, null);
}
private static void InvokePrivate(SmartCommunicationForm form, string methodName, params object[] parameters)
{
MethodInfo method = typeof(SmartCommunicationForm).GetMethod(
methodName, BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(form, parameters);
}
private static void WithSmartReaders(IList<ISmartReader> readers, Action action)
{
lock (ProcessDataLock)
{
IList<ISmartReader> previous = ProcessData.SmartHeadsUni;
string previousSelectedType = SmartCommunicationForm.SelectedTypeReader;
try
{
ProcessData.SmartHeadsUni = readers;
SmartCommunicationForm.SelectedTypeReader = null;
action();
}
finally
{
ProcessData.SmartHeadsUni = previous;
SmartCommunicationForm.SelectedTypeReader = previousSelectedType;
}
}
}
private static void RunInSta(Action action)
{
Exception failure = null;
Thread thread = new Thread(() =>
{
try { action(); }
catch (Exception exception) { failure = exception; }
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
if (failure != null)
throw new AssertFailedException(failure.ToString());
}
}
}

View File

@ -0,0 +1,92 @@
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.RegisterReaders.AllyReader;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations;
using LegacyIPerlReader = TBF.Rig.RegisterReaders.IPerlReader.implementations.SmartReader;
using AsicIPerlReader = TBF.Rig.RegisterReaders.iPerlASICReader.implementations.SmartReader;
namespace TBFTests.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
/// <summary>Fast tests of the correction-adapter contract; no COM port is opened.</summary>
[TestClass]
public class CorrectionsContractTests
{
[TestMethod]
public void ManualAdapters_ExposeStableFamilyNames()
{
Assert.AreEqual("ALLY", new AllyCorrections(null).TypeIdentificatorName());
Assert.AreEqual("Genesis", new GenesisCorrections(null).TypeIdentificatorName());
Assert.AreEqual("iPerl", new IPerlCorrections(null).TypeIdentificatorName());
Assert.AreEqual("iPerl ASIC", new IPerlASICCorrections(null).TypeIdentificatorName());
Assert.AreEqual("Poseidon", new PoseidonCorrections(null).TypeIdentificatorName());
}
[TestMethod]
public void AllyManualAdapter_ExposesOnlySupportedSafeOperations()
{
var menu = new AllyCorrections(null).GetContextMenu();
CollectionAssert.AreEqual(
new[] { "Read Serial Number", "Read Version and Type", "Set RFID mode", "Set NFC mode" },
menu.MenuItems.Cast<System.Windows.Forms.MenuItem>().Select(item => item.Text).ToArray());
}
[TestMethod]
public void GenesisManualAdapter_ExposesOnlyImplementedOperations()
{
var menu = new GenesisCorrections(null).GetContextMenu();
CollectionAssert.AreEqual(
new[] { "Read PCB Number", "Set RFID mode", "Set NFC mode" },
menu.MenuItems.Cast<System.Windows.Forms.MenuItem>().Select(item => item.Text).ToArray());
}
[TestMethod]
public void ManualOnlyAdapters_RejectTestCommunicationExplicitly()
{
ICorrections correction = new AllyCorrections(null);
CommErr error = CommErr.None;
string result = string.Empty;
bool handled = correction.WorkerActivity("Read Serial Number", null, null, null, 0,
ref error, ref result, new bool[0], 0, 0);
Assert.IsFalse(handled);
Assert.AreEqual(CommErr.WrongIPerlType, error);
StringAssert.Contains(result, "test communication is not implemented");
}
[TestMethod]
public void IPerlCorrection_DisabledReaderStopsBusinessActivityBeforeCommunication()
{
ISmartReader reader = new LegacyIPerlReader(
new TBF.Rig.RegisterReaders.IPerlReader.Factory().DefaultConfig()) { Disabled = true };
CommErr error = CommErr.None;
string result = string.Empty;
bool handled = new IPerlCorrections(null).WorkerActivity("Unknown activity", reader, null, null, 0,
ref error, ref result, new[] { true }, 0, 0);
Assert.IsTrue(handled);
Assert.AreEqual(CommErr.HeadDisabledByUser, error);
}
[TestMethod]
public void IPerlAsicCorrection_DisabledReaderStopsBusinessActivityBeforeCommunication()
{
ISmartReader reader = new AsicIPerlReader(
new TBF.Rig.RegisterReaders.iPerlASICReader.Factory().DefaultConfig()) { Disabled = true };
CommErr error = CommErr.None;
string result = string.Empty;
bool handled = new IPerlASICCorrections(null).WorkerActivity("Unknown activity", reader, null, null, 0,
ref error, ref result, new[] { true }, 0, 0);
Assert.IsTrue(handled);
Assert.AreEqual(CommErr.HeadDisabledByUser, error);
}
}
}

View File

@ -0,0 +1,78 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.RegisterReaders.AllyReader;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations;
using IPerlSmartReader = TBF.Rig.RegisterReaders.IPerlReader.implementations.SmartReader;
using IPerlAsicSmartReader = TBF.Rig.RegisterReaders.iPerlASICReader.implementations.SmartReader;
using PoseidonSmartReader = TBF.Rig.RegisterReaders.PoseidonReader.SmartReader;
namespace TBFTests.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
/// <summary>Reader-to-adapter wiring tests. They use real reader classes but no hardware transport.</summary>
[TestClass]
public class RegisterReaderCorrectionWiringTests
{
[TestMethod]
public void AllyReader_IsRecognizedOnlyByAllyCorrection()
{
AllyMeterReader reader = new AllyMeterReader(new AllyReaderCfg(new TBF.Rig.RegisterReaders.AllyReader.Factory()));
Assert.IsInstanceOfType(reader, typeof(ISmartReader));
Assert.IsInstanceOfType(reader, typeof(IRegReaderSmart));
Assert.IsTrue(new AllyCorrections(null).IsFamilyOfSmartReader(reader));
Assert.IsFalse(new GenesisCorrections(null).IsFamilyOfSmartReader(reader));
Assert.IsFalse(new IPerlCorrections(null).IsFamilyOfSmartReader(reader));
Assert.IsFalse(new IPerlASICCorrections(null).IsFamilyOfSmartReader(reader));
}
[TestMethod]
public void GenesisReader_IsRecognizedOnlyByGenesisCorrection()
{
GenesisSmartReader reader = new GenesisSmartReader(
new TBF.Rig.RegisterReaders.GenesisRegReader.GenesisCfg(new TBF.Rig.RegisterReaders.GenesisRegReader.Factory()));
Assert.IsInstanceOfType(reader, typeof(ISmartReader));
Assert.IsInstanceOfType(reader, typeof(IRegReaderSmart));
Assert.IsTrue(new GenesisCorrections(null).IsFamilyOfSmartReader(reader));
Assert.IsFalse(new AllyCorrections(null).IsFamilyOfSmartReader(reader));
Assert.IsFalse(new IPerlCorrections(null).IsFamilyOfSmartReader(reader));
Assert.IsFalse(new IPerlASICCorrections(null).IsFamilyOfSmartReader(reader));
}
[TestMethod]
public void ExistingSmartReaderFamilies_AreBoundToTheirOwnCorrections()
{
ISmartReader oldIperl = new IPerlSmartReader(
new TBF.Rig.RegisterReaders.IPerlReader.Factory().DefaultConfig());
ISmartReader asic = new IPerlAsicSmartReader(
new TBF.Rig.RegisterReaders.iPerlASICReader.Factory().DefaultConfig());
ISmartReader poseidon = new PoseidonSmartReader(
new TBF.Rig.RegisterReaders.PoseidonReader.Factory().DefaultConfig());
Assert.IsTrue(new IPerlCorrections(null).IsFamilyOfSmartReader(oldIperl));
Assert.IsTrue(new IPerlASICCorrections(null).IsFamilyOfSmartReader(asic));
Assert.IsTrue(new PoseidonCorrections(null).IsFamilyOfSmartReader(poseidon));
Assert.IsFalse(new IPerlCorrections(null).IsFamilyOfSmartReader(asic));
Assert.IsFalse(new IPerlASICCorrections(null).IsFamilyOfSmartReader(oldIperl));
Assert.IsFalse(new PoseidonCorrections(null).IsFamilyOfSmartReader(oldIperl));
}
[TestMethod]
public void SmartReaderContract_PreservesManualSelectionStateWithoutTransport()
{
ISmartReader reader = new AllyMeterReader(new AllyReaderCfg(new TBF.Rig.RegisterReaders.AllyReader.Factory()));
reader.Disabled = true;
reader.SerialNr = "ALLY-TEST";
reader.SetCommunicationInterface("RFID");
Assert.IsTrue(reader.Disabled);
Assert.AreEqual("ALLY-TEST", reader.SerialNr);
Assert.AreEqual("Touch-Read", reader.CommInterface);
}
}
}

View File

@ -159,6 +159,9 @@
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\IperlResponseFactory.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\RadioServiceTest.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrectionsTest.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\SmartCommunicationFormTests.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\CorrectionsContractTests.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\RegisterReaderCorrectionWiringTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />