/// /// 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.Linq; using System.Runtime.CompilerServices; using System.Windows.Forms; using Config.Entities; using log4net; using NHibernate.Util; using TBF.Resources; using TBF.Rig.Generic; using TBF.Rig.RegisterReaders.CommonRR.IPerl; using TBF.Rig.RegisterReaders.iPerlReaderUNI; using TBF.Rig.RegisterReaders.PoseidonReader; using TBF.Rig.Sequences; using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations; using TBF.Tools; using CheckBoxImage = TBF.Boxes.CheckBoxImage; //using TestMethodCfg = TBF.Rig.RegisterReaders.iPerlReaderUNI.TestMethodCfg; namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication { 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 } public partial class SmartCommunicationForm : Form, GenericDevices.IHasCompleted { private static readonly ILog log = LogManager.GetLogger(typeof(SmartCommunicationForm)); protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); readonly bool checkBoxesEditMode; // Set to 'true' when the form closes public bool Completed { get { return formCompleted; } } bool formCompleted; bool forcedClose; /// Set in the forced close handler /// Number of text boxes for serial numbers 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 iperlHeads; static IList waterMeterPositions0; /// keeps original 0-based indices in RegisterReaders list static int commonWMType; //share form to correction solver public IList Heads { get => iperlHeads; } public ILog Log { get => SmartCommunicationForm.log; } public ILog RfidDataLogger { get => SmartCommunicationForm.rfidDataLogger; } public Label ActivityLabel { get => this.activityLabel; } public Label[] Labels { get => this.labels; } public PictureBox[] Counters { get => this.counters; } public TextBox[] Messages { get => this.messages; } public CheckBoxImage[] CheckBoxes { get => this.checkBoxes; } public int[] CkbIndex { get => SmartCommunicationForm.ckbIndex; } public bool[] CkbState { get => SmartCommunicationForm.ckbState; } /// /// RFID multiplexer PCB / RFID serial port and worker thread related variables /// private static List _corrections; private static ICorrections Correction { get { if (string.IsNullOrEmpty(SelectedTypeReader) && _corrections.Count > 0) { return _corrections.First(); } foreach (ICorrections correction in _corrections) { if (SelectedTypeReader == correction.TypeIdentificatorName()) { return correction; } } if (_corrections.Count > 0) { return _corrections.First(); } return null; } } private List TypeReaders { get { return IdentifyReaderTypes(); } } public static string SelectedTypeReader { get; set; } private List GetNewCorrectionList(ISmartTestMethod componentBase , TestMethodCfg cfg, IList tests, IList multiTestParams) { List correctionsList = new List(); foreach (var smartHead in ProcessData.SmartHeadsUni) { try{ if (smartHead is IperlHead iperlHead) { if (correctionsList.Any(x => x is IPerlCorrections)) continue; correctionsList.Add(new IPerlCorrections( this,componentBase, cfg, tests, multiTestParams)); continue; } if (smartHead is SmartReader smartReader) { if (correctionsList.Any(x => x is SmartReader)) continue; correctionsList.Add(new PoseidonCorrections(this)); continue; } throw new Exception("Unknown smart head type"); } catch (Exception e) { log.Error("IdentifyReaderTypes()", e); } } return correctionsList; } private static List GetNewCorrectionList(SmartCommunicationForm form) { List correctionsList = new List(); 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; } public static List IdentifyReaderTypes() { List typeReaders = new List(); foreach (var smartHead in ProcessData.SmartHeadsUni) { try { if (typeReaders.Contains(smartHead.ClassName)) continue; 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); } } return typeReaders; } public static ITestMethodCfg? TestMethodCfg { get { return Correction?.Cfg; } set { // Add null check for the value being set if (value == null) { // Log or handle null case return; } if (_corrections == null || _corrections.Count == 0) { _corrections = GetNewCorrectionList(null); } foreach (var correction in _corrections) { correction.Cfg = value; } } } static int currentActivityStep; static int currentGroup; /// form -> worker thread (0 = none) static int lastGroup; static int completedCommCount; /// Number of completed communication steps /// Parameterless constructor (without watermeters, threads) public SmartCommunicationForm() { InitializeComponent(); } /// /// Constructor for checkBox states (active/inactive iPerl head) editing. /// /// Initial check box states public SmartCommunicationForm(bool isCheckBoxesEditMode) : this() { //TODO get corrections based on defined meter _corrections = GetNewCorrectionList(this); // default iPerl Head communication params InitializeMeterTypeItems(); if (isCheckBoxesEditMode) { checkBoxesEditMode = true; saveButton.Visible = true; activityLabel.Text = Strings.Optical_heads; ShuffleTextBoxes(ProcessData.WMsCount, ProcessData.LineSize); this.ContextMenu = Correction.GetContextMenu(); } InitializeWaterMeterData(); if (iperlHeads.Count <= 0) UpdateHeads(); } /// /// Constructor for one iPerlCommunication 'test' /// /// Number of text boxes for serial numbers public SmartCommunicationForm(Generic.IComponent componentBase, Test test, ITestParams testParams) : this(componentBase, new List { test }, new List { testParams }) { } /// /// Constructor for multiple iPerlCommunication 'tests' /// /// Number of text boxes for serial numbers public SmartCommunicationForm(Generic.IComponent componentBase, IList tests, IList multiTestParams) : this() { checkBoxesEditMode = false; //TODO get corrections based on defined meter _corrections = GetNewCorrectionList(componentBase as ISmartTestMethod, componentBase.Cfg as TestMethodCfg, tests, multiTestParams); InitializeMeterTypeItems(); UpdateHeads(); //_corrections = new PoseidonCorrections(this, log, rfidDataLogger, componentBase as ISmartTestMethod,componentBase.Cfg as TestMethodCfg,tests,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() == iPerlCommunicationConstants.GetDefaultQ2CorrectionsStr.ToLower()) { /// Reset IsQ2PreCorrectionCalculated that is used for synchronization/to prevent double REST call ProcessData.IsQ2PreCorrectionCalculated = false; commonWMType = 0; break; } } } /// Attach to 'CommCompleted' handler SmartCommunicationForm.CommCompletedHandler += delegate(object sender, CommCompletedEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(DoOnCommCompleted), sender, args); } else DoOnCommCompleted(sender, args); }; /// Attach to 'AllCompleted' handler SmartCommunicationForm.AllCompletedHandler += delegate(object sender, AllCompletedEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(DoOnAllCompleted), sender, args); } else DoOnAllCompleted(sender, args); }; formCompleted = false; StartForceCloseHandler(); InitializeWaterMeterData(); } private void UpdateHeads() { iperlHeads?.Clear(); if (iperlHeads == null) iperlHeads = new List(); waterMeterPositions0?.Clear(); if (waterMeterPositions0 == null) waterMeterPositions0 = new List(); //iperlHeads = ProcessData.SmartHeadsUni; string comparedTypeReader = SelectedTypeReader; if (string.IsNullOrEmpty(SelectedTypeReader)) { comparedTypeReader = ProcessData.SmartHeadsUni?.First()?.GetType().Name; } ICorrections corre = null; foreach (ICorrections correction in _corrections) { if (correction.TypeIdentificatorName() == SelectedTypeReader) { corre = correction; break; } } if (corre != null) { int wmPos = 0; foreach (var smartHead in ProcessData.SmartHeadsUni) { if (corre.IsFamilyOfSmartReader(smartHead)) { iperlHeads.Add(smartHead); waterMeterPositions0.Add(wmPos); wmPos++; if (wmPos >= ProcessData.WMsCount) break; } } } } 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 InitializeWaterMeterData() { InitializeSmartReaderLists(); if (iperlHeads.Count <= 0) UpdateHeads(); WaterMetersCount = iperlHeads.Count; ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize); Correction.PrepareForTestsActivities(WaterMetersCount); } /// /// this part works fine if we are on test loop /// - because ProcessData.RegisterReaders is initialized in test loop /// private static void InitializeSmartReaderLists() { iperlHeads = new List(); waterMeterPositions0 = new List(); /// for (int wmPos = 0; wmPos < ProcessData.RegisterReaders.Length; wmPos++) { ISmartReader iperlHead = ProcessData.RegisterReaders[wmPos] as ISmartReader; if (iperlHead != null) // what if iperlHead should be null { iperlHeads.Add(iperlHead); waterMeterPositions0.Add(wmPos); } } } /// /// Called when communication with all watermeters is completed /// static void OnAllCompleted(object sender, AllCompletedEventArgs data) { if ( AllCompletedHandler == null) return; try { AllCompletedHandler(sender, data); } catch (Exception e) { log.Error("AllCompletedHandler(...) failed", e); } } private void DoOnCommCompleted(object sender, CommCompletedEventArgs data) { Correction.DoOnCommCompleted(sender, data, waterMeterPositions0); } /// /// Make sure the layout of labels/text boxes on the screen /// corresponds to the layout of watermeters of the test bench. /// /// Number of watermeters /// Number of watermeters in one line 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 = nrLines==0? 0 : (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, Correction.GetHeadsCount()); 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 = iPerlCommunicationConstants.OptoAndDirOKColor; samplePictureBox2.BackColor = iPerlCommunicationConstants.OptoNokColor; samplePictureBox3.BackColor = iPerlCommunicationConstants.DirNokColor; } private void SmartCommunicationForm_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; } if (_corrections.Count > 0)//enable combo for choose SmartMeter { meterTypeComboBox.Visible = true; } Correction.Load(labels,counters,messages,checkBoxes,ckbIndex,ckbState, iperlHeads,textBoxesCount,checkBoxesEditMode ); /// /// 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 < Correction.GetHeadsCount(); i++) { counters[i].BackColor = iPerlCommunicationConstants.OptoNokColor; } /// Start communication process by incrementing 'currentGroup'. currentGroup++; int wtId = 0; foreach (var wt in Correction.GetAllThreads()) { wt.Start(new Boxes.IntBox(wtId++)); /// Start worker threads !!! } } } #region Forced close handling public void StartForceCloseHandler() { UiBridge.Bridge.CloseModelessFormHandler += delegate(object sender, EventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(OnForceClose), sender, args); } else OnForceClose(sender, args); }; } void OnForceClose(object sender, EventArgs args) { CommCompletedHandler = null; AllCompletedHandler = null; Correction?.StopWorkerThreads(true); forcedClose = true; DialogResult = DialogResult.Cancel; Close(); } #endregion /// /// Worker thread /// /// Thread ID (integer) wrapped into IntBox void Worker(object threadData) { Correction?.Worker(threadData); } void StartDataStreamProcessingForActiveMeters(int iMultiTestParamsItem) { Correction?.StartDataStreamProcessingForActiveMeters(iMultiTestParamsItem); } /// /// Called when communication with one watermeter is completed /// 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 CommCompletedHandler; public static event EventHandler AllCompletedHandler; void DoOnAllCompleted(object sender, AllCompletedEventArgs data) { Text = data.CommMessage; } #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; } /// /// Get states of checkboxes as one bitfield (long) /// /// Long bitfield public 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; } /// /// Set checkboxes to states stored in a bitfield (long) /// 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 SmartCommunicationForm_FormClosing(object sender, FormClosingEventArgs e) { if (!forcedClose && !formCompleted && !checkBoxesEditMode) { e.Cancel = true; } } public void NormalClose() { CommCompletedHandler = null; AllCompletedHandler = null; Correction?.NormalClose(waterMeterPositions0); 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(); } private void meterTypeComboBox_SelectedIndexChanged(object sender, EventArgs e) { ComboBox senderCombo = sender as ComboBox; if (senderCombo == null) return; SelectedTypeReader = senderCombo.SelectedItem?.ToString(); UpdateHeads(); } } }