2026-09-09 13:04:49 +00:00
using TBF.Rig.TestMethods.iPerlCommunication ;
///
/// Copyright (c) 2015-2023 Sensus Slovensko a.s.
///
//#define VERIFY_ACTIVE_MODE
//#define VERIFY_Q2_CORR_RESET
using System ;
using System.Collections.Generic ;
using System.Drawing ;
using System.Globalization ;
using System.Linq ;
using System.Threading ;
using System.Windows.Forms ;
using log4net ;
using Common ;
using Config.Entities ;
using TBF.Resources ;
using TBF.Rig.Sequences ;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead ;
using Results.Entities ;
using static Sensus . iPerl . NfcHandler . MCI_Protocol ;
using System.Threading.Tasks ;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication ;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations ;
using TBF.Rig.TestMethods.GenesisCommunication ;
using TBF.Rig.TestMethods.iPerlCommunication.communication ;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed ;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons ;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common ;
using CommunicationInterface = TBF . Rig . TestMethods . iPerlCommunication . iPerlHead . CommunicationInterface ;
using ConfigStruct = TBF . Rig . TestMethods . iPerlCommunication . iPerlHead . ConfigStruct ;
using MessageID = TBF . Rig . TestMethods . iPerlCommunication . iPerlHead . MessageID ;
using MeterType = TBF . Rig . TestMethods . iPerlCommunication . iPerlHead . MeterType ;
namespace TBF.Rig.TestMethods.GenesisCommunication
{
public enum CommErr
{
None = 0 ,
CommFailed , /// 1
OpenPort , /// 2
Read , /// 3
Read1 , /// 4
Read2 , /// 5
Read3 , /// 6
Read4 , /// 7
Write , /// 8
ReadAfterWrite , /// 9
CmdActive , /// 0AH = 10
CmdTest , /// 0BH = 11
Verify , /// 0CH = 12
WrongIPerlType , /// 0DH = 13
OutOfRange , /// 0EH = 14
Q2OutOfRange , /// 0FH = 15
MissingTest , /// 10H = 16
RFPowerRecordMissing , /// 11H = 17
HeadDisabledByUser , /// 12H = 18
WrongArguments , /// 13H = 19
FailedInit , /// 14H = 20
FailedConnect , /// 15H = 21
FailedReadSerialNr , /// 16H = 22
FailedSetPassword , /// 17H = 23
FailedLogin , /// 18H = 24
FailedSetTestMode , /// 19H = 25
FailedSetActiveMode , /// 1AH = 26
FailedWriteCalibrationFactor , /// 1BH = 27
FailedWriteRegister , /// 1CH = 28
FailedPrepare , /// 1DH = 29
}
public partial class GenesisCommunicationForm : Form , GenericDevices . IHasCompleted
{
private static readonly ILog log = LogManager . GetLogger ( typeof ( GenesisCommunicationForm ) ) ;
protected static readonly ILog rfidDataLogger = LogManager . GetLogger ( "RfidData" ) ;
const int Hz2CorrFactorsAddr = 0x1875 ; /// Used by Reset2HzCorrection(...) and Write2HzCorrection(...)
const int Q2CorrFactorsAddr = 0x1878 ; /// Used by ResetQ2Correction(...) and WriteQ2Correction(...)
const int Q2CorrFactorsAddrLR = 0x1878 ;
const int Q2CorrFactorsAddrRL = 0x1879 ;
public const string SlotInitializeStr = "Initialise Slot" ;
public const string SlotUpdateStr = "Update Slot" ;
public const string SlotConnectStr = "Connect Slot" ;
public const string SlotPCBSlotStr = "PCB Slot" ;
public const string SlotSetPasswordStr = "Set Password" ;
public const string SlotLoginStr = "Login" ;
public const string SlotGroupedLoginStr = "Login (Combined workflow)" ;
public const string SlotSetTestModeStr = "Switch to Test Mode" ;
public const string SlotSetActiveModeStr = "Switch to Active Mode" ;
public const string SlotDisconnectStr = "Disconnect Slot" ;
public const string PrepareSlotQ3CalibrationStr = "Prepare Q3 Calibration Slot" ;
public const string WriteSlotQ3CalibrationStr = "Write Q3 Calibration Slot" ;
public const string CheckMeterPrepareStr = "Check Meter Prepare Slot" ;
public const string HoldSlotStr = "Hold Slot" ;
public const string PrepareInitializeStr = "Initialise Prepare" ;
public const string ReadConfigurationStr = "Read configuration" ; /// Example: "Read configuration" or "Read configuration if enabled"
public const string SetTestModeStr = "Set Test mode" ; /// Example: "Set Test mode" or "Set Test mode A0" (hexadecimal number is the required 'testModeConfig'
public const string SetActiveModeStr = "Set Active mode" ;
public const string ReadSerialNrStr = "Read SerialNr" ;
public const string SetIdleModeStr = "Set Idle mode" ;
public const string ReadCalibrationStr = "Read calibration" ;
public const string ReadCalibrationV4Str = "Read calibration_V4" ;
public const string WriteCalibrationFactorStr = "Write calibration factor" ;
public const string WriteCalibrationV4FactorsStr = "Write calibration_V4" ;
public const string NormalizeCalibrationFactorStr = "Normalize calibration factor" ;
public const string NormalizeCalibrationV4FactorsStr = "Normalize calibration_V4" ;
public const string GetDefaultQ2CorrectionsStr = "Get default Q2 corrections" ;
public const string ReadQ2CorrectionStr = "Read Q2 corrections" ;
public const string ResetQ2CorrectionStr = "Reset Q2 correction" ;
public const string WriteDefaultQ2CorrectionsStr = "Write default Q2 corrections" ;
public const string InitOrReadQ2CorrectionsStr = "Init or read Q2 corrections" ;
public const string WriteQ2CorrectionStr = "Write Q2 correction" ; /// No arguments
public const string WriteQ2CorrectionAltStr = "Write Q2 correction Alt" ; /// No arguments
public const string WriteQ2CorrectionGreeceStr = "Write Q2 correction Greece" ; /// Arguments: test_name
public const string WriteQ2CorrectionRLStr = "Write Q2 correction R-L" ; /// Arguments: test_name
public const string WriteQ2CorrectionLRStr = "Write Q2 correction L-R" ; /// Arguments: test_name
public const string WriteQ2CorrectionIncl05Str = "Write_Q2_correction_incl.-0,5..0,5%" ; /// No arguments
public const string WriteQ2CorrectionAltIncl05Str = "Write_Q2_correction_Alt_incl.-0,5..0,5%" ; /// No arguments
public const string WriteQ2CorrectionPlusIncl05Str = "Write_Q2_correction_plus_incl.-0,5..0,5%" ; /// No arguments
public const string WriteQ2CorrectionPlusAltIncl05Str = "Write_Q2_correction_plus_Alt_incl.-0,5..0,5%" ; /// No arguments
public const string WriteQ2CorrectionGreeceIncl05Str = "Write_Q2_correction_Greece_incl.-0,5..0,5%" ; /// Arguments: test_name
public const string WriteQ2CorrectionRLIncl05Str = "Write_Q2_correction_R-L_incl.-0,5..0,5%" ; /// Arguments: test_name
public const string WriteQ2CorrectionLRIncl05Str = "Write_Q2_correction_L-R_incl.-0,5..0,5%" ; /// Arguments: test_name
public const string UpdateBothQ2FactorsTestRLOnlyStr = "Update_both_Q2_factors_Test_RL_only" ; /// No arguments
public const string UpdateBothQ2FactorsTestLROnlyStr = "Update_both_Q2_factors_Test_LR_only" ; /// No arguments
public const string UpdateQ2CorrectionsStr = "Update Q2 corrections" ; /// Arguments: R-L_test_name L-R_test_name
public const string ConditnlUpdateQ2CorrectionsStr = "Conditional update of Q2 corrections" ; /// Arguments: R-L_test_name L-R_test_name
public const string ConditnlUpdateQ2CorrRLStr = "Conditional update of Q2 correction R-L" ; /// Arguments: R-L_test_name
public const string ConditnlUpdateQ2CorrLRStr = "Conditional update of Q2 correction L-R" ; /// Arguments: L-R_test_name
public const string Reset2HzCorrectionStr = "Reset 2Hz correction" ;
public const string Write2HzCorrectionStr = "Write 2Hz correction" ;
public const string DewaReworkRLStr = "DEWA rework R-L" ;
public const string DewaReworkLRStr = "DEWA rework L-R" ;
public const string StartTestingSealedMetersStr = "Start testing sealed meters" ;
public const string EndTestingSealedMetersStr = "End testing sealed meters" ;
public const string SimulateCmd = "simulate " ;
public static Color DisabledColor = Color . DarkGray ;
public static Color OptoAndDirOKColor = Color . Green ;
public static Color OptoNokColor = Color . Orange ;
public static Color DirNokColor = Color . Red ;
#region Simulation / RFID / NFC Interface : ReadRequestPort , WriteRequestPort
/// <summary>
/// Wrapper function with safe interface and unsafe body
/// </summary>
/// <param name="iperlHead">Water meter (iPerlHead) object</param>
/// <returns>Value returned by readRequestPort(...)</returns>
/// <summary>
/// Wrapper function with safe interface and unsafe body
/// </summary>
/// <param name="iperlHead">Water meter (iPerlHead) object</param>
/// <returns>Value returned by writeRequestPort(...)</returns>
#endregion iPerl_Head_RFID_Interface : ReadRequestPort , WriteRequestPort
readonly bool checkBoxesEditMode ;
DateTime startTime ;
int startTimeSec ;
// Set to 'true' when the form closes
public bool Completed { get { return formCompleted ; } }
bool formCompleted ;
bool forcedClose ; /// Set in the forced close handler
/// <summary> Number of text boxes for serial numbers </summary>
public int WaterMetersCount ;
const int MaxTextBoxesCount = 48 ;
int textBoxesCount ;
Label [ ] labels ;
PictureBox [ ] counters ;
TextBox [ ] messages ;
CheckBoxImage [ ] checkBoxes ;
static int [ ] ckbIndex ;
static bool [ ] ckbState ;
static IList < GenesisSmartReader > genesisHeads ;
static IList < int > waterMeterPositions0 ; /// keeps original 0-based indices in RegisterReaders list
static int commonWMType ;
///
/// RFID multiplexer PCB / RFID serial port and worker thread related variables
///
static TestMethod testMethod ;
public static TestMethodCfg cfg ;
static IList < Config . Entities . Test > tests ;
static IList < iPerlCommunicationParams > multiTestParams ;
2026-09-10 20:09:30 +00:00
static volatile int currentActivityStep ;
static volatile int currentGroup ; /// form -> worker thread (0 = none)
2026-09-09 13:04:49 +00:00
static int lastGroup ;
2026-09-10 20:09:30 +00:00
private GenesisWorkerGroupCompletion groupCompletion ;
2026-09-09 13:04:49 +00:00
static IList < Thread > workerThreads ;
static IList < int > muxBrdOrGroup14Nrs ;
2026-09-10 20:09:30 +00:00
static volatile bool stopWorkerThreads ; /// form -> worker thread
2026-09-09 13:04:49 +00:00
/// <summary> Parameterless constructor (without watermeters, threads) </summary>
public GenesisCommunicationForm ( )
{
InitializeComponent ( ) ;
}
/// <summary>
/// Constructor for checkBox states (active/inactive iPerl head) editing.
/// </summary>
/// <param name="checkBoxes">Initial check box states</param>
public GenesisCommunicationForm ( bool isCheckBoxesEditMode )
: this ( )
{
GenesisCommunicationForm . cfg = new TestMethodCfg ( null ) ; // default iPerl Head communication params
if ( isCheckBoxesEditMode )
{
checkBoxesEditMode = true ;
saveButton . Visible = true ;
activityLabel . Text = Strings . Optical_heads ;
ShuffleTextBoxes ( ProcessData . WMsCount , ProcessData . LineSize ) ;
#if IPERL
ContextMenu cm = new ContextMenu ( ) ;
//////////////////////////////////////////////////////////////////////
cm . MenuItems . Add ( NewMenuItem ( "Initialise Slot" , "Initialize" ) ) ;
// cm.MenuItems.Add(NewMenuItem("Update Slot" , "Update"));
// cm.MenuItems.Add(NewMenuItem("Connect Slot" , "Connect"));
cm . MenuItems . Add ( NewMenuItem ( "Login (Combined)" , "Login (Combined)" ) ) ;
cm . MenuItems . Add ( NewMenuItem ( "PCB Slot" , "PCBSlot" ) ) ;
// cm.MenuItems.Add(NewMenuItem("Set Password" , "SetPassword"));
// cm.MenuItems.Add(NewMenuItem("Login" , "Login"));
cm . MenuItems . Add ( NewMenuItem ( "Switch to Test Mode" , "SetTestMode" ) ) ;
cm . MenuItems . Add ( NewMenuItem ( "Switch to Active Mode" , "SetActiveMode" ) ) ;
/////////////////////////////////////////////////////////////////////
this . ContextMenu = cm ;
#endif
}
}
/// <summary>
/// Constructor for one iPerlCommunication 'test'
/// </summary>
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
public GenesisCommunicationForm ( TestMethod testMethod , Test test , iPerlCommunicationParams testParams )
: this ( testMethod , new List < Test > { test } , new List < iPerlCommunicationParams > { testParams } )
{
}
/// <summary>
/// Constructor for multiple iPerlCommunication 'tests'
/// </summary>
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
public GenesisCommunicationForm ( TestMethod testMethod , IList < Test > tests , IList < iPerlCommunicationParams > multiTestParams )
: this ( )
{
checkBoxesEditMode = false ;
GenesisCommunicationForm . testMethod = testMethod ;
GenesisCommunicationForm . cfg = testMethod . Cfg as TestMethodCfg ;
GenesisCommunicationForm . tests = tests ;
GenesisCommunicationForm . multiTestParams = multiTestParams ;
if ( multiTestParams . Count > 0 )
{
ProcessData . RegisterReaders = StateMachine . GetMetersPath ( tests [ 0 ] ) . RegisterReaders ;
activityLabel . Text = multiTestParams [ 0 ] . Activity ;
foreach ( var p in multiTestParams )
{
if ( p . Activity . ToLower ( ) = = GetDefaultQ2CorrectionsStr . ToLower ( ) )
{
/// Reset IsQ2PreCorrectionCalculated that is used for synchronization/to prevent double REST call
ProcessData . IsQ2PreCorrectionCalculated = false ;
commonWMType = 0 ;
break ;
}
}
}
PrepareForTestsActivities ( ) ;
}
private bool CanUseUi ( )
{
return ! IsDisposed & & ! Disposing & & IsHandleCreated ;
}
void PrepareForTestsActivities ( )
{
startTime = DateTime . Now ;
startTimeSec = StateMachine . Time ;
/// Attach to 'CommCompleted' handler
CommCompletedHandler + = delegate ( object sender , CommCompletedEventArgs args )
{
if ( ! CanUseUi ( ) ) return ;
if ( InvokeRequired )
{
try
{
BeginInvoke ( new EventHandler < CommCompletedEventArgs > ( ( s , a ) = >
{
if ( ! CanUseUi ( ) ) return ;
DoOnCommCompleted ( s , a ) ;
} ) , sender , args ) ;
}
catch ( ObjectDisposedException ) { }
catch ( InvalidOperationException ) { }
}
else
{
DoOnCommCompleted ( sender , args ) ;
}
} ;
/// Attach to 'AllCompleted' handler
AllCompletedHandler + = delegate ( object sender , AllCompletedEventArgs args )
{
if ( IsDisposed | | Disposing | | ! IsHandleCreated )
return ;
if ( InvokeRequired )
{
try
{
BeginInvoke ( new EventHandler < AllCompletedEventArgs > ( ( s , a ) = >
{
if ( IsDisposed | | Disposing )
return ;
DoOnAllCompleted ( s , a ) ;
} ) , sender , args ) ;
}
catch ( ObjectDisposedException ) { }
catch ( InvalidOperationException ) { }
}
else
{
DoOnAllCompleted ( sender , args ) ;
}
} ;
formCompleted = false ;
StartForceCloseHandler ( ) ;
genesisHeads = new List < GenesisSmartReader > ( ) ;
waterMeterPositions0 = new List < int > ( ) ;
///
for ( int wmPos = 0 ; wmPos < ProcessData . RegisterReaders . Length ; wmPos + + )
{
GenesisSmartReader genesisSmartReader = ProcessData . RegisterReaders [ wmPos ] as GenesisSmartReader ;
if ( genesisSmartReader ! = null )
{
genesisHeads . Add ( genesisSmartReader ) ;
waterMeterPositions0 . Add ( wmPos ) ;
}
}
WaterMetersCount = genesisHeads . Count ;
ShuffleTextBoxes ( WaterMetersCount , ProcessData . LineSize ) ;
///
/// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc..
///
currentActivityStep = 0 ;
currentGroup = 0 ;
stopWorkerThreads = false ;
/// group numbers are >=1, lastGroup == 0 means there is no group
lastGroup = 0 ;
foreach ( var iPerl in GenesisCommunicationForm . genesisHeads )
{
if ( iPerl . Group > lastGroup ) lastGroup = iPerl . Group ;
}
workerThreads = new List < Thread > ( ) ;
for ( int i = 0 ; i < cfg . NrThreads ; i + + )
{
Thread thread = new Thread ( Worker ) ;
thread . CurrentCulture = CultureInfo . CurrentCulture ;
thread . CurrentUICulture = CultureInfo . CurrentUICulture ;
workerThreads . Add ( thread ) ;
}
muxBrdOrGroup14Nrs = new List < int > ( ) ;
foreach ( var iPerl in GenesisCommunicationForm . genesisHeads )
{
if ( ! muxBrdOrGroup14Nrs . Contains ( iPerl . MuxBoardNrOrGroup14 ) ) muxBrdOrGroup14Nrs . Add ( iPerl . MuxBoardNrOrGroup14 ) ;
}
2026-09-10 20:09:30 +00:00
groupCompletion = new GenesisWorkerGroupCompletion ( workerThreads . Count ) ;
groupCompletion . Begin ( 0 , 1 ) ;
log . InfoFormat ( "Genesis workers configured: Threads={0}, Group1Count={1}, LastGroup2={2}" , workerThreads . Count , muxBrdOrGroup14Nrs . Count , lastGroup ) ;
2026-09-09 13:04:49 +00:00
log . WarnFormat ( "nrThreads = {0}" , workerThreads . Count ) ;
}
/// <summary>
/// Make sure the layout of labels/text boxes on the screen
/// corresponds to the layout of watermeters of the test bench.
/// </summary>
/// <param name="wmsCount">Number of watermeters</param>
/// <param name="lineSize">Number of watermeters in one line</param>
void ShuffleTextBoxes ( int wmsCount , int lineSize )
{
labels = new Label [ MaxTextBoxesCount ]
{
wmLabel1 , wmLabel2 , wmLabel3 , wmLabel4 , wmLabel5 , wmLabel6 , wmLabel7 , wmLabel8 , wmLabel9 , wmLabel10 ,
wmLabel11 , wmLabel12 , wmLabel13 , wmLabel14 , wmLabel15 , wmLabel16 , wmLabel17 , wmLabel18 , wmLabel19 , wmLabel20 ,
wmLabel21 , wmLabel22 , wmLabel23 , wmLabel24 , wmLabel25 , wmLabel26 , wmLabel27 , wmLabel28 , wmLabel29 , wmLabel30 ,
wmLabel31 , wmLabel32 , wmLabel33 , wmLabel34 , wmLabel35 , wmLabel36 , wmLabel37 , wmLabel38 , wmLabel39 , wmLabel40 ,
wmLabel41 , wmLabel42 , wmLabel43 , wmLabel44 , wmLabel45 , wmLabel46 , wmLabel47 , wmLabel48 ,
} ;
counters = new PictureBox [ MaxTextBoxesCount ]
{
pictureBox1 , pictureBox2 , pictureBox3 , pictureBox4 , pictureBox5 , pictureBox6 , pictureBox7 , pictureBox8 , pictureBox9 , pictureBox10 ,
pictureBox11 , pictureBox12 , pictureBox13 , pictureBox14 , pictureBox15 , pictureBox16 , pictureBox17 , pictureBox18 , pictureBox19 , pictureBox20 ,
pictureBox21 , pictureBox22 , pictureBox23 , pictureBox24 , pictureBox25 , pictureBox26 , pictureBox27 , pictureBox28 , pictureBox29 , pictureBox30 ,
pictureBox31 , pictureBox32 , pictureBox33 , pictureBox34 , pictureBox35 , pictureBox36 , pictureBox37 , pictureBox38 , pictureBox39 , pictureBox40 ,
pictureBox41 , pictureBox42 , pictureBox43 , pictureBox44 , pictureBox45 , pictureBox46 , pictureBox47 , pictureBox48 ,
} ;
messages = new TextBox [ MaxTextBoxesCount ]
{
wmTextBox1 , wmTextBox2 , wmTextBox3 , wmTextBox4 , wmTextBox5 , wmTextBox6 , wmTextBox7 , wmTextBox8 , wmTextBox9 , wmTextBox10 ,
wmTextBox11 , wmTextBox12 , wmTextBox13 , wmTextBox14 , wmTextBox15 , wmTextBox16 , wmTextBox17 , wmTextBox18 , wmTextBox19 , wmTextBox20 ,
wmTextBox21 , wmTextBox22 , wmTextBox23 , wmTextBox24 , wmTextBox25 , wmTextBox26 , wmTextBox27 , wmTextBox28 , wmTextBox29 , wmTextBox30 ,
wmTextBox31 , wmTextBox32 , wmTextBox33 , wmTextBox34 , wmTextBox35 , wmTextBox36 , wmTextBox37 , wmTextBox38 , wmTextBox39 , wmTextBox40 ,
wmTextBox41 , wmTextBox42 , wmTextBox43 , wmTextBox44 , wmTextBox45 , wmTextBox46 , wmTextBox47 , wmTextBox48 ,
} ;
checkBoxes = new CheckBoxImage [ MaxTextBoxesCount ]
{
checkBoxImage1 , checkBoxImage2 , checkBoxImage3 , checkBoxImage4 , checkBoxImage5 , checkBoxImage6 , checkBoxImage7 , checkBoxImage8 , checkBoxImage9 , checkBoxImage10 ,
checkBoxImage11 , checkBoxImage12 , checkBoxImage13 , checkBoxImage14 , checkBoxImage15 , checkBoxImage16 , checkBoxImage17 , checkBoxImage18 , checkBoxImage19 , checkBoxImage20 ,
checkBoxImage21 , checkBoxImage22 , checkBoxImage23 , checkBoxImage24 , checkBoxImage25 , checkBoxImage26 , checkBoxImage27 , checkBoxImage28 , checkBoxImage29 , checkBoxImage30 ,
checkBoxImage31 , checkBoxImage32 , checkBoxImage33 , checkBoxImage34 , checkBoxImage35 , checkBoxImage36 , checkBoxImage37 , checkBoxImage38 , checkBoxImage39 , checkBoxImage40 ,
checkBoxImage41 , checkBoxImage42 , checkBoxImage43 , checkBoxImage44 , checkBoxImage45 , checkBoxImage46 , checkBoxImage47 , checkBoxImage48 ,
} ;
ckbIndex = new int [ MaxTextBoxesCount ] ;
ckbState = new bool [ MaxTextBoxesCount ] ;
textBoxesCount = MaxTextBoxesCount ;
///
if ( wmsCount < textBoxesCount & & lineSize > 0 )
{
int nrLines = ( wmsCount + lineSize - 1 ) / lineSize ;
int gap = ( textBoxesCount - wmsCount ) / nrLines ;
for ( int i = 0 ; i < ckbIndex . Length ; i + + )
{
ckbIndex [ i ] = - 1 ; /// Initialize with invalid indices
}
int dest = 0 ;
for ( int l = 0 ; l < nrLines ; l + + )
{
for ( int i = 0 ; i < lineSize ; i + + )
{
int origin = l * lineSize + l * gap + i ;
labels [ dest ] = labels [ origin ] ;
counters [ dest ] = counters [ origin ] ;
messages [ dest ] = messages [ origin ] ;
checkBoxes [ dest ] = checkBoxes [ origin ] ;
ckbIndex [ origin ] = dest ;
dest + + ;
}
}
textBoxesCount = wmsCount ;
}
int count = checkBoxesEditMode ? textBoxesCount : Math . Min ( textBoxesCount , genesisHeads . Count ) ;
for ( int j = 0 ; j < count ; j + + )
{
labels [ j ] . Text = ( j + 1 ) . ToString ( ) ;
}
ResizeDlgToFitEnabledControls ( ) ;
}
void ResizeDlgToFitEnabledControls ( )
{
int xMax = 0 ;
int yMax = 0 ;
for ( int i = 0 ; i < textBoxesCount ; i + + )
{
if ( messages [ i ] . Left + messages [ i ] . Width > xMax ) xMax = messages [ i ] . Left + messages [ i ] . Width ;
if ( messages [ i ] . Top + messages [ i ] . Height > yMax ) yMax = messages [ i ] . Top + messages [ i ] . Height ;
}
Width = xMax + 50 ;
Height = yMax + 60 ;
}
void Localize ( )
{
Text = checkBoxesEditMode ? Strings . Optical_heads : Strings . Water_Meter_States ;
saveButton . Text = Strings . Save ;
sampleLabel1 . Text = Strings . Direction_and_pulses_are_OK ;
sampleLabel2 . Text = Strings . There_are_no_opto_pulses ;
sampleLabel3 . Text = Strings . Direction_is_NOK ;
samplePictureBox1 . BackColor = OptoAndDirOKColor ;
samplePictureBox2 . BackColor = OptoNokColor ;
samplePictureBox3 . BackColor = DirNokColor ;
}
private void GenesisCommunicationForm_Load ( object sender , EventArgs e )
{
Localize ( ) ;
if ( checkBoxesEditMode )
{
/// Check box edit mode => Hide explanation of activity colours
sampleLabel1 . Visible = false ;
sampleLabel2 . Visible = false ;
sampleLabel3 . Visible = false ;
samplePictureBox1 . Visible = false ;
samplePictureBox2 . Visible = false ;
samplePictureBox3 . Visible = false ;
}
///
/// Set checkbox states accroding to iPerlHeads[i].Disabled states
///
for ( int i = 0 ; i < textBoxesCount ; i + + )
{
labels [ i ] . Visible = counters [ i ] . Visible = messages [ i ] . Visible = checkBoxes [ i ] . Visible = true ;
if ( ! checkBoxesEditMode & & ( genesisHeads [ i ] = = null | | genesisHeads [ i ] . Disabled ) )
{
/// iPerl position i+1 is disabled
checkBoxes [ i ] . Enabled = checkBoxes [ i ] . Checked = ckbState [ i ] = false ;
counters [ i ] . BackColor = DisabledColor ;
messages [ i ] . Text = Strings . Head_was_disabled_by_the_user ;
}
else
{
/// iPerl position i+1 is enabled
checkBoxes [ i ] . Enabled = checkBoxes [ i ] . Checked = ckbState [ i ] = true ;
messages [ i ] . Text = "---" ;
}
}
///
/// 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 ( ! checkBoxesEditMode )
{
/// Regular activity (not a checkbox edit mode invoked from TBF menu)
/// Reset opto-data indication
for ( int i = 0 ; i < genesisHeads . Count ; i + + )
{
counters [ i ] . BackColor = OptoNokColor ;
}
/// Start communication process by incrementing 'currentGroup'.
currentGroup + + ;
int wtId = 0 ;
foreach ( var wt in workerThreads )
{
wt . Start ( new Boxes . IntBox ( wtId + + ) ) ; /// Start worker threads !!!
}
}
}
private void NormalClose ( )
{
CommCompletedHandler = null ;
AllCompletedHandler = null ;
if ( multiTestParams ! = null & &
multiTestParams . Count > 0 & &
! multiTestParams [ 0 ] . SimultWithNext ) /// RFID Communication at the end of the cycle does not influence the result
{
UpdateRfidCommResult ( tests ) ; /// TODO: Pass the test info in a correct way
}
long checkboxStates = GetCheckBoxStates ( ) ;
if ( Program . LocalSettings . iPerlCommunicationsFormLeft ! = Location . X | |
Program . LocalSettings . iPerlCommunicationsFormTop ! = Location . Y | |
Program . LocalSettings . OptoHeadsEnabled ! = checkboxStates )
{
/// Update local settings
Program . LocalSettings . iPerlCommunicationsFormLeft = Location . X ;
Program . LocalSettings . iPerlCommunicationsFormTop = Location . Y ;
Program . LocalSettings . OptoHeadsEnabled = checkboxStates ;
Program . LocalSettings . Save ( ) ;
}
formCompleted = true ;
DialogResult = DialogResult . OK ;
Close ( ) ;
}
#region Forced close handling
public void StartForceCloseHandler ( )
{
UiBridge . Bridge . CloseModelessFormHandler + = delegate ( object sender , EventArgs args )
{
if ( InvokeRequired ) { Invoke ( new EventHandler < EventArgs > ( OnForceClose ) , sender , args ) ; }
else OnForceClose ( sender , args ) ;
} ;
}
void OnForceClose ( object sender , EventArgs args )
{
CommCompletedHandler = null ;
AllCompletedHandler = null ;
stopWorkerThreads = true ;
forcedClose = true ;
DialogResult = DialogResult . Cancel ;
Close ( ) ;
}
#endregion
private static int _messageBoxActive = 0 ;
// blocked while MessageBox is active
private static readonly ManualResetEventSlim _messageBoxDone =
new ManualResetEventSlim ( true ) ;
/// <summary>
/// Worker thread
/// </summary>
/// <param name="threadData">Thread ID (integer) wrapped into IntBox</param>
void Worker ( object threadData )
{
int threadID = ( threadData as Boxes . IntBox ) . Val ;
int activityStep = 0 ; /// activity step > 0 in case multiTestParams are used
for ( int i = 0 ; i < multiTestParams . Count ; i + + )
{
2026-09-10 20:09:30 +00:00
while ( activityStep ! = currentActivityStep & & ! stopWorkerThreads ) Thread . Sleep ( 50 ) ;
if ( stopWorkerThreads ) break ;
2026-09-09 13:04:49 +00:00
Test currentTest = tests [ i ] ;
iPerlCommunicationParams currentTestParams = multiTestParams [ i ] ;
string currentActivity = currentTestParams . Activity ; /// Current activity
TBF . UiBridge . TestProgressEventArgs . SetEstimatedTimes ( new int [ ] { 0 , 0 , 10 , 0 , 140 , 0 , 0 , 0 } ) ;
TBF . UiBridge . Bridge . OnTestProgress ( null , new TBF . UiBridge . TestProgressEventArgs ( tests [ i ] , Progress . JustStarted ) ) ;
if ( threadID = = 0 )
{
/// Check whether previous activity was 'Set test mode A0' or 'A4'
if ( i > 0 & & multiTestParams [ i - 1 ] . Activity . ToLower ( ) . Contains ( SetTestModeStr . ToLower ( ) ) & & ! multiTestParams [ i - 1 ] . Activity . Contains ( "80" ) )
{
/// Start processing of opto-datastreams from all iPERL-s
int count = 0 ;
for ( int wmNr0 = 0 ; wmNr0 < genesisHeads . Count ; wmNr0 + + )
{
WaterMeter wm = ( ProcessData . BatchRslts . Batch . WaterMeters ! = null & & ProcessData . BatchRslts . Batch . WaterMeters . Count > wmNr0 )
? ProcessData . BatchRslts . Batch . WaterMeters [ wmNr0 ] : null ;
GenesisSmartReader ihead = genesisHeads [ wmNr0 ] ;
if ( ihead ! = null & & wm ! = null & & ! wm . Disabled )
{
lock ( ihead )
{
ihead . StartDataStreamProcessing ( ) ;
count + + ;
}
}
}
log . WarnFormat ( "End of activity '{0}', StartDataStreamProcessing() of {1} heads was called." , multiTestParams [ i - 1 ] . Activity , count ) ;
}
/// A new activity starts - information into RFID data log
rfidDataLogger . InfoFormat ( "" ) ;
rfidDataLogger . WarnFormat ( "Activity = {0}" , currentActivity ) ;
rfidDataLogger . InfoFormat ( "" ) ;
}
//HOLD ON - if activity is like HoldSlotStr, ignore loop and do activity like HoldSlotStr
2026-09-10 20:09:30 +00:00
bool isHoldActivity = currentActivity . ToLower ( ) . Equals ( HoldSlotStr . ToLower ( ) ) ;
if ( isHoldActivity )
2026-09-09 13:04:49 +00:00
{
log . Debug ( $"Activity '{currentActivity}' is HoldSlotStr, skipping loop and performing HoldOn operation. Thread: {threadID}" ) ;
CommErr error ;
string resultStr = string . Empty ;
error = HoldOn ( threadID , ref resultStr ) ; // wait for the hold on to complete - one time for each thread
ProcessWaterMetersDialogConfirmation ( threadID , resultStr , error ) ;
}
for ( int group = 1 ; group < = lastGroup ; group + + )
{
/// Synchronize with QuidoRS and other threads
while ( ( ( group ! = currentGroup ) | | ( activityStep ! = currentActivityStep ) ) & & ! stopWorkerThreads )
{
Thread . Sleep ( 50 ) ;
}
if ( stopWorkerThreads ) break ;
2026-09-10 20:09:30 +00:00
if ( ! isHoldActivity )
{
2026-09-09 13:04:49 +00:00
#if TURA_SPECIAL
int threadIx = threadID ; /// Just one thread for TURA_SPECIAL
#else
2026-09-10 20:09:30 +00:00
foreach ( int threadIx in GenesisWorkerGroupCompletion . BoardIndexes ( threadID , workerThreads . Count , muxBrdOrGroup14Nrs . Count ) )
2026-09-09 13:04:49 +00:00
#endif
{
bool wmFound = false ;
for ( int wmNr0 = 0 ; wmNr0 < genesisHeads . Count ; wmNr0 + + )
{
GenesisSmartReader ihead = genesisHeads [ wmNr0 ] ;
if ( ( ihead . Group = = group ) & & ( threadIx < muxBrdOrGroup14Nrs . Count ) & & ( ihead . MuxBoardNrOrGroup14 = = muxBrdOrGroup14Nrs [ threadIx ] ) )
{
wmFound = true ;
WaterMeter wm = null ;
if ( ProcessData . BatchRslts . Batch . WaterMeters ! = null )
{
foreach ( var w in ProcessData . BatchRslts . Batch . WaterMeters )
{
if ( w . WMPosition = = wmNr0 + 1 )
{
wm = w ;
break ;
}
}
}
CommErr error ;
string resultStr = string . Empty ;
///
/// RFID communication activity call
///
if ( ( ihead = = null ) | | ihead . Disabled | | ! ckbState [ wmNr0 ] ) error = CommErr . HeadDisabledByUser ;
#if IPERL
else if ( currentActivity . ToLower ( ) . Equals ( SlotInitializeStr . ToLower ( ) ) ) error = SlotInitialize ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotUpdateStr . ToLower ( ) ) ) error = SlotUpdate ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotConnectStr . ToLower ( ) ) ) error = SlotConnect ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotPCBSlotStr . ToLower ( ) ) ) error = SlotPCBSlot ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotSetPasswordStr . ToLower ( ) ) ) error = SlotSetPassword ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotLoginStr . ToLower ( ) ) ) error = SlotLogin ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotGroupedLoginStr . ToLower ( ) ) ) error = SlotGroupedLogin ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotSetTestModeStr . ToLower ( ) ) ) error = SlotSetTestMode ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotSetActiveModeStr . ToLower ( ) ) ) error = SlotSetActiveMode ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SlotDisconnectStr . ToLower ( ) ) ) error = SlotDisconnect ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( PrepareSlotQ3CalibrationStr . ToLower ( ) ) ) error = PrepareSlotQ3Calibration ( threadID , ihead , wm , currentTest , tests , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( WriteSlotQ3CalibrationStr . ToLower ( ) ) ) error = WriteSlotQ3Calibration ( threadID , ihead , wm , currentTest , tests , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( CheckMeterPrepareStr . ToLower ( ) ) ) error = CheckMeterPrepare ( threadID , ihead , ref resultStr ) ;
//TODO MAREK dorobit dalsie moznosti podla vzoru
else if ( currentActivity . ToLower ( ) . Contains ( ReadSerialNrStr . ToLower ( ) ) ) error = ReadSerialNr ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Contains ( SetTestModeStr . ToLower ( ) ) ) error = SetTestMode ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SetActiveModeStr . ToLower ( ) ) ) error = SetActiveMode ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Equals ( SetIdleModeStr . ToLower ( ) ) ) error = SetIdleMode ( threadID , ihead , ref resultStr ) ;
else if ( currentActivity . ToLower ( ) . Contains ( ReadConfigurationStr . ToLower ( ) ) ) error = ReadConfiguration ( ihead , wm , ref resultStr ) ;
///
/// RFID communication functions below require a reference to water meter entity (wm != null)
///
else if ( wm = = null ) error = CommErr . CommFailed ;
else if ( currentActivity . ToLower ( ) . Contains ( SimulateCmd . ToLower ( ) ) ) error = Simulate ( ihead , wm , ref resultStr ) ;
#endif
else
{
error = CommErr . None ;
ConditionID id = ConditionID . Count ;
#if IPERL
for ( id = ConditionID . A ; id < ConditionID . Count ; id + + )
{
if ( currentActivity . ToLower ( ) = = string . Format ( SequenceConditionOp . ConditionNameFmt , id ) . ToLower ( ) )
{
error = SetIperlCommMilestoneReached ( testMethod , id , ref resultStr ) ;
break ;
}
}
#endif
if ( id = = ConditionID . Count )
{
resultStr = "Invalid activity" ; /// No activity or milestone
}
}
///
/// Process the result of RFID communication activity
///
if ( error = = CommErr . HeadDisabledByUser | | ! ckbState [ wmNr0 ] )
{
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , Strings . Head_was_disabled_by_the_user , CommErr . HeadDisabledByUser ) ) ;
}
else if ( error = = CommErr . None )
{
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , resultStr , CommErr . None ) ) ;
}
else if ( ( error = = CommErr . OutOfRange ) | | ( error = = CommErr . Q2OutOfRange ) )
{
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , resultStr , CommErr . CommFailed ) ) ;
}
else if ( ( error = = CommErr . FailedInit ) | |
( error = = CommErr . FailedConnect ) | |
( error = = CommErr . FailedReadSerialNr ) | |
( error = = CommErr . FailedSetPassword ) | |
( error = = CommErr . FailedLogin ) | |
( error = = CommErr . FailedSetTestMode ) | |
( error = = CommErr . FailedSetActiveMode ) | |
( error = = CommErr . FailedWriteRegister ) | |
( error = = CommErr . FailedWriteCalibrationFactor ) | |
( error = = CommErr . FailedPrepare )
)
{
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , resultStr , error ) ) ;
}
else if ( ihead . CommFailed | | ( error = = CommErr . CommFailed ) )
{
ihead . CommFailed = true ;
if ( wm ! = null & & ( wm . ResultCode & ( int ) Results . Entities . ResultCode . RfidErrorCodeMask ) = = 0 )
{
wm . ResultCode | = ( ( ( int ) error < < 16 ) | ( ( int ) tests [ i ] . ItemNr < < 20 ) ) ;
}
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , Strings . Radio_Communication_failed , error ) ) ;
}
else
{
ihead . CommFailed = true ;
if ( wm ! = null & & ( wm . ResultCode & ( int ) Results . Entities . ResultCode . RfidErrorCodeMask ) = = 0 )
{
wm . ResultCode | = ( ( ( int ) error < < 16 ) | ( ( int ) tests [ i ] . ItemNr < < 20 ) ) ;
}
string failureCauseLocal = string . Format ( Strings . failed_0_1_exclamation , currentActivity , error ) ;
rfidDataLogger . ErrorFormat ( "Group={0}, Board={1}, {2}" , currentGroup , ihead . MuxBoardNrOrGroup14 , failureCauseLocal ) ;
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , failureCauseLocal , error ) ) ;
}
break ;
}
TBF . UiBridge . Bridge . OnTestProgress ( null , new TBF . UiBridge . TestProgressEventArgs ( tests [ i ] , Progress . FlowSetting ) ) ;
}
if ( ! wmFound )
{
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , - 1 , null , null , string . Empty , CommErr . None ) ) ; /// Send negative wmNr
}
Thread . Sleep ( 2000 ) ;
if ( stopWorkerThreads ) break ;
}
2026-09-10 20:09:30 +00:00
}
if ( stopWorkerThreads ) break ;
log . DebugFormat ( "Genesis worker group completed: Activity={0}, Group2={1}, Worker={2}" , activityStep , group , threadID ) ;
OnCommCompleted ( null , new CommCompletedEventArgs ( threadID , - 1 , null , null , string . Empty , CommErr . None )
{ WorkerGroupCompleted = true , ActivityStep = activityStep , Group = group } ) ;
} /// for (int group
2026-09-09 13:04:49 +00:00
TBF . UiBridge . Bridge . OnTestProgress ( null , new TBF . UiBridge . TestProgressEventArgs ( tests [ i ] , Progress . Completed ) ) ;
activityStep + + ;
if ( stopWorkerThreads ) break ;
}
}
private CommErr CheckMeterPrepare ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedWriteRegister ;
var gciFullLoginResult = iHead . OptoHeadTest . CheckMeterPrepare ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) & & resultStr . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . Debug ( "CheckMeterPrepare successful" ) ;
resultStr = string . Format ( $"Check Meter Prepare: OK" ) ;
// note Q3 calibration is done
error = CommErr . None ;
}
else
{
resultStr = "Check Meter Prepare: Failed" ;
}
return error ;
}
/// <summary>
/// Set the state messages in WaterMeters Dialog Confirmation
/// Use after HoldOn()
/// </summary>
/// <param name="threadID"></param>
/// <param name="resultStr"></param>
private static void ProcessWaterMetersDialogConfirmation ( int threadID , string resultStr , CommErr commErr )
{
bool wmFound = false ;
for ( int wmNr0 = 0 ; wmNr0 < genesisHeads . Count ; wmNr0 + + )
{
GenesisSmartReader ihead = genesisHeads [ wmNr0 ] ;
wmFound = true ;
WaterMeter wm = null ;
if ( ProcessData . BatchRslts . Batch . WaterMeters ! = null )
{
foreach ( var w in ProcessData . BatchRslts . Batch . WaterMeters )
{
if ( w . WMPosition = = wmNr0 + 1 )
{
wm = w ;
break ;
}
}
}
OnCommCompleted ( null ,
new CommCompletedEventArgs ( threadID , wmNr0 , ihead , wm , resultStr , commErr ) ) ;
}
}
private CommErr HoldOn ( int threadId , ref string resultStr )
{
log . InfoFormat ( "HoldOn() threadId={0}" , threadId ) ;
CommErr error = CommErr . CommFailed ;
// only first thread enters here
if ( Interlocked . CompareExchange ( ref _messageBoxActive , 1 , 0 ) = = 0 )
{
try
{
// block other threads
_messageBoxDone . Reset ( ) ;
if ( this . InvokeRequired )
{
this . Invoke ( new Action ( ( ) = > { MessageBox . Show ( this , "Confirm when you are ready to continue." , "Communication HOLD ON" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ; } ) ) ;
}
else
{
MessageBox . Show ( this , "Confirm when you are ready to continue." , "Communication HOLD ON" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
}
}
finally
{
// release all waiting threads after OK
Interlocked . Exchange ( ref _messageBoxActive , 0 ) ;
_messageBoxDone . Set ( ) ;
}
}
else
{
// other threads wait here until OK is pressed
_messageBoxDone . Wait ( ) ;
}
error = CommErr . None ;
return error ;
}
private CommErr PrepareSlotQ3Calibration ( int threadId , GenesisSmartReader iHead , WaterMeter wm ,
Test currentTest , IList < Test > tests , ref string resultStr )
{
CommErr error = CommErr . FailedPrepare ;
//TODO BUMI get Next test method
log . InfoFormat ( "PrepareSlotQ3Calibration() threadId={0}" , threadId ) ;
try
{
//there is only currecnt test method
//find all tests in Procedure and set the test method
log . Debug ( $"StateMachne Procedure:{StateMachine.Procedure?.Name}" ) ;
log . Debug ( $"StateMachne TestInstances:{StateMachine.TestInstances?.Length}" ) ;
IList < Test > procedureTests = StateMachine . Procedure ? . Tests ;
Test NextTest = null ;
bool bNextChatch = false ;
foreach ( Test test in procedureTests )
{
if ( test . Equals ( currentTest ) )
{
bNextChatch = true ;
continue ;
}
if ( bNextChatch )
{
NextTest = test ;
break ;
}
}
var gciFullLoginResult = iHead . OptoHeadTest . PrepareQ3Calibration ( cfg , NextTest , wm ) ;
log . Debug ( $"PrepareSlotQ3Calibration(threadId: {threadId}, iHead: {iHead?.Name}) result:{gciFullLoginResult}" ) ;
if ( ! string . IsNullOrEmpty ( gciFullLoginResult ) & &
gciFullLoginResult . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . DebugFormat ( "PrepareQ3Calibration successfull threadId={0} head={1}" , threadId , iHead ? . Name ) ;
resultStr = string . Format ( $"Write Q3 Calibration: OK" ) ;
// note Q3 calibration is done
error = CommErr . None ;
}
else
{
log . DebugFormat ( "PrepareQ3Calibration failed threadId={0} head={1}" , threadId , iHead ? . Name ) ;
resultStr = "Write Q3 Calibration: Failed" ;
}
return error ;
} catch ( Exception ex )
{
log . ErrorFormat ( "PrepareSlotQ3Calibration() threadId={0}, iHead: {1}, Error: {2}" , threadId , iHead , ex . Message ) ;
return CommErr . FailedPrepare ;
}
}
private CommErr WriteSlotQ3Calibration ( int threadId , GenesisSmartReader iHead , WaterMeter wm ,
Test currentTest , IList < Test > tests , ref string resultStr )
{
CommErr error = CommErr . FailedWriteCalibrationFactor ;
log . DebugFormat ( "WriteSlotQ3Calibration() threadId={0}, iHead: {1}, wm: {2}, currentTest: {3}, tests: {4}" , threadId , iHead ? . Name , wm ? . Id , currentTest ? . Name , tests ? . Count ) ;
//TODO BUMI get Before test method
try
{
//there is only currecnt test method
//find all tests in Procedure and set the test method
log . Debug ( $"StateMachne Procedure:{StateMachine.Procedure?.Name}" ) ;
log . Debug ( $"StateMachne TestInstances:{StateMachine.TestInstances?.Length}" ) ;
IList < Test > procedureTests = StateMachine . Procedure ? . Tests ;
Test BeforeTest = null ;
foreach ( Test test in procedureTests )
{
if ( test . Equals ( currentTest ) )
{
log . DebugFormat ( "WriteSlotQ3Calibration() threadId={0}, currentTest: {1}, BeforeTest: {2}" , threadId , currentTest ? . Name , BeforeTest ? . Name ) ;
break ;
}
BeforeTest = test ;
}
if ( BeforeTest = = null )
{
log . DebugFormat ( $"No Before test method found, we use the current test method threadId={0}, currentTest: {1}" , threadId , currentTest ? . Name ) ;
BeforeTest = currentTest ;
}
2026-09-16 08:23:04 +00:00
// Keep the Q3 measurement result on the preceding test, but validate against the
// limits configured on the current "Write Q3 Calibration Slot" activity.
var gciFullLoginResult = iHead . OptoHeadTest . WriteQ3Calibration ( cfg , BeforeTest , wm , currentTest ) ;
2026-09-09 13:04:49 +00:00
if ( ! string . IsNullOrEmpty ( gciFullLoginResult ) & &
gciFullLoginResult . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . Debug ( "SlotLogin successful" ) ;
resultStr = string . Format ( $"Write Q3 Calibration: OK" ) ;
// note Q3 calibration is done
error = CommErr . None ;
}
else
{
resultStr = "Write Q3 Calibration: Failed" ;
}
return error ;
}
catch ( Exception ex )
{
log . ErrorFormat ( "WriteSlotQ3Calibration() threadId={0}, Error: {1}" , threadId , ex . Message ) ;
return CommErr . FailedWriteCalibrationFactor ;
}
}
private CommErr SlotGroupedLogin ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedLogin ;
var gciFullLoginResult = iHead . OptoHeadTest . GroupedLoginSlot ( ) ;
if ( gciFullLoginResult . Success )
{
log . Debug ( $"SlotLogin Head:{iHead.Name} successful, PCB: {gciFullLoginResult?.PcbResult?.Result?.PcbId}" ) ;
resultStr = string . Format ( $"Login OK - Serial No: {gciFullLoginResult?.PcbResult?.Result?.PcbId}" ) ;
log . Debug ( $"Setting PCB: {gciFullLoginResult?.PcbResult?.Result?.PcbId} for Head: {iHead.Name}" ) ;
iHead . SerialNr = gciFullLoginResult ? . PcbResult ? . Result ? . PcbId ;
if ( iHead . ConfigStruct ! = null )
{
iHead . ConfigStruct . PCBNumberString = gciFullLoginResult ? . PcbResult ? . Result ? . PcbId ;
}
error = CommErr . None ;
}
else
{
resultStr = "Failed Combined Login" ;
}
return error ;
}
private CommErr SlotDisconnect ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedSetActiveMode ;
bool result = iHead . OptoHeadTest . TurnOffRadio ( ) ;
if ( result )
{
log . Debug ( "SlotDisconnect successful" ) ;
resultStr = string . Format ( $"Slot Disconnected: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Disconnect Slot" ;
}
return error ;
}
private CommErr SlotSetActiveMode ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedSetActiveMode ;
resultStr = iHead . OptoHeadTest . SetActiveModeSlot ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) & & resultStr . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . Debug ( "SlotSetActiveMode successful" ) ;
resultStr = string . Format ( $"Serial No: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Read Serial No" ;
}
return error ;
}
private CommErr SlotSetTestMode ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedSetTestMode ;
resultStr = iHead . OptoHeadTest . SetTestModeSlot ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) & & resultStr . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . Debug ( "SlotSetTestMode successful" ) ;
resultStr = string . Format ( $"SlotSetTestMode: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Set Test Mode" ;
}
return error ;
}
private CommErr SlotLogin ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedLogin ;
resultStr = iHead . OptoHeadTest . LoginSlot ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) & & resultStr . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . Debug ( "SlotLogin successful" ) ;
resultStr = string . Format ( $"SlotLogin: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed SlotLogin" ;
}
return error ;
}
private CommErr SlotSetPassword ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedSetPassword ;
resultStr = iHead . OptoHeadTest . SetPasswordSlot ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) & & resultStr . Equals ( TBF . Rig . RegisterReaders . GenesisRegReader . communication . OptoHeadTest . ResultOk ) )
{
log . Debug ( "SlotSetPassword successful" ) ;
resultStr = string . Format ( $"SlotSetPassword: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Set Password" ;
}
return error ;
}
private CommErr SlotPCBSlot ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedReadSerialNr ;
PcbReadResult pcbReadSlot = iHead . OptoHeadTest . PCB_ReadSlot ( ) ;
if ( pcbReadSlot . Success )
{
var pcbId = pcbReadSlot ? . PcbId ;
log . Debug ( $"SlotPCBSlot Head:{iHead.Name} successful, PCB:{pcbId}" ) ;
resultStr = string . Format ( $"SlotPCBSlot: {pcbId}" ) ;
if ( ! string . IsNullOrWhiteSpace ( pcbId ) )
{
log . Debug ( $"Setting PCB: {pcbId} for Head: {iHead.Name}" ) ;
iHead . SerialNr = pcbId ;
if ( iHead . ConfigStruct ! = null ) iHead . ConfigStruct . PCBNumberString = pcbId ;
}
error = CommErr . None ;
}
else
{
resultStr = "Failed SlotPCBSlot" ;
}
return error ;
}
private CommErr SlotConnect ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
CommErr error = CommErr . FailedConnect ;
resultStr = iHead . OptoHeadTest . ConnectSlot ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) )
{
log . Debug ( "SlotConnect successful" ) ;
resultStr = string . Format ( $"SlotConnect: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Connect Slot" ;
}
return error ;
}
private CommErr SlotUpdate ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
resultStr = iHead . OptoHeadTest . UpdateSlot ( ) ;
return CommErr . None ;
}
private CommErr SlotInitialize ( int threadId , GenesisSmartReader iHead , ref string resultStr )
{
log . Debug ( "SlotInitialize - thrededId = " + threadId ) ;
CommErr error = CommErr . FailedInit ;
resultStr = iHead . OptoHeadTest . InitialiseSlot ( ) ;
if ( ! string . IsNullOrEmpty ( resultStr ) )
{
log . Debug ( "SlotInitialize successful" ) ;
resultStr = string . Format ( $"SlotInitialize: {resultStr}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Init Slot" ;
}
return error ;
}
private CommErr ReadSerialNr ( int threadId , GenesisSmartReader ihead , ref string resultStr )
{
log . Debug ( "ReadSerialNr threadId=" + threadId + ", ihead=" + ihead . ToString ( ) ) ;
if ( ihead . ConfigStruct = = null )
{
log . Debug ( "ConfigStruct is null - created new in ReadSerialNr()" ) ;
ihead . ConfigStruct = new TBF . Rig . RegisterReaders . GenesisRegReader . implementations . ConfigStruct ( ) ;
}
if ( ihead . CommFailed | | ihead . ConfigStruct = = null ) return CommErr . CommFailed ;
//I will do communication to meter now
CommErr error = CommErr . Read ;
var result = ihead . OptoHeadTest . ReadRequest_PCB ( ) ;
if ( ! string . IsNullOrEmpty ( result ) )
{
log . Debug ( "ReadSerialNr successful" ) ;
resultStr = string . Format ( $"Serial No: {result}" ) ;
error = CommErr . None ;
}
else
{
resultStr = "Failed Read Serial No" ;
}
return error ;
}
private CommErr SetIdleMode ( int threadId , GenesisSmartReader ihead , ref string resultStr )
{
log . Debug ( "SetActiveMode threadId=" + threadId ) ;
CommErr error = CommErr . CmdActive ;
/// Switch to active mode
if ( ihead . OptoHeadTest . SetIdleMode ( ) )
{
error = CommErr . None ;
}
if ( error = = CommErr . None )
{
if ( ihead . ConfigStruct = = null )
resultStr = "OK (Config not available)" ;
else
resultStr = ihead . ConfigStruct . GetStatusModeString ( ) ;
}
return error ;
}
#region Communication functions
#if IPERL
/// <summary>
/// Read a complete configuration structure of the watermeter
/// </summary>
/// <param name="ihead">iPERL head object</param>
/// <param name="wm">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr ReadConfiguration ( GenesisSmartReader ihead , WaterMeter wm , ref string resultStr )
{
// TODO BUMI in clasic case we need to read most of data - see ConfigStruct
///
/// The activity is "Read configuration" (this enables the watermeter, resets error flag)
/// or "Read configuration if enabled" (this keeps the error flag).
///
if ( ! multiTestParams [ currentActivityStep ] . Activity . ToLower ( ) . Contains ( " if enabled" ) )
{
ihead . CommFailed = false ;
}
if ( ihead . CommFailed ) return CommErr . CommFailed ;
//zeroing
ihead . ConfigStruct = null ; /// Clear previous ConfigStruct, avoid reuse of (not anymore valid) PCB Number
CommErr error = CommErr . Read ;
int readRetVal = 0 ;
/// Read configuration
if ( ihead . OptoHeadTest . ReadConfiguration ( DiagnosticLedState . State4 ) )
{
error = CommErr . None ;
//read, set and create ConfigStruct is set directly in method ReadConfiguration
//ihead.ConfigStruct = new ConfigStruct(); //.FromByteArray(config);
if ( ihead . ConfigStruct ! = null )
{
resultStr = ihead . ConfigStruct . ToString ( 1 ) ;
}
else
{
resultStr = "Data not available" ;
}
}
else
{
resultStr = "Failed to read configuration" ;
}
//return error + Math.Max(0, Math.Min(readRetVal, 4));
return error ;
}
/// <summary>
/// Set the watermeter to the test mode.
/// If testModeConfig is specified as a hexadeximal number appended to "set test mode ", it is verified
/// whether the testModeConfig is correctly set, if necessary it is changed to the specified value.
/// Read a part of configuration afterwards to verify the mode was set correctly.
/// </summary>
/// <param name="threadId">Thread ID passed to RFID communication functions</param>
/// <param name="ihead">iPERL head object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr SetTestMode ( int threadId , GenesisSmartReader ihead , ref string resultStr )
{
log . Debug ( "SetTestMode threadId=" + threadId + ", ihead=" + ihead . ToString ( ) ) ;
if ( ihead . ConfigStruct = = null )
{
log . Debug ( "ConfigStruct is null - created new in SetTestMode()" ) ;
ihead . ConfigStruct = new TBF . Rig . RegisterReaders . GenesisRegReader . implementations . ConfigStruct ( ) ;
}
if ( ihead . CommFailed | | ihead . ConfigStruct = = null ) return CommErr . CommFailed ;
//I will do communication to meter now
DiagnosticLedState testModeConfig = DiagnosticLedState . State4 ; /// Default value
///
if ( ihead . OptoHeadTest . SetTestMode ( ) )
{
log . Debug ( $"Meter Head:{ihead.Name}, test mode activated now" ) ;
}
if ( ihead . ConfigStruct . MeterState = = ProtocolStatuses . Active /*Test*/ & & ihead . ConfigStruct . TestModeConfig = = testModeConfig )
{
/// Already in the correct test mode
resultStr = "Already " + ihead . ConfigStruct . ToString ( 1 ) ;
log . Debug ( $"Meter Head:{ihead.Name}, status: {resultStr}" ) ;
return CommErr . None ;
}
/// Communication necessary
CommErr error = CommErr . None ;
/// Now the meter should be in the Test mode ... verify
if ( error = = CommErr . None )
{
/// Verify the configuration
error = CommErr . Verify ;
if ( ( ihead . ConfigStruct . MeterState = = ProtocolStatuses . Active ) & &
( ihead . ConfigStruct . TestModeConfig = = testModeConfig ) )
{
error = CommErr . None ;
resultStr = ihead . ConfigStruct . GetActiveModeString ( ) ;
}
}
return error ;
}
/// <summary>
/// Set the watermeter to the active mode.
/// Read a part of configuration afterwards to verify the mode was set correctly.
/// </summary>
/// <param name="ihead">iPERL head object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr SetActiveMode ( int threadId , GenesisSmartReader ihead , ref string resultStr )
{
log . Debug ( "SetActiveMode threadId=" + threadId ) ;
CommErr error = CommErr . CmdActive ;
/// Switch to active mode
if ( ihead . OptoHeadTest . SetActiveMode ( ) )
{
error = CommErr . None ;
}
if ( error = = CommErr . None )
{
if ( ihead . ConfigStruct = = null )
resultStr = "OK (Config not available)" ;
else
resultStr = ihead . ConfigStruct . GetActiveModeString ( ) ;
}
return error ;
}
/// <summary>
/// Reset both Q2 correction factors in the memory to 0.
/// Read them back to verify factors were written correctly.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr Simulate ( GenesisSmartReader ihead , WaterMeter wm , ref string resultStr )
{
string [ ] arguments = multiTestParams [ currentActivityStep ] . Activity . Split ( new char [ ] { ' ' } ) ;
if ( arguments . Length < 2 | | arguments [ 1 ] . ToLower ( ) ! = "iperls" ) return CommErr . None ;
if ( ihead . CommFailed ) return CommErr . CommFailed ;
string [ ] pcbNrs = new string [ ] { "831232435539" , "831232435562" ,
"831232435587" , "831232432141" ,
"831232432497" , "831232763641" } ;
if ( wm . WMPosition > 0 & & wm . WMPosition < = pcbNrs . Length )
{
ihead . SerialNr = wm . SerialNr = pcbNrs [ wm . WMPosition - 1 ] ;
}
resultStr = string . Format ( "PCB Nr. = {0}" , wm . SerialNr ? ? "<null>" ) ;
return CommErr . None ;
}
static CommErr SetIperlCommMilestoneReached ( TestMethod testMethod , ConditionID id , ref string resultStr )
{
if ( id < ConditionID . A | | id > = ConditionID . Count )
{
resultStr = Strings . Error ;
return CommErr . WrongArguments ;
}
testMethod . IperlCommMilestone [ ( int ) id ] = true ;
resultStr = string . Format ( SequenceConditionOp . ConditionNameFmt , id ) ;
return CommErr . None ;
}
#endif
#endregion
/// <summary>
/// Called when communication with one watermeter is completed
/// </summary>
public static void OnCommCompleted ( object sender , CommCompletedEventArgs data )
{
if ( CommCompletedHandler = = null ) return ;
try { CommCompletedHandler ( sender , data ) ; }
catch ( Exception e ) { log . Error ( "CommCompletedHandler(...) failed" , e ) ; }
}
public static event EventHandler < CommCompletedEventArgs > CommCompletedHandler ;
void DoOnCommCompleted ( object sender , CommCompletedEventArgs data )
{
try
{
///
/// Update the text message
///
if ( data . WMNr0 > = 0 ) messages [ data . WMNr0 ] . Text = data . CommMessage ;
///
/// Update head active/inactive switch
///
if ( data . WMNr0 > = 0 & & data . CommErr = = CommErr . HeadDisabledByUser )
{
/// iPerl head was disabled by the user
ckbState [ data . WMNr0 ] = false ;
checkBoxes [ data . WMNr0 ] . Checked = false ;
checkBoxes [ data . WMNr0 ] . Enabled = false ;
if ( data . Ihead ! = null ) data . Ihead . Disabled = true ;
if ( data . Wm ! = null ) data . Wm . Disabled = true ;
}
else if ( data . WMNr0 > = 0 & & data . CommErr = = CommErr . None )
{
/// One RFID communication successful => iPerl cannot be disabled by the user anymore
ckbState [ data . WMNr0 ] = true ;
checkBoxes [ data . WMNr0 ] . Checked = true ;
checkBoxes [ data . WMNr0 ] . Enabled = false ;
}
// else if (data.WMNr0 >= 0 && data.CommErr != CommErr.None)
// {
// //disable if error
// ckbState[data.WMNr0] = false;
// checkBoxes[data.WMNr0].Checked = false;
// checkBoxes[data.WMNr0].Enabled = false;
// if (data.Ihead != null) data.Ihead.Disabled = true;
// if (data.Wm != null) data.Wm.Disabled = true;
// //color
// if (counters.Length > data.WMNr0) counters[data.WMNr0].BackColor = OptoNokColor;
// }
///
/// Update opto-communication indication
///
for ( int i = 0 ; i < genesisHeads . Count ; i + + )
{
if ( genesisHeads [ i ] = = null | | genesisHeads [ i ] . Disabled )
{
counters [ i ] . BackColor = DisabledColor ;
}
else
{
counters [ i ] . BackColor = OptoAndDirOKColor ;
/ * switch ( genesisHeads [ i ] . CheckFlowDirection ( ) )
{
case OptoHeadState . OptoAndDirOK :
counters [ i ] . BackColor = OptoAndDirOKColor ;
break ;
case OptoHeadState . DirNok :
counters [ i ] . BackColor = DirNokColor ;
break ;
default :
case OptoHeadState . OptoNok :
counters [ i ] . BackColor = OptoNokColor ;
break ;
} * /
}
}
2026-09-10 20:09:30 +00:00
// Per-meter results update the UI only. Advance after every worker
// has finished all of its Group 1 assignments for this Group 2.
if ( ! data . WorkerGroupCompleted | | ! groupCompletion . Complete ( data . ActivityStep , data . Group , data . ThreadId ) ) return ;
log . InfoFormat ( "Genesis group completed: Activity={0}, Group2={1}, Workers={2}" , data . ActivityStep , data . Group , workerThreads . Count ) ;
2026-09-09 13:04:49 +00:00
if ( currentGroup < lastGroup )
{
/// Go to the next step / next group
currentGroup + + ;
2026-09-10 20:09:30 +00:00
groupCompletion . Begin ( currentActivityStep , currentGroup ) ;
2026-09-09 13:04:49 +00:00
}
else if ( currentActivityStep + 1 < multiTestParams . Count )
{
currentGroup = 0 ;
currentActivityStep + + ;
activityLabel . Text = multiTestParams [ currentActivityStep ] . Activity ;
currentGroup + + ;
2026-09-10 20:09:30 +00:00
groupCompletion . Begin ( currentActivityStep , currentGroup ) ;
2026-09-09 13:04:49 +00:00
}
else
{
2026-09-10 20:09:30 +00:00
log . Debug ( "Waiting for all Genesis workers; results remain visible for 4 seconds afterwards." ) ;
2026-09-09 13:04:49 +00:00
2026-09-10 20:09:30 +00:00
Thread [ ] finishingThreads = workerThreads . ToArray ( ) ;
2026-09-09 13:04:49 +00:00
Task . Run ( ( ) = >
{
2026-09-10 20:09:30 +00:00
foreach ( var thread in finishingThreads ) thread . Join ( ) ;
2026-09-09 13:04:49 +00:00
if ( ! CanUseUi ( ) ) return ;
BeginInvoke ( new Action ( async ( ) = >
{
if ( ! CanUseUi ( ) ) return ;
// nechaj výsledky/chyby čitateľné 4 sekundy
await Task . Delay ( 4000 ) ;
if ( ! CanUseUi ( ) | | forcedClose ) return ;
NormalClose ( ) ;
} ) ) ;
} ) ;
}
}
catch ( Exception e )
{
log . ErrorFormat ( "DoOnCommCompleted({0}) failed: {1}" , data , e . Message ) ;
log . FatalFormat ( "StackTrace : {0}{1}" , Environment . NewLine , e . StackTrace ) ;
}
}
public static event EventHandler < AllCompletedEventArgs > AllCompletedHandler ;
void DoOnAllCompleted ( object sender , AllCompletedEventArgs data )
{
Text = data . CommMessage ;
}
/// <summary>
/// Update test result representing RFID communication success/failure
/// </summary>
/// <param name="test"></param>
void UpdateRfidCommResult ( IList < Config . Entities . Test > tests )
{
DateTime endTime = DateTime . Now ;
int testTime = StateMachine . Time - startTimeSec ;
if ( ! tests . Contains ( StateMachine . TestInstances [ 0 ] . Test ) )
{
tests . Insert ( 0 , StateMachine . TestInstances [ 0 ] . Test ) ; /// Add RFID test as the 1st item
}
foreach ( var test in tests )
{
Results . Entities . TestRslt tstRslt = ProcessData . BatchRslts . GetTestRslt ( test . Name , test . Part ) ;
if ( tstRslt ! = null )
{
Results . Utils . GetCounterStates ( tstRslt , Program . LocalSettings . Counters ) ;
/// Auxiliary results ... not required
/// Main results
tstRslt . MethodClass = TbfComponents . FindComponent ( test . Method ) . ClassName ;
tstRslt . TestDone = true ;
tstRslt . StartTime = tstRslt . Batch . StartTime ;
tstRslt . EndTime = endTime ;
tstRslt . FlowSetTime = 0 ;
tstRslt . MassOfEvapWater = 0 ;
tstRslt . TestTime + = testTime ; /// [s] total communication time of all tests
for ( int i = 0 ; i < genesisHeads . Count ; i + + )
{
Results . Entities . MeterTestRslt meterRslt =
ProcessData . BatchRslts . GetMeterTestRslt ( test . Name , waterMeterPositions0 [ i ] , CompoundMeterId . Single ) ;
if ( meterRslt ! = null & & genesisHeads [ i ] ! = null )
{
meterRslt . WaterMeter . SerialNr = genesisHeads [ i ] . SerialNr ;
meterRslt . Passed = ( ! genesisHeads [ i ] . CommFailed & & ! genesisHeads [ i ] . Disabled ) ;
meterRslt . TestDone = true ;
}
}
}
}
UiBridge . Bridge . OnTestCompleted ( this , new UiBridge . TestCompletedEventArgs ( string . Empty , null ) ) ;
}
#if IPERL
private MenuItem NewMenuItem ( string text , string tag )
{
MenuItem menuItem = new MenuItem { Text = text , Tag = tag } ;
menuItem . Click + = OnClick_Optical_Heads_Settings_Menu ;
return menuItem ;
}
private async void OnClick_Optical_Heads_Settings_Menu ( object sender , EventArgs e )
{
MenuItem menuItem = ( MenuItem ) sender ;
activityLabel . Text = menuItem . Text ;
List < Task > tasks = new List < Task > ( ) ;
foreach ( var iHead in ProcessData . SmartHeadsUni )
{
if ( ! checkBoxes [ iHead . Position - 1 ] . Checked )
{
if ( iHead . Position - 1 < messages . Length ) messages [ iHead . Position - 1 ] . Text = "" ;
continue ;
}
messages [ iHead . Position - 1 ] . Text = $"COM{iHead.RfidComPortNr}" ;
Application . DoEvents ( ) ; // Refresh UI
tasks . Add ( Task . Run ( async ( ) = >
{
if ( iHead is GenesisSmartReader genesisHead )
{
string result = await ProcessTask ( genesisHead , menuItem . Tag ) ;
this . Invoke ( ( Action ) ( ( ) = >
{
messages [ iHead . Position - 1 ] . Text = result ;
Application . DoEvents ( ) ; // Refresh UI
} ) ) ;
}
} ) ) ;
}
await Task . WhenAll ( tasks ) ;
}
private async Task < string > ProcessTask ( GenesisSmartReader iHead , object tag )
{
string txt = "" ;
bool success = false ;
switch ( tag )
{
////////////////////////////////////////////////////////
case "Initialize" :
txt = iHead . OptoHeadTest . InitialiseSlot ( ) ;
break ;
//now unused
case "Update" :
txt = iHead . OptoHeadTest . UpdateSlot ( ) ;
break ;
case "Connect" :
txt = iHead . OptoHeadTest . ConnectSlot ( ) ;
break ;
//~now unused
case "PCBSlot" :
PcbReadResult pcbReadSlot = iHead . OptoHeadTest . PCB_ReadSlot ( ) ;
txt = pcbReadSlot . Success ? pcbReadSlot . PcbId : "PCB read failed" ;
break ;
//now unused
case "SetPassword" :
txt = iHead . OptoHeadTest . SetPasswordSlot ( ) ;
break ;
case "Login" :
txt = iHead . OptoHeadTest . LoginSlot ( ) ;
break ;
//~ now unused
case "Login (Combined)" :
var result = iHead . OptoHeadTest . GroupedLoginSlot ( ) ;
txt = result ? . LoginResult ? . Success ? ? false ? ( "Login successful; PCB: " + result ? . PcbResult ? . Result ? . PcbId ) : "Login failed" ;
break ;
case "SetTestMode" :
txt = iHead . OptoHeadTest . SetTestModeSlot ( ) ;
break ;
case "SetActiveMode" :
txt = iHead . OptoHeadTest . SetActiveModeSlot ( ) ;
break ;
}
return txt ;
}
#endif /// IPERL
#region Check boxes edit mode support
private void checkBoxImage1_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 0 ] ] = checkBoxImage1 . Checked ; }
private void checkBoxImage2_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 1 ] ] = checkBoxImage2 . Checked ; }
private void checkBoxImage3_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 2 ] ] = checkBoxImage3 . Checked ; }
private void checkBoxImage4_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 3 ] ] = checkBoxImage4 . Checked ; }
private void checkBoxImage5_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 4 ] ] = checkBoxImage5 . Checked ; }
private void checkBoxImage6_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 5 ] ] = checkBoxImage6 . Checked ; }
private void checkBoxImage7_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 6 ] ] = checkBoxImage7 . Checked ; }
private void checkBoxImage8_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 7 ] ] = checkBoxImage8 . Checked ; }
private void checkBoxImage9_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 8 ] ] = checkBoxImage9 . Checked ; }
private void checkBoxImage10_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 9 ] ] = checkBoxImage10 . Checked ; }
private void checkBoxImage11_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 10 ] ] = checkBoxImage11 . Checked ; }
private void checkBoxImage12_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 11 ] ] = checkBoxImage12 . Checked ; }
private void checkBoxImage13_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 12 ] ] = checkBoxImage13 . Checked ; }
private void checkBoxImage14_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 13 ] ] = checkBoxImage14 . Checked ; }
private void checkBoxImage15_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 14 ] ] = checkBoxImage15 . Checked ; }
private void checkBoxImage16_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 15 ] ] = checkBoxImage16 . Checked ; }
private void checkBoxImage17_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 16 ] ] = checkBoxImage17 . Checked ; }
private void checkBoxImage18_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 17 ] ] = checkBoxImage18 . Checked ; }
private void checkBoxImage19_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 18 ] ] = checkBoxImage19 . Checked ; }
private void checkBoxImage20_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 19 ] ] = checkBoxImage20 . Checked ; }
private void checkBoxImage21_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 20 ] ] = checkBoxImage21 . Checked ; }
private void checkBoxImage22_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 21 ] ] = checkBoxImage22 . Checked ; }
private void checkBoxImage23_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 22 ] ] = checkBoxImage23 . Checked ; }
private void checkBoxImage24_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 23 ] ] = checkBoxImage24 . Checked ; }
private void checkBoxImage25_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 24 ] ] = checkBoxImage25 . Checked ; }
private void checkBoxImage26_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 25 ] ] = checkBoxImage26 . Checked ; }
private void checkBoxImage27_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 26 ] ] = checkBoxImage27 . Checked ; }
private void checkBoxImage28_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 27 ] ] = checkBoxImage28 . Checked ; }
private void checkBoxImage29_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 28 ] ] = checkBoxImage29 . Checked ; }
private void checkBoxImage30_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 29 ] ] = checkBoxImage30 . Checked ; }
private void checkBoxImage31_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 30 ] ] = checkBoxImage31 . Checked ; }
private void checkBoxImage32_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 31 ] ] = checkBoxImage32 . Checked ; }
private void checkBoxImage33_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 32 ] ] = checkBoxImage33 . Checked ; }
private void checkBoxImage34_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 33 ] ] = checkBoxImage34 . Checked ; }
private void checkBoxImage35_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 34 ] ] = checkBoxImage35 . Checked ; }
private void checkBoxImage36_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 35 ] ] = checkBoxImage36 . Checked ; }
private void checkBoxImage37_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 36 ] ] = checkBoxImage37 . Checked ; }
private void checkBoxImage38_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 37 ] ] = checkBoxImage38 . Checked ; }
private void checkBoxImage39_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 38 ] ] = checkBoxImage39 . Checked ; }
private void checkBoxImage40_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 39 ] ] = checkBoxImage40 . Checked ; }
private void checkBoxImage41_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 40 ] ] = checkBoxImage41 . Checked ; }
private void checkBoxImage42_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 41 ] ] = checkBoxImage42 . Checked ; }
private void checkBoxImage43_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 42 ] ] = checkBoxImage43 . Checked ; }
private void checkBoxImage44_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 43 ] ] = checkBoxImage44 . Checked ; }
private void checkBoxImage45_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 44 ] ] = checkBoxImage45 . Checked ; }
private void checkBoxImage46_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 45 ] ] = checkBoxImage46 . Checked ; }
private void checkBoxImage47_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 46 ] ] = checkBoxImage47 . Checked ; }
private void checkBoxImage48_Click ( object sender , EventArgs e ) { ckbState [ ckbIndex [ 47 ] ] = checkBoxImage48 . Checked ; }
/// <summary>
/// Get states of checkboxes as one bitfield (long)
/// </summary>
/// <returns>Long bitfield</returns>
private long GetCheckBoxStates ( )
{
long result = 0 ;
for ( int i = 0 ; i < 48 ; i + + )
{
int wmNr0 = ckbIndex [ i ] ;
if ( wmNr0 > = 0 & & ckbState [ wmNr0 ] )
{
result + = ( 1L < < wmNr0 ) ;
}
}
return result ;
}
/// <summary>
/// Set checkboxes to states stored in a bitfield (long)
/// </summary>
private void SetCheckBoxStates ( long state )
{
CheckBoxImage [ ] chkBoxes = new CheckBoxImage [ 48 ]
{
checkBoxImage1 , checkBoxImage2 , checkBoxImage3 , checkBoxImage4 , checkBoxImage5 ,
checkBoxImage6 , checkBoxImage7 , checkBoxImage8 , checkBoxImage9 , checkBoxImage10 ,
checkBoxImage11 , checkBoxImage12 , checkBoxImage13 , checkBoxImage14 , checkBoxImage15 ,
checkBoxImage16 , checkBoxImage17 , checkBoxImage18 , checkBoxImage19 , checkBoxImage20 ,
checkBoxImage21 , checkBoxImage22 , checkBoxImage23 , checkBoxImage24 , checkBoxImage25 ,
checkBoxImage26 , checkBoxImage27 , checkBoxImage28 , checkBoxImage29 , checkBoxImage30 ,
checkBoxImage31 , checkBoxImage32 , checkBoxImage33 , checkBoxImage34 , checkBoxImage35 ,
checkBoxImage36 , checkBoxImage37 , checkBoxImage38 , checkBoxImage39 , checkBoxImage40 ,
checkBoxImage41 , checkBoxImage42 , checkBoxImage43 , checkBoxImage44 , checkBoxImage45 ,
checkBoxImage46 , checkBoxImage47 , checkBoxImage48 ,
} ;
for ( int i = 0 ; i < 48 ; i + + )
{
int wmNr0 = ckbIndex [ i ] ;
if ( wmNr0 > = 0 )
{
chkBoxes [ i ] . Checked = ckbState [ wmNr0 ] = ( ( state & ( 1L < < wmNr0 ) ) ! = 0 ) ;
}
}
}
private void saveButton_Click ( object sender , EventArgs e )
{
Program . LocalSettings . OptoHeadsEnabled = GetCheckBoxStates ( ) ;
Program . LocalSettings . Save ( ) ;
DialogResult = DialogResult . OK ;
Close ( ) ;
}
#endregion
private void GenesisCommunicationForm_FormClosing ( object sender , FormClosingEventArgs e )
{
if ( ! forcedClose & & ! formCompleted & & ! checkBoxesEditMode )
{
e . Cancel = true ;
}
}
}
}