diff --git a/Common/Enums.cs b/Common/Enums.cs index 5c9916494..aa56ebe3d 100644 --- a/Common/Enums.cs +++ b/Common/Enums.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Runtime.InteropServices; namespace Common { @@ -289,17 +290,18 @@ namespace Common CompoundAux, Compound, HeatMeterVolume, - HeatMeterEnergy, + HeatMeterMass,//...MF + HeatMeterEnergy, SingleOrCompound, /// Only used when querying results } public enum PulsesTypeByQuantity : short { - [Description("dm3")] Volume_dm3, - [Description("kg")] Mass_kg, + [Description("dm3")] Volume_dm3, + [Description("kg")] Mass_kg, Count - } + } public enum Medium { @@ -837,6 +839,15 @@ namespace Common E63 = (1L << 62), } + //...MF + public enum FlowType : int + { + none, + volume, + mass, + Count, + } + #region iPERL enums public enum Side diff --git a/Common/Units.cs b/Common/Units.cs index 8f5e5571a..2513a4d64 100644 --- a/Common/Units.cs +++ b/Common/Units.cs @@ -33,6 +33,20 @@ namespace Common [Description("m3/m")] m3pm, /// 1 m3/m = 60 m3/h [Description("cf/s")] cfs, /// 1 cubic foot per second = 101.9406477312 m3/h + + [Description("g/s")] gps, /// 1 g/s = 0.0036 t/h + [Description("g/min")] gpm, /// 1 g/min = 0.00006 t/h + [Description("g/h")] gph, /// 1 g/h = 0.000001 t/h + [Description("kg/s")] kgps, /// 1 kg/s = 3.6 t/h + [Description("kg/min")] kgpm, /// 1 kg/min = 0.06 t/h + [Description("kg/h")] kgph, /// 1 kg/h = 0.001 t/h + [Description("t/s")] tps, /// 1 t/s = 3600 t/h + [Description("t/min")] tpm, /// 1 t/min = 60 t/h + [Description("t/h")] tph, /// 1 t/h = 1 t/h + [Description("lb/s")] lbps, /// 1 lb/s ≈ 1.633 t/h + [Description("lb/min")] lbpm, /// 1 lb/min ≈ 0.027216 t/h + [Description("lb/h")] lbph, /// 1 lb/h ≈ 0.0004536 t/h + [Description("g")] g, /// 0.001 kg [Description("oz")] oz, /// 0.0283495231 kg [Description("lb")] lb, /// 0.45359237 kg @@ -221,11 +235,13 @@ namespace Common [Description("Corrente")] Current, [Description("Voltaggio")] Voltage, #else - [Description("RegisterReader")] RegisterReader, - [Description("MultiFunctionalVariables")] MultiFunctionalVariables, + [Description("RegisterReader")] RegisterReader, + [Description("MultiFunctionalVariables")] MultiFunctionalVariables, + [Description("VolumeFlow")] VolumeFlow, [Description("Volume")] Volume, [Description("Flow")] Flow, - [Description("Mass")] Mass, + [Description("MassFlow")] MassFlow, + [Description("Mass")] Mass, [Description("Time")] Time, [Description("Temperature")] Temperature, [Description("Pressure")] Pressure, @@ -236,8 +252,9 @@ namespace Common [Description("Energy")] Energy, [Description("Pulses")] Pulses, [Description("Pulses/liter")] PulsePerLtr, + [Description("Pulses/kg")] PulsePerKilogram, //...MF + [Description("Pulses/Unit")] PulsePerUnit,//...MF [Description("Pulses/kWh")] PulsePerKWh, - [Description("Pulses/Unit")] PulsePerUnit, [Description("Conductivity")] Conductivity, /// Quantities without units and conversions @@ -281,29 +298,72 @@ namespace Common return Quantity.Pulses; case Unit.ml: + return Quantity.Volume; case Unit.l: + return Quantity.Volume; case Unit.dm3: + return Quantity.Volume; case Unit.USgal: + return Quantity.Volume; case Unit.UKgal: + return Quantity.Volume; case Unit.cf: + return Quantity.Volume; case Unit.m3: return Quantity.Volume; case Unit.lph: + return Quantity.Flow; case Unit.cfph: + return Quantity.Flow; case Unit.lpm: + return Quantity.Flow; case Unit.USgalpm: + return Quantity.Flow; case Unit.m3ph: + return Quantity.Flow; case Unit.lps: + return Quantity.Flow; case Unit.USgalps: + return Quantity.Flow; case Unit.m3pm: + return Quantity.Flow; case Unit.cfs: return Quantity.Flow; + case Unit.gps: + return Quantity.MassFlow; + case Unit.gpm: + return Quantity.MassFlow; + case Unit.gph: + return Quantity.MassFlow; + case Unit.kgps: + return Quantity.MassFlow; + case Unit.kgpm: + return Quantity.MassFlow; + case Unit.kgph: + return Quantity.MassFlow; + case Unit.tps: + return Quantity.MassFlow; + case Unit.tpm: + return Quantity.MassFlow; + case Unit.tph: + return Quantity.MassFlow; + case Unit.lbps: + return Quantity.MassFlow; + case Unit.lbpm: + return Quantity.MassFlow; + case Unit.lbph: + return Quantity.MassFlow; + case Unit.g: + return Quantity.Mass; case Unit.oz: + return Quantity.Mass; case Unit.lb: + return Quantity.Mass; case Unit.kg: + return Quantity.Mass; case Unit.t: return Quantity.Mass; @@ -387,8 +447,10 @@ namespace Common } } - public static bool IsVolume(Unit unit) { return IsQuantity(unit, Quantity.Volume); } + public static bool IsVolumeFlow(Unit unit) { return IsQuantity(unit, Quantity.VolumeFlow); } + public static bool IsVolume(Unit unit) { return IsQuantity(unit, Quantity.Volume); } public static bool IsFlow(Unit unit) { return IsQuantity(unit, Quantity.Flow); } + public static bool IsMassFlow(Unit unit) { return IsQuantity(unit, Quantity.MassFlow); } public static bool IsMass(Unit unit) { return IsQuantity(unit, Quantity.Mass); } public static bool IsTime(Unit unit) { return IsQuantity(unit, Quantity.Time); } public static bool IsTemperature(Unit unit) { return IsQuantity(unit, Quantity.Temperature); } diff --git a/Common/Utils.cs b/Common/Utils.cs index b9befa258..2b1b2c6ac 100644 --- a/Common/Utils.cs +++ b/Common/Utils.cs @@ -302,7 +302,7 @@ namespace Common string passwordOfDay = Convert.ToString(number, 8); return (userName.Equals("milan") && password.Equals("kraken")) || - (userName.Equals("BuMi") && password.Equals("70630")) || + (userName.Equals("bumi") && password.Equals("70630")) || (userName.Equals("igor") && password.Equals("mojronko8")) || (userName.Equals("lubo1212") && password.Equals("Tatry52")) || (userName.Equals("Michal") && password.Equals("Plok789456123")) || diff --git a/SharedComponents/obj/Debug/net472/SharedComponents.GeneratedMSBuildEditorConfig.editorconfig b/SharedComponents/obj/Debug/net472/SharedComponents.GeneratedMSBuildEditorConfig.editorconfig index 64e85c9ac..a02128ff9 100644 --- a/SharedComponents/obj/Debug/net472/SharedComponents.GeneratedMSBuildEditorConfig.editorconfig +++ b/SharedComponents/obj/Debug/net472/SharedComponents.GeneratedMSBuildEditorConfig.editorconfig @@ -1,8 +1,5 @@ is_global = true build_property.RootNamespace = SharedComponents -build_property.ProjectDir = C:\Sensus projects\LocalBranch_start_at_19.2.2026\tbf-exchange260123\tbf\SharedComponents\ +build_property.ProjectDir = C:\Users\micha\git\tbf\SharedComponents\ build_property.EnableComHosting = build_property.EnableGeneratedComInterfaceComImportInterop = -build_property.CsWinRTUseWindowsUIXamlProjections = false -build_property.EffectiveAnalysisLevelStyle = -build_property.EnableCodeStyleSeverity = diff --git a/TBF/Rig/Ambient/Comet/AmbientCfg.cs b/TBF/Rig/Ambient/Comet/AmbientCfg.cs index 80a74662c..119f632c6 100644 --- a/TBF/Rig/Ambient/Comet/AmbientCfg.cs +++ b/TBF/Rig/Ambient/Comet/AmbientCfg.cs @@ -73,8 +73,11 @@ namespace TBF.Rig.Ambient.Comet [XmlIgnore] public IList GNodes { get; set; } - /// Private parameterless constructor invoked by all other (public) constructors - AmbientCfg() + [XmlIgnore] + public bool IsOffline { get; set; } + + /// Private parameterless constructor invoked by all other (public) constructors + AmbientCfg() { GNodes = new List(); Format = string.Empty; @@ -128,15 +131,15 @@ namespace TBF.Rig.Ambient.Comet "Stop bits", /// 4 "Handshake", /// 5 "Set DTR to one", /// 6 - "Unit of temperature", /// 7 + "Units of temperature", /// 7 "Temperature limit Lo", /// 8 "Temperature limit Hi", /// 9 "Default temperature", /// 10 - "Unit of pressure", /// 11 + "Units of pressure", /// 11 "Pressure limit Lo", /// 12 "Pressure limit Hi", /// 13 "Default pressure", /// 14 - "Unit of rel. humidity", /// 15 + "Units of rel. humidity", /// 15 "Rel. humidity limit Lo", /// 16 "Rel. humidity limit Hi", /// 17 "Default retl. humidity", /// 18 diff --git a/TBF/Rig/DataEntry/DEItem.cs b/TBF/Rig/DataEntry/DEItem.cs index a07e26c37..f7cca5df6 100644 --- a/TBF/Rig/DataEntry/DEItem.cs +++ b/TBF/Rig/DataEntry/DEItem.cs @@ -16,6 +16,7 @@ namespace TBF.Rig.DataEntry [Description("Load")] Load, /// Load from water meters when the form is open, save on OK [Description("Load (readonly)")] LoadReadOnly, /// Load from water meters when the form is open, prevent changes, do not save [Description("Set")] Set, /// Set to 'yes' when the form is open + [Description("Set by RegReader")] RegReader, /// Set to 'yes' when the form is open Count, } diff --git a/TBF/Rig/DataEntry/Uni/CycleBgEnForm.cs b/TBF/Rig/DataEntry/Uni/CycleBgEnForm.cs index 3fb74061a..e84674d4e 100644 --- a/TBF/Rig/DataEntry/Uni/CycleBgEnForm.cs +++ b/TBF/Rig/DataEntry/Uni/CycleBgEnForm.cs @@ -5,10 +5,13 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; +using System.Threading.Tasks; using System.Windows.Forms; using log4net; +using NHibernate.Util; using Results.Entities; using TBF.Resources; +using TBF.Rig.GenericDevices; namespace TBF.Rig.DataEntry.Uni { @@ -49,6 +52,18 @@ namespace TBF.Rig.DataEntry.Uni readonly Label[] labels; /// Labels for water meter numbers readonly ComboBox[,] comboBoxes; /// Combo boxes for values in columns readonly CheckBox[] checkBoxes; /// Check boxes for water meter enable/disable + /// + bool readSerialNoByRegisterReader = true; + /// + /// automaticly read serial number from register reader + /// + bool bAutoRead; + /// + ///autoclose disabled by default, if > 0 is enabled + /// - in seconds + /// + int iAutocloseGap; + readonly MultiPurposeBtnFunction multiPurposeButtonFn; bool multiPurposeButtonFlag; @@ -60,18 +75,16 @@ namespace TBF.Rig.DataEntry.Uni /// Set to 'true' when the form closes public bool Completed { get { return completed; } } bool completed; + private readonly IRegReader[] regReaders; - /// + /// /// Parameterless constructor for common functionality /// public CycleBgEnForm() { InitializeComponent(); - - this.Icon = Properties.Resources.TBF_icon; - - ControlBox = false; + ControlBox = false; completed = false; StartForceCloseHandler(); } @@ -89,7 +102,7 @@ namespace TBF.Rig.DataEntry.Uni /// Water meter items displayed in columns (in the matrix in the main part of the form) /// true = This form is displayed at the end of cycle public CycleBgEnForm(IList waterMeters, int _lineSize, string title, FontSz sz, bool isLrOrder, bool isCameraPicture, - string formCloseKeys, IList commonItems, IList colItems, bool isEnd = false) + string formCloseKeys, IList commonItems, IList colItems, bool AutoRead, int AutoCloseGap, bool isEnd = false) : this() { /// Arguments @@ -102,6 +115,9 @@ namespace TBF.Rig.DataEntry.Uni this.commonItems = commonItems; this.colItems = colItems; this.isEnd = isEnd; + + this.bAutoRead = AutoRead; + this.iAutocloseGap = AutoCloseGap; //autoclose disabled by default, if > 0 is enabled /// Preserve column items for use in SummaryResults if (!isEnd) @@ -423,6 +439,16 @@ namespace TBF.Rig.DataEntry.Uni } } + public CycleBgEnForm(IList waterMeters, IRegReader[] regReaders, int title, string myCfgBgTitle, FontSz myCfgBgSize, bool myCfgBgIsLrOrder, bool myCfgBgIsCameraPicture, string myCfgBgFormCloseKeys, IList getItems, IList getColumns, bool b, IRegReader[] iRegReaders, bool AutoRead, int AutoCloseGap) + : this(waterMeters, title, myCfgBgTitle, myCfgBgSize, myCfgBgIsLrOrder, myCfgBgIsCameraPicture, myCfgBgFormCloseKeys, getItems, getColumns,AutoRead,AutoCloseGap, b) + { + this.regReaders = regReaders; + if (bAutoRead) + { + ReadAndProcessSerialNumbersByRegReader(); + } + } + /// /// Add combo box items from a history stored in a string array (obtained usually from LocalSettings) /// @@ -509,6 +535,9 @@ namespace TBF.Rig.DataEntry.Uni case Ac.Set: commonComboBoxes[ix].Text = Strings.yes; break; + case Ac.RegReader: + commonComboBoxes[ix].Text = "--"; + break; } } @@ -690,47 +719,66 @@ namespace TBF.Rig.DataEntry.Uni } char[] digits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; - - /// - /// Find a column with serial numbers - /// - for (int k = 0; k < colItems.Count; k++) + + // if (readSerialNoByRegisterReader) + // { + // Task.Run(() => ReadAndProcessSerialNumbersByRegReader()); + // } + // else { - if ((colItems[k].Content == Ct.SerialNr || colItems[k].Content == Ct.SerialNrAux) && colItems[k].Action != Ac.LoadReadOnly) + /// + /// Find a column with serial numbers + /// + for (int k = 0; k < colItems.Count; k++) { - /// - /// Column with serial numbers found => perform an auto s/n assignment - /// - string firstSN = comboBoxes[k, firstIx].Text; - - int firstSnNr; - int startIx = firstSN.IndexOfAny(digits); - if (startIx >= 0) + if ((colItems[k].Content == Ct.SerialNr || colItems[k].Content == Ct.SerialNrAux) && + colItems[k].Action != Ac.LoadReadOnly) { - int lastDigitPosPlus1 = startIx + 1; - var listOfDigits = new List(digits); - while (lastDigitPosPlus1 < firstSN.Length && listOfDigits.Contains(firstSN[lastDigitPosPlus1])) - { - lastDigitPosPlus1++; - } - int digitsCount = lastDigitPosPlus1 - startIx; + /// + /// Column with serial numbers found => perform an auto s/n assignment + /// + string firstSN = comboBoxes[k, firstIx].Text; - if (int.TryParse(firstSN.Substring(startIx, digitsCount), out firstSnNr) && firstSnNr >= 0) + + + + + int firstSnNr; + int startIx = firstSN.IndexOfAny(digits); + if (startIx >= 0) { - for (int ix = firstIx + 1; ix < wmsCount; ix++) + int lastDigitPosPlus1 = startIx + 1; + var listOfDigits = new List(digits); + while (lastDigitPosPlus1 < firstSN.Length && + listOfDigits.Contains(firstSN[lastDigitPosPlus1])) { - if (checkBoxes[ix].Checked) + lastDigitPosPlus1++; + } + + int digitsCount = lastDigitPosPlus1 - startIx; + + if (int.TryParse(firstSN.Substring(startIx, digitsCount), out firstSnNr) && + firstSnNr >= 0) + { + for (int ix = firstIx + 1; ix < wmsCount; ix++) { - firstSnNr++; - string newSN = firstSnNr.ToString(); - int len = newSN.Length; - if (len <= digitsCount) + if (checkBoxes[ix].Checked) { - comboBoxes[k, ix].Text = firstSN.Substring(0, startIx + digitsCount - len) + newSN + firstSN.Substring(startIx + digitsCount); - } - else - { - comboBoxes[k, ix].Text = firstSN.Substring(0, startIx) + newSN + firstSN.Substring(startIx + digitsCount); ; + firstSnNr++; + string newSN = firstSnNr.ToString(); + int len = newSN.Length; + if (len <= digitsCount) + { + comboBoxes[k, ix].Text = + firstSN.Substring(0, startIx + digitsCount - len) + newSN + + firstSN.Substring(startIx + digitsCount); + } + else + { + comboBoxes[k, ix].Text = firstSN.Substring(0, startIx) + newSN + + firstSN.Substring(startIx + digitsCount); + ; + } } } } @@ -762,6 +810,136 @@ namespace TBF.Rig.DataEntry.Uni } } + private void ReadAndProcessSerialNumbersByRegReader() + { + log.Debug("Reading serial numbers from register readers..."); + this.SerialNumberRead += (s, eArgs) => + { + log.Debug("Serial updated: " + eArgs.SerialNumber); + UpdateSomethingBySerial(eArgs.Reader, eArgs.SerialNumber); + }; + + BeforeUpdate(); + this.DoneUpdateBySerial += (s, eArgs) => + { + log.Debug("Serial updated DONE!"); + DoneUpdate(); + }; + + ReadSerialNumbersAsync(regReaders); + } + + private void UpdateSomethingBySerial(IRegReader eReader, string eSerialNumber) + { + log.Debug($"RegReader name: {eReader.Name}, Serial No updated: " + eSerialNumber); + PopulateComboBoxWithSerialNumbers(eReader, eSerialNumber); + } + + LinkedHashMap storeUIForUpdate = new LinkedHashMap(); + private Cursor _previousCursor; + private bool GetStoredOrDefault(string key) + { + bool value; + if (storeUIForUpdate.TryGetValue(key, out value)) + return value; + + return true; // default if nothing stored + } + + private void BeforeUpdate() + { + log.Debug("BeforeUpdate"); + + storeUIForUpdate["okButton"] = this.okButton.Enabled; + storeUIForUpdate["clearButton"] = this.clearButton.Enabled; + storeUIForUpdate["multiPurposeButton"] = this.multiPurposeButton.Enabled; + + this.okButton.Enabled = false; + this.clearButton.Enabled = false; + this.multiPurposeButton.Enabled = false; + + _previousCursor = Cursor.Current; + Cursor.Current = Cursors.WaitCursor; + + + //Enable all checkboxes + + for (int firstIx = 0; firstIx < wmsCount; firstIx++) + { + checkBoxes[firstIx].Checked = true; + } + + + + } + private void DoneUpdate() + { + log.Debug("DoneUpdate"); + + //enbale only found checkboxes + int comboRows = comboBoxes.GetLength(0); + int comboCols = comboBoxes.GetLength(1); + + for (int k = 0; k < colItems.Count && k < comboRows; k++) + { + for (int ix = 0; ix < wmsCount && ix < comboCols; ix++) + { + bool letEnable = false; + var combo = comboBoxes[k, ix]; + if (combo != null) + { + letEnable = !string.IsNullOrEmpty(combo.Text); + } + + if (letEnable && checkBoxes.Length > ix) + { + + checkBoxes[ix].Enabled = true; + } + } + } + + + + + this.okButton.Enabled = GetStoredOrDefault("okButton"); + this.clearButton.Enabled = GetStoredOrDefault("clearButton"); + this.multiPurposeButton.Enabled = GetStoredOrDefault("multiPurposeButton"); + Cursor.Current = _previousCursor; + + if (iAutocloseGap > 0) + { + AutoClickOkAfterDelay(iAutocloseGap * 1000); + } + } + + private void PopulateComboBoxWithSerialNumbers( IRegReader eReader, string eSerialNumber) + { + if (regReaders == null || comboBoxes == null) + return; + + int regReadersLength = regReaders.Length; + int comboRows = comboBoxes.GetLength(0); + int comboCols = comboBoxes.GetLength(1); + + for (int k = 0; k < colItems.Count && k < comboRows; k++) + { + for (int ix = 0; ix < wmsCount && ix < comboCols; ix++) + { + int regIndex = ix + wmsCount*k; + + if (regIndex >= 0 && regIndex < regReadersLength) + { + var combo = comboBoxes[k, ix]; + if (combo != null && regReaders[regIndex] == eReader) + { + combo.Text = eSerialNumber; + } + } + } + } + } + private void comboBox_SelectedIndexChanged(object sndr, EventArgs e) { if (!isHandlersEnabled) return; @@ -908,5 +1086,150 @@ namespace TBF.Rig.DataEntry.Uni } #endregion + + public event EventHandler SerialNumberRead; + public event EventHandler DoneUpdateBySerial; + + public sealed class SerialNumberReadEventArgs : EventArgs + { + public IRegReader Reader { get; private set; } + public string SerialNumber { get; private set; } + + public SerialNumberReadEventArgs(IRegReader reader, string serialNumber) + { + Reader = reader; + SerialNumber = serialNumber; + } + } + + public sealed class SerialNumberReadDoneEventArgs : EventArgs + { + public SerialNumberReadDoneEventArgs() + { + } + } + + protected virtual void OnSerialNumberRead(IRegReader reader, string serial) + { + var handler = SerialNumberRead; // copy for thread-safety + if (handler == null) return; + if (IsHandleCreated && InvokeRequired) + { + BeginInvoke(new Action(() => + handler(this, new SerialNumberReadEventArgs(reader, serial)))); + } + else + { + handler(this, new SerialNumberReadEventArgs(reader, serial)); + } + } + + protected virtual void OnReadDone() + { + var handler = DoneUpdateBySerial; // copy for thread-safety + if (handler == null) return; + + if (IsHandleCreated && InvokeRequired) + { + BeginInvoke(new Action(() => + handler(this, new SerialNumberReadDoneEventArgs()))); + } + else + { + handler(this, new SerialNumberReadDoneEventArgs()); + } + } + + public async void ReadSerialNumbersAsync(IEnumerable regReaders) + { + log.Debug($"Reading-> regReaders.length({(regReaders != null ? regReaders.Count() : 0)})"); + if (regReaders == null) + { + log.Debug("Reading-> regReaders is null"); + return; + } + + + foreach (IRegReader reader in regReaders) + { + if (reader == null) continue; + log.Debug($"Reading-> regReader: {reader.GetType().Name}"); + } + + + try + { + var groups = regReaders + .OfType() + .GroupBy(r => r.Group) + .OrderBy(g => g.Key); + + if (groups != null) + log.Debug($"Reading-> groups.length({groups.Count()})"); + + foreach (var group in groups) + { + var subGroups = group + .GroupBy(r => r.MuxBoardNrOrGroup14) + .OrderBy(sg => sg.Key); + + foreach (var subGroup in subGroups) + { + log.Debug(string.Format("Processing Group {0}, SubGroup {1}", group.Key, subGroup.Key)); + + // Start tasks in parallel inside subgroup + var tasks = subGroup.Select(async r => + { + var serial = await r.DataEntry_ReadSerialNumber().ConfigureAwait(false); + return new KeyValuePair((IRegReader)r, serial); + }).ToList(); + + var results = await Task.WhenAll(tasks).ConfigureAwait(false); + + foreach (var kv in results) + { + var reader = kv.Key; + var serial = kv.Value; + + if (string.IsNullOrWhiteSpace(serial)) + continue; + + // Notify for each successful read + OnSerialNumberRead(reader, serial); + } + } + } + } + catch (Exception ex) + { + log.Error("Error reading serial numbers from register readers", ex); + } + finally + { + OnReadDone(); + } + + + log.Debug("Reading serial numbers DONE!"); + } + + public void AutoClickOkAfterDelay(int delayMs = 10000) + { + _ = AutoClickInternal(okButton, delayMs); + } + + private async Task AutoClickInternal(Button clickButton, int delayMs) + { + await Task.Delay(delayMs); + + if (clickButton.IsHandleCreated && clickButton.Enabled && clickButton.Visible) + { + // Invoke on UI thread + if (clickButton.InvokeRequired) + clickButton.BeginInvoke(new Action(() => clickButton.PerformClick())); + else + clickButton.PerformClick(); + } + } } } diff --git a/TBF/Rig/DataEntry/Uni/EntryFormCfg.cs b/TBF/Rig/DataEntry/Uni/EntryFormCfg.cs index 83376d5f9..ea877ef37 100644 --- a/TBF/Rig/DataEntry/Uni/EntryFormCfg.cs +++ b/TBF/Rig/DataEntry/Uni/EntryFormCfg.cs @@ -41,8 +41,10 @@ namespace TBF.Rig.DataEntry.Uni public bool BgIsLrOrder; /// 5 public bool BgIsCameraPicture; /// 6 public string BgFormCloseKeys; /// 7 + public bool BgIsAutoReadingSerialNo;/// 8 - new + public int BgAutoCloseGap; /// 9 - new - public bool EnShowForm; /// 8 + public bool EnShowForm; /// 8 + 2 public string EnTitle; /// 9 public FontSz EnSize; /// 10 // int EnItemsCount; /// 11 @@ -60,7 +62,7 @@ namespace TBF.Rig.DataEntry.Uni public bool TestIsCameraPicture; /// 22 public string TestStartPicName; /// 23 public string TestEndPicName; /// 24 - public string TestFormCloseKeys; /// 25 + public string TestFormCloseKeys; /// 25 + 2 public Ct[] BgItemContent; /// 26 + 4 * ix public string[] BgItemCaption; /// 27 + 4 * ix @@ -343,6 +345,8 @@ namespace TBF.Rig.DataEntry.Uni BgIsLrOrder = false; BgIsCameraPicture = false; BgFormCloseKeys = string.Empty; + BgIsAutoReadingSerialNo = false; + BgAutoCloseGap = 10; EnShowForm = false; EnTitle = "Enter water meter data"; @@ -389,16 +393,18 @@ namespace TBF.Rig.DataEntry.Uni string[] paramNames = new string[] { - "Beginning: Show form", - "Beginning: Form title", - "Beginning: Font ize", - "Beginning: Common items count", + "Beginning: Show form", //0 + "Beginning: Form title", //1 + "Beginning: Font ize", //2 + "Beginning: Common items count",//3 "Beginning: Columns count", "Beginning: Left-to-right order", "Beginning: Show camera picture", "Beginning: Keys to close the form", + "Beginning: Read Automatic Serial No from watermeter", //8 + "Beginning: Continue automatic after Read Serial No", //9 - "End: Show form", + "End: Show form",//8+2 "End: Form title", "End: Font size", "End: Common items count", @@ -508,17 +514,18 @@ namespace TBF.Rig.DataEntry.Uni case 0: case 5: case 6: - case 8: - case 13: - case 14: + case 8: //new auto read SerialNo + case 10: //8+2 + case 15: case 16: - case 20: - case 21: + case 18: case 22: + case 23: + case 24: return new string[] { Strings.yes, Strings.no }; case 2: - case 10: - case 18: + case 12: + case 20: for (FontSz sz = 0; sz < FontSz.Count; sz++) list.Add(sz.ToDescription()); return list; default: @@ -596,26 +603,28 @@ namespace TBF.Rig.DataEntry.Uni case 5: return BgIsLrOrder ? Strings.yes : Strings.no; case 6: return BgIsCameraPicture ? Strings.yes : Strings.no; case 7: return BgFormCloseKeys; + case 8: return BgIsAutoReadingSerialNo ? Strings.yes : Strings.no;; + case 9: return BgAutoCloseGap.ToString(); - case 8: return EnShowForm ? Strings.yes : Strings.no; - case 9: return EnTitle; - case 10: return EnSize.ToDescription(); - case 11: return GetEnItemsCount().ToString(); - case 12: return GetEnColumnsCount().ToString(); - case 13: return EnIsLrOrder ? Strings.yes : Strings.no; - case 14: return EnIsCameraPicture ? Strings.yes : Strings.no; - case 15: return EnFormCloseKeys; + case 10: return EnShowForm ? Strings.yes : Strings.no; + case 11: return EnTitle; + case 12: return EnSize.ToDescription(); + case 13: return GetEnItemsCount().ToString(); + case 14: return GetEnColumnsCount().ToString(); + case 15: return EnIsLrOrder ? Strings.yes : Strings.no; + case 16: return EnIsCameraPicture ? Strings.yes : Strings.no; + case 17: return EnFormCloseKeys; - case 16: return TestStartEndShowForm ? Strings.yes : Strings.no; - case 17: return TestTitle; - case 18: return TestSize.ToDescription(); - case 19: return GetTestColumnsCount().ToString(); - case 20: return TestStartBoxAlwaysEn ? Strings.yes : Strings.no; - case 21: return TestIsLrOrder ? Strings.yes : Strings.no; - case 22: return TestIsCameraPicture ? Strings.yes : Strings.no; - case 23: return TestStartPicName; - case 24: return TestEndPicName; - case 25: return TestFormCloseKeys; + case 18: return TestStartEndShowForm ? Strings.yes : Strings.no; + case 19: return TestTitle; + case 20: return TestSize.ToDescription(); + case 21: return GetTestColumnsCount().ToString(); + case 22: return TestStartBoxAlwaysEn ? Strings.yes : Strings.no; + case 23: return TestIsLrOrder ? Strings.yes : Strings.no; + case 24: return TestIsCameraPicture ? Strings.yes : Strings.no; + case 25: return TestStartPicName; + case 26: return TestEndPicName; + case 27: return TestFormCloseKeys; default: return string.Empty; } @@ -714,10 +723,12 @@ namespace TBF.Rig.DataEntry.Uni case 5: BgIsLrOrder = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; case 6: BgIsCameraPicture = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; case 7: BgFormCloseKeys = str; return CfgUpdateFlags.RestartRqrd; - - case 8: EnShowForm = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 9: EnTitle = str; return CfgUpdateFlags.RestartRqrd; - case 10: + case 8: BgIsAutoReadingSerialNo = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 9: BgAutoCloseGap = int.Parse(str); return CfgUpdateFlags.RestartRqrd; + + case 10: EnShowForm = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 11: EnTitle = str; return CfgUpdateFlags.RestartRqrd; + case 12: for (FontSz sz = 0; sz < FontSz.Count; sz++) { if (str == sz.ToDescription()) @@ -727,15 +738,15 @@ namespace TBF.Rig.DataEntry.Uni } } return CfgUpdateFlags.None; - case 11: SetEnItemsCount(int.Parse(str)); return CfgUpdateFlags.RestartRqrd; - case 12: SetEnColumnsCount(int.Parse(str)); return CfgUpdateFlags.RestartRqrd; - case 13: EnIsLrOrder = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 14: EnIsCameraPicture = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 15: EnFormCloseKeys = str; return CfgUpdateFlags.RestartRqrd; + case 13: SetEnItemsCount(int.Parse(str)); return CfgUpdateFlags.RestartRqrd; + case 14: SetEnColumnsCount(int.Parse(str)); return CfgUpdateFlags.RestartRqrd; + case 15: EnIsLrOrder = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 16: EnIsCameraPicture = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 17: EnFormCloseKeys = str; return CfgUpdateFlags.RestartRqrd; - case 16: TestStartEndShowForm = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 17: TestTitle = str; return CfgUpdateFlags.RestartRqrd; - case 18: + case 18: TestStartEndShowForm = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 19: TestTitle = str; return CfgUpdateFlags.RestartRqrd; + case 20: for (FontSz sz = 0; sz < FontSz.Count; sz++) { if (str == sz.ToDescription()) @@ -745,13 +756,13 @@ namespace TBF.Rig.DataEntry.Uni } } return CfgUpdateFlags.None; - case 19: SetTestColumnsCount(int.Parse(str)); return CfgUpdateFlags.RestartRqrd; - case 20: TestStartBoxAlwaysEn = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 21: TestIsLrOrder = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 22: TestIsCameraPicture = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 23: TestStartPicName = str; return CfgUpdateFlags.RestartRqrd; - case 24: TestEndPicName = str; return CfgUpdateFlags.RestartRqrd; - case 25: TestFormCloseKeys = str; return CfgUpdateFlags.RestartRqrd; + case 21: SetTestColumnsCount(int.Parse(str)); return CfgUpdateFlags.RestartRqrd; + case 22: TestStartBoxAlwaysEn = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 23: TestIsLrOrder = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 24: TestIsCameraPicture = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 25: TestStartPicName = str; return CfgUpdateFlags.RestartRqrd; + case 26: TestEndPicName = str; return CfgUpdateFlags.RestartRqrd; + case 27: TestFormCloseKeys = str; return CfgUpdateFlags.RestartRqrd; default: return CfgUpdateFlags.None; @@ -872,34 +883,36 @@ namespace TBF.Rig.DataEntry.Uni case 2: case 5: case 6: - case 8: - case 10: - case 13: - case 14: + case 8://Auto close - yes/No + case 10://8+2 + case 12: + case 15: case 16: case 18: case 20: - case 21: case 22: + case 23: + case 24: message = string.Empty; if (ParamValues(i).Contains(str)) return true; break; case 3: case 4: - case 11: - case 12: - case 19: + case 9: //Gap AutoClose + case 13: + case 14: + case 21: message = string.Empty; if (int.TryParse(str, out idummy)) return true; break; case 1: case 7: - case 9: - case 15: + case 11: case 17: - case 23: - case 24: + case 19: case 25: + case 26: + case 27: message = string.Empty; return true; default: @@ -942,6 +955,8 @@ namespace TBF.Rig.DataEntry.Uni prms.BgIsLrOrder = BgIsLrOrder; prms.BgIsCameraPicture = BgIsCameraPicture; prms.BgFormCloseKeys = BgFormCloseKeys; + prms.BgIsAutoReadingSerialNo = BgIsAutoReadingSerialNo; + prms.BgAutoCloseGap = BgAutoCloseGap; prms.EnShowForm = EnShowForm; prms.EnTitle = EnTitle; diff --git a/TBF/Rig/DataEntry/Uni/EntryFormNoStartEnd.cs b/TBF/Rig/DataEntry/Uni/EntryFormNoStartEnd.cs index 6d7808b91..5482a1b55 100644 --- a/TBF/Rig/DataEntry/Uni/EntryFormNoStartEnd.cs +++ b/TBF/Rig/DataEntry/Uni/EntryFormNoStartEnd.cs @@ -155,6 +155,7 @@ namespace TBF.Rig.DataEntry.Uni if (currentOp != CurrentOp.None) throw new Exception("Sequence error"); currentOp = CurrentOp.FormAtCycleBeginning; this.waterMeters = Sequences.ProcessData.BatchRslts.Batch.WaterMeters; + regReaders = regReadersOptional; return this; } @@ -234,9 +235,17 @@ namespace TBF.Rig.DataEntry.Uni DEItem.AddColumn(myCfg.BgColumnContent[i], myCfg.BgColumnCaption[i], myCfg.BgColumnAction[i], myCfg.BgColumnWidth[i]); } } - - modelessDlg = new CycleBgEnForm(waterMeters, TBF.Data.LineSize, myCfg.BgTitle, myCfg.BgSize, myCfg.BgIsLrOrder, myCfg.BgIsCameraPicture, - myCfg.BgFormCloseKeys, DEItem.GetItems(), DEItem.GetColumns(), false); + + if (regReaders != null) + { + modelessDlg = new CycleBgEnForm(waterMeters, regReaders, TBF.Data.LineSize, myCfg.BgTitle, myCfg.BgSize, myCfg.BgIsLrOrder, myCfg.BgIsCameraPicture, + myCfg.BgFormCloseKeys, DEItem.GetItems(), DEItem.GetColumns(), false, regReaders, myCfg.BgIsAutoReadingSerialNo, myCfg.BgAutoCloseGap); + } + else + { + modelessDlg = new CycleBgEnForm(waterMeters, TBF.Data.LineSize, myCfg.BgTitle, myCfg.BgSize, myCfg.BgIsLrOrder, myCfg.BgIsCameraPicture, + myCfg.BgFormCloseKeys, DEItem.GetItems(), DEItem.GetColumns(), myCfg.BgIsAutoReadingSerialNo, myCfg.BgAutoCloseGap, false); + } modelessDlg.Show(); } /// @@ -264,7 +273,7 @@ namespace TBF.Rig.DataEntry.Uni } modelessDlg = new CycleBgEnForm(waterMeters, TBF.Data.LineSize, myCfg.EnTitle, myCfg.EnSize, myCfg.EnIsLrOrder, myCfg.EnIsCameraPicture, - myCfg.EnFormCloseKeys, DEItem.GetItems(), DEItem.GetColumns(), true); + myCfg.EnFormCloseKeys, DEItem.GetItems(), DEItem.GetColumns(), myCfg.BgIsAutoReadingSerialNo, myCfg.BgAutoCloseGap, true); modelessDlg.Show(); } /// @@ -286,7 +295,8 @@ namespace TBF.Rig.DataEntry.Uni modelessDlg = new TestStartEndForm(waterMeters, myRef.regReaders, TBF.Data.LineSize, myCfg.TestTitle, myCfg.TestSize, myCfg.TestStartBoxAlwaysEn, myCfg.TestIsLrOrder, myCfg.TestFormCloseKeys, DEItem.GetColumns(), isCompound, volumeUnit, myCfg.TestIsCameraPicture, - startImages, endImages, ocr, ocrMessage, myRef.OcrStream); + startImages,endImages, ocr, ocrMessage, myRef.OcrStream, + myCfg.BgIsAutoReadingSerialNo, myCfg.BgAutoCloseGap); modelessDlg.Show(); } /// @@ -308,7 +318,7 @@ namespace TBF.Rig.DataEntry.Uni modelessDlg = new TestStartEndForm(waterMeters, myRef.regReaders, TBF.Data.LineSize, myCfg.TestTitle, myCfg.TestSize, myCfg.TestStartBoxAlwaysEn, myCfg.TestIsLrOrder, myCfg.TestFormCloseKeys, DEItem.GetColumns(), isCompound, volumeUnit, myCfg.TestIsCameraPicture, startImages, endImages, - ocr, ocrMessage, myRef.OcrStream, wmStartStateStr, refVolume, errLimLo, errLimHi); + ocr, ocrMessage, myRef.OcrStream, myCfg.BgIsAutoReadingSerialNo, myCfg.BgAutoCloseGap, wmStartStateStr, refVolume, errLimLo, errLimHi); modelessDlg.Show(); } /// @@ -330,7 +340,7 @@ namespace TBF.Rig.DataEntry.Uni modelessDlg = new TestStartEndForm(waterMeters, myRef.regReaders, TBF.Data.LineSize, myCfg.TestTitle, myCfg.TestSize, myCfg.TestStartBoxAlwaysEn, myCfg.TestIsLrOrder, myCfg.TestFormCloseKeys, DEItem.GetColumns(), isCompound, volumeUnit, myCfg.TestIsCameraPicture, startImages, endImages, - ocr, ocrMessage, myRef.OcrStream, wmStartStateStr, refVolume, errLimLo, errLimHi); + ocr, ocrMessage, myRef.OcrStream, myCfg.BgIsAutoReadingSerialNo,myCfg.BgAutoCloseGap, wmStartStateStr, refVolume, errLimLo, errLimHi); modelessDlg.Show(); } /// diff --git a/TBF/Rig/DataEntry/Uni/ProcParams.cs b/TBF/Rig/DataEntry/Uni/ProcParams.cs index 3fce4e9ba..044232e37 100644 --- a/TBF/Rig/DataEntry/Uni/ProcParams.cs +++ b/TBF/Rig/DataEntry/Uni/ProcParams.cs @@ -1,11 +1,11 @@ using Common; using Config.Entities; using log4net; -using System; /// /// Copyright (c) 2022-2023 Sensus Slovensko a.s. /// +using System; using System.IO; using System.Xml.Serialization; using TBF.Rig.Generic; @@ -97,16 +97,16 @@ namespace TBF.Rig.DataEntry.Uni return pars; } - public override bool UpdateFromDbEntity(ComponentProcedure dbEntity) - { - if (dbEntity == null) return false; - try - { - ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams; + public override bool UpdateFromDbEntity(ComponentProcedure dbEntity) + { + if (dbEntity == null) return false; + try + { + ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams; - procedureParamsEntity = dbEntity; - componentName = dbEntity.CmpntName; - procedure = dbEntity.Procedure; + procedureParamsEntity = dbEntity; + componentName = dbEntity.CmpntName; + procedure = dbEntity.Procedure; if (tmp != null) { @@ -118,7 +118,7 @@ namespace TBF.Rig.DataEntry.Uni catch (Exception ex) { log.DebugFormat( - "Error during RRProcParams deserialization. CmpntName='{0}', Procedure='{1}', Parameters='{2}', Exception: {3}", + "Error during Procedure parameters deserialization. CmpntName='{0}', Procedure='{1}', Parameters='{2}', Exception: {3}", dbEntity?.CmpntName, dbEntity?.Procedure, dbEntity?.Parameters, @@ -129,10 +129,10 @@ namespace TBF.Rig.DataEntry.Uni } } - /// - /// Parameterless constructor initializes the parameters - /// - public ProcParams() + /// + /// Parameterless constructor initializes the parameters + /// + public ProcParams() { } diff --git a/TBF/Rig/DataEntry/Uni/TestStartEndForm.cs b/TBF/Rig/DataEntry/Uni/TestStartEndForm.cs index e6a963db0..0b656c3e3 100644 --- a/TBF/Rig/DataEntry/Uni/TestStartEndForm.cs +++ b/TBF/Rig/DataEntry/Uni/TestStartEndForm.cs @@ -13,6 +13,8 @@ using TBF.Rig.GenericDevices; using TBF.Resources; using System.Threading; using System.IO; +using System.Threading.Tasks; +using NHibernate.Util; using static System.Net.Mime.MediaTypeNames; namespace TBF.Rig.DataEntry.Uni @@ -60,6 +62,17 @@ namespace TBF.Rig.DataEntry.Uni readonly double refVolume; readonly double warningLimLo; /// limit to display exclamation mark, typically 2x errLimLo readonly double warningLimHi; /// limit to display exclamation mark, typically 2x errLimHi + + private bool _readDataFromRegReaders = true; + /// + /// automaticly read serial number from register reader + /// + bool bAutoRead; + /// + ///autoclose disabled by default, if > 0 is enabled + /// - in seconds + /// + int iAutocloseGap; /// Derived from arguments in the constructor readonly bool isEnd; @@ -121,10 +134,7 @@ namespace TBF.Rig.DataEntry.Uni public TestStartEndForm() { InitializeComponent(); - - this.Icon = Properties.Resources.TBF_icon; - - ControlBox = false; + ControlBox = false; imageProcessingThread = null; completed = false; StartForceCloseHandler(); @@ -157,7 +167,7 @@ namespace TBF.Rig.DataEntry.Uni public TestStartEndForm(IList waterMeters, IRegReader[] regReaders, int _lineSize, string title, FontSz sz, bool isStartBoxAlwaysEn, bool isLrOrder, string formCloseKeys, IList colItems, bool isCompound, Unit initialVolumeUnit, bool isCameraPicture, string[] startImages, string[] endImages, - OcrVidi ocrVidi, string ocrMessage, string streamName, string[] wmStartStateStr = null, + OcrVidi ocrVidi, string ocrMessage, string streamName, bool bAutoRead, int iAutocloseGap, string[] wmStartStateStr = null, double refVolume = 0, double errLimLo = 0, double errLimHi = 0) : this() { @@ -182,6 +192,8 @@ namespace TBF.Rig.DataEntry.Uni this.refVolume = refVolume; this.warningLimLo = 2 * errLimLo; this.warningLimHi = 2 * errLimHi; + this.bAutoRead = bAutoRead; + this.iAutocloseGap = iAutocloseGap; if (waterMeters == null || regReaders == null || (wmStartStateStr != null && wmStartStateStr.Length != (isCompound ? 2 : 1) * waterMeters.Count)) @@ -466,6 +478,8 @@ namespace TBF.Rig.DataEntry.Uni okButton.Text = Strings.OkBtnText; } + + /// /// Initialize combo boxes state defined by related 'Action'. /// Clear check boxes. @@ -496,6 +510,7 @@ namespace TBF.Rig.DataEntry.Uni textBoxes[k, i].Enabled = (isStartBoxAlwaysEn || !isEnd) && waterMeters[i] != null && !waterMeters[i].Disabled && rrIx < regReaders.Length && regReaders[rrIx] != null; } + } else if (colItems[k].Content == Ct.StartStateAux) { @@ -567,10 +582,207 @@ namespace TBF.Rig.DataEntry.Uni } } + + if (bAutoRead) + { + log.Debug($"Reading serial numbers from register readers... IsEnd: {isEnd}"); + this.VolumeStartReadbyRegReader += (s, eArgs) => + { + log.Debug("Volume updated: " + eArgs.Volume); + UpdateVolume(eArgs.Reader, eArgs.Volume); + }; + + BeforeUpdate(); + this.DoneUpdateByRegReader += (s, eArgs) => + { + log.Debug("Volume updated DONE!"); + DoneUpdate(); + }; + + ReadVolumeAsync(regReaders); + } isHandlersEnabled = true; } + LinkedHashMap storeUIForUpdate = new LinkedHashMap(); + private Cursor _previousCursor; + private bool GetStoredOrDefault(string key) + { + bool value; + if (storeUIForUpdate.TryGetValue(key, out value)) + return value; + + return true; // default if nothing stored + } + + private void BeforeUpdate() + { + log.Debug("BeforeUpdate"); + + storeUIForUpdate["okButton"] = this.okButton.Enabled; + storeUIForUpdate["largeTextBox"] = this.largeTextBox.Enabled; + storeUIForUpdate["largeExclamationLabel"] = this.largeExclamationLabel.Enabled; + storeUIForUpdate["unitComboBox"] = this.unitComboBox.Enabled; + + this.okButton.Enabled = false; + this.largeTextBox.Enabled = false; + this.largeExclamationLabel.Enabled = false; + this.unitComboBox.Enabled = false; + + _previousCursor = Cursor.Current; + Cursor.Current = Cursors.WaitCursor; + } + + private void DoneUpdate() + { + log.Debug("DoneUpdate"); + this.okButton.Enabled = GetStoredOrDefault("okButton"); + this.largeTextBox.Enabled = GetStoredOrDefault("largeTextBox"); + this.largeExclamationLabel.Enabled = GetStoredOrDefault("largeExclamationLabel"); + this.unitComboBox.Enabled = GetStoredOrDefault("unitComboBox"); + Cursor.Current = _previousCursor; + + if (iAutocloseGap > 0) + { + AutoClickOkAfterDelay(); + } + } + + public void UpdateVolume(IRegReader eArgsReader, double eArgsVolume) + { + log.Debug($"RegReader name: {eArgsReader.Name}, Serial No updated: " + eArgsVolume); + PopulateVolume(eArgsReader, eArgsVolume); + } + + /// 24-bit counter wrap in liters: 2^24 ticks * 0.00025 L/tick + private const double VOL_RANGE_LITERS = 16777216.0 * 0.00025; // 4194.304 + + /// + /// Populate Volume - also include roll over VOL_RANGE_LITERS + /// Unit test Concept: TBFTests/Rig/DataEntry/Uni/PopulateVolumeRolloverTests_Concept.cs + /// + /// + /// + public void PopulateVolume(IRegReader eArgsReader, double eArgsVolume) + { + + if (regReaders == null || Double.IsNaN(eArgsVolume) || textBoxes == null) + return; + + int regReadersLength = regReaders.Length; + int comboRows = textBoxes.GetLength(0); + int comboCols = textBoxes.GetLength(1); + + //just combine Start and End - switch column to write + List ctValues = isEnd + ? new List { Ct.EndState, Ct.EndStateAux } + : new List { Ct.StartState, Ct.StartStateAux }; + + double VolumeRaw = eArgsVolume; + // Test and compensate roll over + if (isEnd) + { + if (eArgsReader != null && (!Double.IsNaN(eArgsReader.BeginWMState))) + { + if (eArgsReader.BeginWMState > VolumeRaw) //Do RollOver + { + VolumeRaw = eArgsVolume + VOL_RANGE_LITERS; + log.Debug( + $"Roll over detected: {eArgsReader.Name} - {eArgsReader.BeginWMState} -> {VolumeRaw}"); + } + } + else + { + //volume from form + Double beginVolume = findBeginStateFromForm(); + + + if (beginVolume > VolumeRaw) //Do RollOver + { + VolumeRaw = eArgsVolume + VOL_RANGE_LITERS; + log.Debug( + $"Begin from Form! Roll over detected: {eArgsReader.Name} - {beginVolume} -> {VolumeRaw}"); + } + } + } + + for (int k = 0; k < colItems.Count && k < comboRows; k++) + { + Ct current = (Ct)colItems[k].Content; + if (ctValues.Contains(current)) // it define if is start or end + { + for (int ix = 0; ix < wmsCount && ix < comboCols; ix++) + { + int regIndex = ix; + + if (regIndex >= 0 && regIndex < regReadersLength) + { + var textBox = textBoxes[k, ix]; + if (textBox != null && regReaders[regIndex] == eArgsReader) + { + try + { + if (VolumeUnit == Unit.None) + VolumeUnit = Unit.l; + Double convertTo = Units.ConvertTo(VolumeUnit, VolumeRaw); + textBox.Text = convertTo.ToString(); + } + catch (Exception ex) + { + log.Error($"Error converting volume to {VolumeUnit}: {ex.Message}"); + } + } + } + } + } + } + } + + private Double findBeginStateFromForm() + { + + List ctValues = new List { Ct.StartState, Ct.StartStateAux }; + + int regReadersLength = regReaders.Length; + int comboRows = textBoxes.GetLength(0); + int comboCols = textBoxes.GetLength(1); + + for (int k = 0; k < colItems.Count && k < comboRows; k++) + { + Ct current = (Ct)colItems[k].Content; + if (ctValues.Contains(current)) // it define if is start or end + { + for (int ix = 0; ix < wmsCount && ix < comboCols; ix++) + { + int regIndex = ix; + + if (regIndex >= 0 && regIndex < regReadersLength) + { + var textBox = textBoxes[k, ix]; + if (textBox != null && textBox.Text != null && textBox.Text.Length > 0) + { + try + { + if (VolumeUnit == Unit.None) + VolumeUnit = Unit.l; + double VolumeRaw = Double.Parse(textBox.Text); + Double convertBeginVolumeINLiters = Units.ConvertFrom(VolumeUnit, VolumeRaw); + return convertBeginVolumeINLiters; + } + catch (Exception ex) + { + log.Error($"Error converting volume to {VolumeUnit}: {ex.Message}"); + } + } + } + } + } + } + + return 0.0D; + } + /// /// When one combo box is updated using drop-down menu, all combo boxes /// are updated by this function. @@ -1181,7 +1393,11 @@ namespace TBF.Rig.DataEntry.Uni Brush lightBrush = new SolidBrush(Color.LightGreen); Brush darkBrush = new SolidBrush(Color.Green); Font largeFont = new Font("arial", 24.0F, FontStyle.Bold); /// normal image - Font smallFont = new Font("arial", 12.0F, FontStyle.Bold); /// zoomed image + Font smallFont = new Font("arial", 12.0F, FontStyle.Bold); + + + + /// zoomed image /// /// Show selected image in the picture box. @@ -1252,5 +1468,137 @@ namespace TBF.Rig.DataEntry.Uni } #endregion + + public event EventHandler VolumeStartReadbyRegReader; + public event EventHandler DoneUpdateByRegReader; + + public sealed class VolumeReadEventArgs : EventArgs + { + public IRegReader Reader { get; private set; } + public double Volume { get; private set; } + + public VolumeReadEventArgs(IRegReader reader, double volume) + { + Reader = reader; + Volume = volume; + } + } + + public sealed class VolumeReadDoneEventArgs : EventArgs + { + public VolumeReadDoneEventArgs() + { + } + } + + protected virtual void OnReadVolume(IRegReader reader, double volume) + { + var handler = VolumeStartReadbyRegReader; // copy for thread-safety + if (handler == null) return; + if (IsHandleCreated && InvokeRequired) + { + BeginInvoke(new Action(() => + handler(this, new VolumeReadEventArgs(reader, volume)))); + } + else + { + handler(this, new VolumeReadEventArgs(reader, volume)); + } + } + + protected virtual void OnReadDone() + { + var handler = DoneUpdateByRegReader; // copy for thread-safety + if (handler == null) return; + + if (IsHandleCreated && InvokeRequired) + { + BeginInvoke(new Action(() => + handler(this, new VolumeReadDoneEventArgs()))); + } + else + { + handler(this, new VolumeReadDoneEventArgs()); + } + } + + public async void ReadVolumeAsync(IEnumerable regReaders) + { + log.Debug("Reading serial numbers from register readers..."); + + try + { + var groups = regReaders + .OfType() + .GroupBy(r => r.Group) + .OrderBy(g => g.Key); + + foreach (var group in groups) + { + var subGroups = group + .GroupBy(r => r.MuxBoardNrOrGroup14) + .OrderBy(sg => sg.Key); + + foreach (var subGroup in subGroups) + { + log.Debug(string.Format("Processing Group {0}, SubGroup {1}", group.Key, subGroup.Key)); + + // Start tasks in parallel inside subgroup + var tasks = subGroup.Select(async r => + { + double volume = Double.NaN; + if (isEnd) + { + volume = await r.DataEntry_ReadEndVolume().ConfigureAwait(false); + } + else + { + volume = await r.DataEntry_ReadBeginVolume().ConfigureAwait(false); + } + return new KeyValuePair((IRegReader)r, volume); + }).ToList(); + + var results = await Task.WhenAll(tasks).ConfigureAwait(false); + + foreach (var kv in results) + { + var reader = kv.Key; + var volume = kv.Value; + + // Notify for each successful read + OnReadVolume(reader, volume); + } + } + } + } + catch (Exception ex) + { + log.Error("Error reading Strat Volume from register readers", ex); + } + finally + { + OnReadDone(); + } + log.Debug("Reading Start Volume DONE!"); + } + + public void AutoClickOkAfterDelay(int delayMs = 10000) + { + _ = AutoClickInternal(okButton, delayMs); + } + + private async Task AutoClickInternal(Button clickButton, int delayMs) + { + await Task.Delay(delayMs); + + if (clickButton.IsHandleCreated && clickButton.Enabled && clickButton.Visible) + { + // Invoke on UI thread + if (clickButton.InvokeRequired) + clickButton.BeginInvoke(new Action(() => clickButton.PerformClick())); + else + clickButton.PerformClick(); + } + } } } diff --git a/TBF/Rig/DataEntry/iPerl/CycleBeginningForm.cs b/TBF/Rig/DataEntry/iPerl/CycleBeginningForm.cs index 5ed22db3b..2c9e579b7 100644 --- a/TBF/Rig/DataEntry/iPerl/CycleBeginningForm.cs +++ b/TBF/Rig/DataEntry/iPerl/CycleBeginningForm.cs @@ -39,10 +39,7 @@ namespace TBF.Rig.DataEntry.iPerl public CycleBeginningForm() { InitializeComponent(); - - this.Icon = Properties.Resources.TBF_icon; - - ControlBox = false; + ControlBox = false; completed = false; StartForceCloseHandler(); diff --git a/TBF/Rig/DataEntry/iPerl/TestStartEndForm.cs b/TBF/Rig/DataEntry/iPerl/TestStartEndForm.cs index 385ee420b..e4fabb2e7 100644 --- a/TBF/Rig/DataEntry/iPerl/TestStartEndForm.cs +++ b/TBF/Rig/DataEntry/iPerl/TestStartEndForm.cs @@ -50,10 +50,7 @@ namespace TBF.Rig.DataEntry.iPerl public TestStartEndForm() { InitializeComponent(); - - this.Icon = Properties.Resources.TBF_icon; - - ControlBox = false; + ControlBox = false; TextBoxesCount = 48; diff --git a/TBF/Rig/Dummy/FlowMeter/FlowMeterCfg.cs b/TBF/Rig/Dummy/FlowMeter/FlowMeterCfg.cs index a2ba2eebb..629d72527 100644 --- a/TBF/Rig/Dummy/FlowMeter/FlowMeterCfg.cs +++ b/TBF/Rig/Dummy/FlowMeter/FlowMeterCfg.cs @@ -54,9 +54,12 @@ namespace TBF.Rig.Dummy.FlowMeter double msrdValLimLo = 0; double msrdValLimHi; + [XmlIgnore] + public bool IsOffline { get; set; } - /// Private parameterless constructor invoked by all other (public) constructors - FlowMeterCfg() + + /// Private parameterless constructor invoked by all other (public) constructors + FlowMeterCfg() { GNodes = new List(); } @@ -89,7 +92,7 @@ namespace TBF.Rig.Dummy.FlowMeter { "Nominal flow [m3/h]", /// 0 "Display format", /// 1 - "Unit of flow on a display", /// 2 + "Units of flow on a display", /// 2 }; public string ParamName(int i) { return paramNames[i]; } public int ParamsCount() { return paramNames.Length; } diff --git a/TBF/Rig/GenericDevices/IRegReaderSmart.cs b/TBF/Rig/GenericDevices/IRegReaderSmart.cs new file mode 100644 index 000000000..5133990d5 --- /dev/null +++ b/TBF/Rig/GenericDevices/IRegReaderSmart.cs @@ -0,0 +1,16 @@ +using System; +using System.Threading.Tasks; + +namespace TBF.Rig.GenericDevices +{ + public interface IRegReaderSmart + { + Task DataEntry_ReadSerialNumber(); + Task DataEntry_ReadBeginVolume(); + Task DataEntry_ReadEndVolume(); + + int Group { get; } + int MuxBoardNrOrGroup14 { get; } + + } +} \ No newline at end of file diff --git a/TBF/Rig/GenericDevices/IScaleCfg.cs b/TBF/Rig/GenericDevices/IScaleCfg.cs index c3ef15835..4dd3e3d6d 100644 --- a/TBF/Rig/GenericDevices/IScaleCfg.cs +++ b/TBF/Rig/GenericDevices/IScaleCfg.cs @@ -14,7 +14,7 @@ namespace TBF.Rig.GenericDevices float BuoyancyTemp { get; set; } /// ambient temperature in [degree C] float BuoyancyPress { get; set; } /// ambient pressure in [100000 Pa] float BuoyancyHumi { get; set; } /// ambient relative humidity in [%] - float WeightStandardDensity { get; set; } /// density of the weight standard used to calibrate the scale [kg/m3] + float WeightStandardDensity { get; set; } /// density of the volume standard used to calibrate the scale [kg/m3] } } diff --git a/TBF/Rig/GenericDevices/ITestMethod.cs b/TBF/Rig/GenericDevices/ITestMethod.cs index e355909db..da72e8e85 100644 --- a/TBF/Rig/GenericDevices/ITestMethod.cs +++ b/TBF/Rig/GenericDevices/ITestMethod.cs @@ -9,12 +9,19 @@ namespace TBF.Rig.GenericDevices { public interface ITestMethod : TBF.Rig.Generic.IComponent { - /// - /// Check compatibility of the method with the watermeters - /// - /// Type of watermeters - /// true when the watermeters can be tested by this method - bool CanTest(MetersKind meters); + /// + /// Check compatibility of the method with the watermeters + /// + /// Type of watermeters + /// true when the watermeters can be tested by this method + FlowType MethodFlowType { get; } + + /// + /// Check compatibility of the method with the watermeters + /// + /// Type of watermeters + /// true when the watermeters can be tested by this method + bool CanTest(MetersKind meters); /// /// Check capabilities of devces in the output path required for this test method diff --git a/TBF/Rig/GenericDevices/ITestMethodSmart.cs b/TBF/Rig/GenericDevices/ITestMethodSmart.cs new file mode 100644 index 000000000..b7cb466f2 --- /dev/null +++ b/TBF/Rig/GenericDevices/ITestMethodSmart.cs @@ -0,0 +1,11 @@ +namespace TBF.Rig.GenericDevices +{ + /// + /// * mark test method from smart family devices + /// * (this Test method is used for devices that support smart reader) + /// + public interface ITestMethodSmart + { + + } +} \ No newline at end of file diff --git a/TBF/Rig/Sequences/MainSeq.cs b/TBF/Rig/Sequences/MainSeq.cs index 1ae3f8e76..ae6a22162 100644 --- a/TBF/Rig/Sequences/MainSeq.cs +++ b/TBF/Rig/Sequences/MainSeq.cs @@ -56,23 +56,39 @@ namespace TBF.Rig.Sequences { try { + // /// 1nd argument + // ITestMethodCfg testMethodCfg = cfg as ITestMethodCfg; + // if (testMethodCfg == null) + // { + // + // } + // + // /// 2rd argument: as is + // + // /// 3th argument + // IList iPerlCommParams = new List(); + // foreach (var tp in multiTestParams) iPerlCommParams.Add(tp as iPerlCommunicationParams); + // + // /*myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams); + // myRef.modelessDlg.Show();*/ + // + // myRef.modelessDlg = new SmartCommunicationForm( testMethod , tests, iPerlCommParams); + // myRef.modelessDlg.Show(); + /// 1nd argument - ITestMethodCfg testMethodCfg = cfg as ITestMethodCfg; - if (testMethodCfg == null) - { - - } + TestMethods.iPerlCommunication.TestMethodCfg iPerlCfg = cfg as TestMethods.iPerlCommunication.TestMethodCfg; /// 2rd argument: as is /// 3th argument - IList iPerlCommParams = new List(); - foreach (var tp in multiTestParams) iPerlCommParams.Add(tp as iPerlCommunicationParams); + IList iPerlCommParams = new List(); + foreach (var tp in multiTestParams) iPerlCommParams.Add(tp as TestMethods.iPerlCommunication.iPerlCommunicationParams); /*myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams); myRef.modelessDlg.Show();*/ - myRef.modelessDlg = new SmartCommunicationForm( testMethod , tests, iPerlCommParams); + myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm( + testMethod as TBF.Rig.TestMethods.iPerlCommunication.TestMethod, tests, iPerlCommParams); myRef.modelessDlg.Show(); } catch (Exception e) diff --git a/TBF/Rig/TestMethods/Adjustment/TestMethod.cs b/TBF/Rig/TestMethods/Adjustment/TestMethod.cs index 5c0dccdcd..ed1a6a571 100644 --- a/TBF/Rig/TestMethods/Adjustment/TestMethod.cs +++ b/TBF/Rig/TestMethods/Adjustment/TestMethod.cs @@ -13,6 +13,9 @@ namespace TBF.Rig.TestMethods.Adjustment public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/ChangeFlowDirection/TestMethod.cs b/TBF/Rig/TestMethods/ChangeFlowDirection/TestMethod.cs index 0a1632b4a..652f774a2 100644 --- a/TBF/Rig/TestMethods/ChangeFlowDirection/TestMethod.cs +++ b/TBF/Rig/TestMethods/ChangeFlowDirection/TestMethod.cs @@ -13,6 +13,9 @@ namespace TBF.Rig.TestMethods.ChangeFlowDirection public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/CombinedWithDetection/TestMethod.cs b/TBF/Rig/TestMethods/CombinedWithDetection/TestMethod.cs index d9c50a777..be5eaf8aa 100644 --- a/TBF/Rig/TestMethods/CombinedWithDetection/TestMethod.cs +++ b/TBF/Rig/TestMethods/CombinedWithDetection/TestMethod.cs @@ -24,6 +24,8 @@ namespace TBF.Rig.TestMethods.CombinedWithDetection readonly TestMethodCfg testMethodCfg; public bool IsRise { get { return testMethodCfg != null ? testMethodCfg.IsRise : false; } } + public FlowType MethodFlowType => FlowType.volume; + public TestMethod() { } /// public TestMethod(Generic.IComponentCfg cfg) diff --git a/TBF/Rig/TestMethods/Counter/TestMethod.cs b/TBF/Rig/TestMethods/Counter/TestMethod.cs index ff4a676d4..e62b771b1 100644 --- a/TBF/Rig/TestMethods/Counter/TestMethod.cs +++ b/TBF/Rig/TestMethods/Counter/TestMethod.cs @@ -29,6 +29,9 @@ namespace TBF.Rig.TestMethods.Counter /// static int nextCounterIdx = 0; public static int CountersCount { get { return nextCounterIdx; } } + + public FlowType MethodFlowType => FlowType.volume; + public static TestMethod[] Counters = new TestMethod[0]; /// private int counterIdx0; /// 0-based index of this counter diff --git a/TBF/Rig/TestMethods/DiverterTest/Component.cs b/TBF/Rig/TestMethods/DiverterTest/Component.cs index a236534d2..58d1502f2 100644 --- a/TBF/Rig/TestMethods/DiverterTest/Component.cs +++ b/TBF/Rig/TestMethods/DiverterTest/Component.cs @@ -24,7 +24,9 @@ namespace TBF.Rig.TestMethods.DiverterTest readonly TestMethodCfg testMethodCfg; - public Component() { } + public FlowType MethodFlowType => FlowType.volume; + + public Component() { } public Component(Generic.IComponentCfg cfg) : base(cfg) diff --git a/TBF/Rig/TestMethods/Dummy/TestMethod.cs b/TBF/Rig/TestMethods/Dummy/TestMethod.cs index 79b8d3955..c04668e27 100644 --- a/TBF/Rig/TestMethods/Dummy/TestMethod.cs +++ b/TBF/Rig/TestMethods/Dummy/TestMethod.cs @@ -13,6 +13,9 @@ namespace TBF.Rig.TestMethods.Dummy public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/Endurance/Component.cs b/TBF/Rig/TestMethods/Endurance/Component.cs index f748b74c1..52066a834 100644 --- a/TBF/Rig/TestMethods/Endurance/Component.cs +++ b/TBF/Rig/TestMethods/Endurance/Component.cs @@ -24,6 +24,8 @@ namespace TBF.Rig.TestMethods.Endurance readonly TestMethodCfg testMethodCfg; + public FlowType MethodFlowType => FlowType.volume; + public Component() { } /// public Component(Generic.IComponentCfg cfg) diff --git a/TBF/Rig/TestMethods/Evacuation/Component.cs b/TBF/Rig/TestMethods/Evacuation/Component.cs index f78a44f08..aa33fff63 100644 --- a/TBF/Rig/TestMethods/Evacuation/Component.cs +++ b/TBF/Rig/TestMethods/Evacuation/Component.cs @@ -12,7 +12,9 @@ namespace TBF.Rig.TestMethods.Evacuation public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); - public override string ToString() + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", GetType().Namespace.Substring(8), Cfg.ToString(1)); } diff --git a/TBF/Rig/TestMethods/FixedStart/Compound/Component.cs b/TBF/Rig/TestMethods/FixedStart/Compound/Component.cs index 94de94da4..5a50b37cd 100644 --- a/TBF/Rig/TestMethods/FixedStart/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FixedStart/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStart.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FixedStart/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FixedStart/HeatMeters/Component.cs index 5e4a5fd3e..eb396b1af 100644 --- a/TBF/Rig/TestMethods/FixedStart/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FixedStart/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStart.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FixedStart/Single/Component.cs b/TBF/Rig/TestMethods/FixedStart/Single/Component.cs index 187011867..e204b1aaf 100644 --- a/TBF/Rig/TestMethods/FixedStart/Single/Component.cs +++ b/TBF/Rig/TestMethods/FixedStart/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStart.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FixedStartAdvanced/Single/Component.cs b/TBF/Rig/TestMethods/FixedStartAdvanced/Single/Component.cs index 4c10f789d..e3fdf0b36 100644 --- a/TBF/Rig/TestMethods/FixedStartAdvanced/Single/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartAdvanced/Single/Component.cs @@ -13,6 +13,9 @@ namespace TBF.Rig.TestMethods.FixedStartAdvanced.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FixedStartDeferredEval/Compound/Component.cs b/TBF/Rig/TestMethods/FixedStartDeferredEval/Compound/Component.cs index f1cc51ce9..15ac430a6 100644 --- a/TBF/Rig/TestMethods/FixedStartDeferredEval/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartDeferredEval/Compound/Component.cs @@ -35,7 +35,9 @@ namespace TBF.Rig.TestMethods.FixedStartDeferredEval.Compound private IntermediateData intermediateData; public object IntermediateData { get { return intermediateData; } } - public IList Execute(Test test, int repetNr, bool isLastRepetition) + public FlowType MethodFlowType => FlowType.volume; + + public IList Execute(Test test, int repetNr, bool isLastRepetition) { return (new FixedStartDeferredEvalSeq()).Execute(test, repetNr, isLastRepetition, true, null, DebugLevel, out intermediateData); } diff --git a/TBF/Rig/TestMethods/FixedStartDeferredEval/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FixedStartDeferredEval/HeatMeters/Component.cs index b70f05dab..3aa1248cc 100644 --- a/TBF/Rig/TestMethods/FixedStartDeferredEval/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartDeferredEval/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartDeferredEval.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethodWith2ndPass { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FixedStartDeferredEval/Single/Component.cs b/TBF/Rig/TestMethods/FixedStartDeferredEval/Single/Component.cs index 26244738c..505c2ca75 100644 --- a/TBF/Rig/TestMethods/FixedStartDeferredEval/Single/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartDeferredEval/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartDeferredEval.Single public class Component : ComponentBase, GenericDevices.ITestMethodWith2ndPass { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Compound/Component.cs b/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Compound/Component.cs index 9f55dcf52..40b63cdbf 100644 --- a/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Compound/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.FixedStartMassCollAdvanced.Compound public class Component : ComponentBase, GenericDevices.ITestMethod, ISequenceCondition { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/HeatMeters/Component.cs index ed8668f72..263709f25 100644 --- a/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/HeatMeters/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.FixedStartMassCollAdvanced.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod, ISequenceCondition { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Single/Component.cs b/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Single/Component.cs index e161a7891..e3d520945 100644 --- a/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Single/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartMassCollAdvanced/Single/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.FixedStartMassCollAdvanced.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Compound/Component.cs b/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Compound/Component.cs index 1f6a2383d..75d1fe8b7 100644 --- a/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartMassCollDeferredEval.Compound public class Component : ComponentBase, GenericDevices.ITestMethodWith2ndPass { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/HeatMeters/Component.cs index 1a42125c1..00b2b25f8 100644 --- a/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartMassCollDeferredEval.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethodWith2ndPass { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Single/Component.cs b/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Single/Component.cs index ee9903300..305eda5a7 100644 --- a/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Single/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartMassCollDeferredEval/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartMassCollDeferredEval.Single public class Component : ComponentBase, GenericDevices.ITestMethodWith2ndPass { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FixedStartTankCollection/Compound/Component.cs b/TBF/Rig/TestMethods/FixedStartTankCollection/Compound/Component.cs index a27b29393..7fa716ced 100644 --- a/TBF/Rig/TestMethods/FixedStartTankCollection/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartTankCollection/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartTankCollection.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FixedStartTankCollection/Single/Component.cs b/TBF/Rig/TestMethods/FixedStartTankCollection/Single/Component.cs index 9e4d4dd44..777e57006 100644 --- a/TBF/Rig/TestMethods/FixedStartTankCollection/Single/Component.cs +++ b/TBF/Rig/TestMethods/FixedStartTankCollection/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FixedStartTankCollection.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlowAdjustment/Component.cs b/TBF/Rig/TestMethods/FlowAdjustment/Component.cs index 4e5d338a0..7c46d2e20 100644 --- a/TBF/Rig/TestMethods/FlowAdjustment/Component.cs +++ b/TBF/Rig/TestMethods/FlowAdjustment/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlowAdjustment public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlyingStart/Compound/Component.cs b/TBF/Rig/TestMethods/FlyingStart/Compound/Component.cs index 766f1233f..6756a495c 100644 --- a/TBF/Rig/TestMethods/FlyingStart/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStart/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStart.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FlyingStart/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FlyingStart/HeatMeters/Component.cs index ba4e0d45e..77575540f 100644 --- a/TBF/Rig/TestMethods/FlyingStart/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStart/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStart.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FlyingStart/Single/Component.cs b/TBF/Rig/TestMethods/FlyingStart/Single/Component.cs index a12b7a7aa..099cfe2fc 100644 --- a/TBF/Rig/TestMethods/FlyingStart/Single/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStart/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStart.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Compound/Component.cs b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Compound/Component.cs index 4b138c002..9905f219f 100644 --- a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartFirstRepetWithMassColl.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/HeatMeters/Component.cs index af705957d..a926d0c43 100644 --- a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartFirstRepetWithMassColl.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Single/Component.cs b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Single/Component.cs index c7dcd4757..132e2a9fd 100644 --- a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Single/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartFirstRepetWithMassColl.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Compound/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Compound/Component.cs index 77ce82531..01e8d0567 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Compound/Component.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollComparative.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/HeatMeters/Component.cs index 6a7d64f30..5dc3bb5a0 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollComparative.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Single/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Single/Component.cs index 2a0303897..7b72b3a88 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Single/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollComparative.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Compound/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Compound/Component.cs index 9485d2e13..0ec35c4d4 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollProlonged.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/HeatMeters/Component.cs index a766deb0d..28356e9ab 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollProlonged.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Single/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Single/Component.cs index 21c169761..27a1f6c7d 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Single/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollProlonged.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollection/Compound/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollection/Compound/Component.cs index e0d8417cd..6540c998b 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollection/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollection/Compound/Component.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollection/HeatMeters/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollection/HeatMeters/Component.cs index 058dfd7b9..9abb8d5a8 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollection/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollection/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollection/Single/Component.cs b/TBF/Rig/TestMethods/FlyingStartMassCollection/Single/Component.cs index 16216d4dd..097f9eeab 100644 --- a/TBF/Rig/TestMethods/FlyingStartMassCollection/Single/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartMassCollection/Single/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/FlyingStartTankCollection/Compound/Component.cs b/TBF/Rig/TestMethods/FlyingStartTankCollection/Compound/Component.cs index 5471e1ebc..59120e61f 100644 --- a/TBF/Rig/TestMethods/FlyingStartTankCollection/Compound/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartTankCollection/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartTankCollection.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/FlyingStartTankCollection/Single/Component.cs b/TBF/Rig/TestMethods/FlyingStartTankCollection/Single/Component.cs index e0718c2cf..0844cd551 100644 --- a/TBF/Rig/TestMethods/FlyingStartTankCollection/Single/Component.cs +++ b/TBF/Rig/TestMethods/FlyingStartTankCollection/Single/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.FlyingStartTankCollection.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/GrabImage/Component.cs b/TBF/Rig/TestMethods/GrabImage/Component.cs index 3671eacee..547f57e8c 100644 --- a/TBF/Rig/TestMethods/GrabImage/Component.cs +++ b/TBF/Rig/TestMethods/GrabImage/Component.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.GrabImage public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/LeakTest/TestMethod.cs b/TBF/Rig/TestMethods/LeakTest/TestMethod.cs index dcadf3cf0..111902349 100644 --- a/TBF/Rig/TestMethods/LeakTest/TestMethod.cs +++ b/TBF/Rig/TestMethods/LeakTest/TestMethod.cs @@ -15,6 +15,8 @@ namespace TBF.Rig.TestMethods.LeakTest public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/LiveStream/Component.cs b/TBF/Rig/TestMethods/LiveStream/Component.cs index 03b8c1cc9..3d5073cd5 100644 --- a/TBF/Rig/TestMethods/LiveStream/Component.cs +++ b/TBF/Rig/TestMethods/LiveStream/Component.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.LiveStream public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/ManualEntry/Component.cs b/TBF/Rig/TestMethods/ManualEntry/Component.cs index b1479c7cb..9796f8b02 100644 --- a/TBF/Rig/TestMethods/ManualEntry/Component.cs +++ b/TBF/Rig/TestMethods/ManualEntry/Component.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.ManualEntry public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } readonly ManualEntryCfg myCfg; diff --git a/TBF/Rig/TestMethods/OuterLoop/End/Component.cs b/TBF/Rig/TestMethods/OuterLoop/End/Component.cs index 0930abef9..6e694ac4d 100644 --- a/TBF/Rig/TestMethods/OuterLoop/End/Component.cs +++ b/TBF/Rig/TestMethods/OuterLoop/End/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.OuterLoop.End public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/OuterLoop/Start/Component.cs b/TBF/Rig/TestMethods/OuterLoop/Start/Component.cs index c3c4edd62..6557b7090 100644 --- a/TBF/Rig/TestMethods/OuterLoop/Start/Component.cs +++ b/TBF/Rig/TestMethods/OuterLoop/Start/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.OuterLoop.Start public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/PMaxTest/TestMethod.cs b/TBF/Rig/TestMethods/PMaxTest/TestMethod.cs index f05ed0a9d..25fc77282 100644 --- a/TBF/Rig/TestMethods/PMaxTest/TestMethod.cs +++ b/TBF/Rig/TestMethods/PMaxTest/TestMethod.cs @@ -15,6 +15,8 @@ namespace TBF.Rig.TestMethods.PMaxTest public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/PulsesTest/TestMethod.cs b/TBF/Rig/TestMethods/PulsesTest/TestMethod.cs index ef791482a..c3896570e 100644 --- a/TBF/Rig/TestMethods/PulsesTest/TestMethod.cs +++ b/TBF/Rig/TestMethods/PulsesTest/TestMethod.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.PulsesTest public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/PulsesTestManual/TestMethod.cs b/TBF/Rig/TestMethods/PulsesTestManual/TestMethod.cs index 1b6193968..e4ec7d998 100644 --- a/TBF/Rig/TestMethods/PulsesTestManual/TestMethod.cs +++ b/TBF/Rig/TestMethods/PulsesTestManual/TestMethod.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.PulsesTestManual public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/Q2CorrectionFromHistory/Component.cs b/TBF/Rig/TestMethods/Q2CorrectionFromHistory/Component.cs index f41d83a51..62d760e6b 100644 --- a/TBF/Rig/TestMethods/Q2CorrectionFromHistory/Component.cs +++ b/TBF/Rig/TestMethods/Q2CorrectionFromHistory/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.Q2CorrectionFromHistory public class Component : ComponentBase, GenericDevices.ISimultTestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/RoiDetection/RoiDetection.cs b/TBF/Rig/TestMethods/RoiDetection/RoiDetection.cs index 7da50e655..5676cb691 100644 --- a/TBF/Rig/TestMethods/RoiDetection/RoiDetection.cs +++ b/TBF/Rig/TestMethods/RoiDetection/RoiDetection.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.RoiDetection public class RoiDetection : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(RoiDetection)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return true; } diff --git a/TBF/Rig/TestMethods/S640Communication/S640End.cs b/TBF/Rig/TestMethods/S640Communication/S640End.cs index 024764e9f..0d8716783 100644 --- a/TBF/Rig/TestMethods/S640Communication/S640End.cs +++ b/TBF/Rig/TestMethods/S640Communication/S640End.cs @@ -21,7 +21,9 @@ namespace TBF.Rig.TestMethods.S640Communication public class S640End : ComponentBase, GenericDevices.ISimultTestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(S640End)); - public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return false; } diff --git a/TBF/Rig/TestMethods/S640Communication/S640Start.cs b/TBF/Rig/TestMethods/S640Communication/S640Start.cs index 2fa2d1cc5..6f1cb4a46 100644 --- a/TBF/Rig/TestMethods/S640Communication/S640Start.cs +++ b/TBF/Rig/TestMethods/S640Communication/S640Start.cs @@ -21,7 +21,9 @@ namespace TBF.Rig.TestMethods.S640Communication public class S640Start : ComponentBase, GenericDevices.ISimultTestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(S640Start)); - public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return false; } diff --git a/TBF/Rig/TestMethods/SensitivityTest/TestMethod.cs b/TBF/Rig/TestMethods/SensitivityTest/TestMethod.cs index 661617d22..2e0d78bbb 100644 --- a/TBF/Rig/TestMethods/SensitivityTest/TestMethod.cs +++ b/TBF/Rig/TestMethods/SensitivityTest/TestMethod.cs @@ -13,6 +13,8 @@ namespace TBF.Rig.TestMethods.SensitivityTest public class TestMethod : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/SmartMeterFlyingStartMassCollection/TestMethod.cs b/TBF/Rig/TestMethods/SmartMeterFlyingStartMassCollection/TestMethod.cs index 06263ed90..c10a1e989 100644 --- a/TBF/Rig/TestMethods/SmartMeterFlyingStartMassCollection/TestMethod.cs +++ b/TBF/Rig/TestMethods/SmartMeterFlyingStartMassCollection/TestMethod.cs @@ -22,7 +22,8 @@ namespace TBF.Rig.TestMethods.SmartMeterFlyingStartMassCollection public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } - public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return false; } public bool SimultWithPrevious { get { return _testMethodCfg.TestParams.SimultWithPrevious; } } diff --git a/TBF/Rig/TestMethods/SmartTest/TestMethod.cs b/TBF/Rig/TestMethods/SmartTest/TestMethod.cs index 90f3cb53b..873ab6f73 100644 --- a/TBF/Rig/TestMethods/SmartTest/TestMethod.cs +++ b/TBF/Rig/TestMethods/SmartTest/TestMethod.cs @@ -22,6 +22,8 @@ namespace TBF.Rig.TestMethods.SmartTest public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return false; } diff --git a/TBF/Rig/TestMethods/StandingStart/Compound/Component.cs b/TBF/Rig/TestMethods/StandingStart/Compound/Component.cs index 2f5cdb9f9..ad6b7ae7e 100644 --- a/TBF/Rig/TestMethods/StandingStart/Compound/Component.cs +++ b/TBF/Rig/TestMethods/StandingStart/Compound/Component.cs @@ -12,6 +12,9 @@ namespace TBF.Rig.TestMethods.StandingStart.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/StandingStart/HeatMeters/Component.cs b/TBF/Rig/TestMethods/StandingStart/HeatMeters/Component.cs index 8c1ddb148..87279a296 100644 --- a/TBF/Rig/TestMethods/StandingStart/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/StandingStart/HeatMeters/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.StandingStart.HeatMeters public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } diff --git a/TBF/Rig/TestMethods/StandingStart/Single/Component.cs b/TBF/Rig/TestMethods/StandingStart/Single/Component.cs index 810a9a18f..f309bcb90 100644 --- a/TBF/Rig/TestMethods/StandingStart/Single/Component.cs +++ b/TBF/Rig/TestMethods/StandingStart/Single/Component.cs @@ -12,6 +12,9 @@ namespace TBF.Rig.TestMethods.StandingStart.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/StandingStartMassCollWODiv/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollWODiv/Component.cs index c20d71a3f..7dd49d9f1 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollWODiv/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollWODiv/Component.cs @@ -12,6 +12,9 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollWODiv public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/StandingStartMassCollection/Compound/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollection/Compound/Component.cs index 8ba5e4a28..23314398b 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollection/Compound/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollection/Compound/Component.cs @@ -12,6 +12,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/StandingStartMassCollection/HeatMeters/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollection/HeatMeters/Component.cs index 377da9672..54989e7ee 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollection/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollection/HeatMeters/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection.HeatMeters private static readonly ILog log = LogManager.GetLogger(typeof(Component)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } public bool DoTransitions() { return true; } public bool CheckDeviceCaps(Test test, OutputPath devices, out string message) diff --git a/TBF/Rig/TestMethods/StandingStartMassCollection/Single/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollection/Single/Component.cs index 43ddc8d89..48c3770ac 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollection/Single/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollection/Single/Component.cs @@ -13,7 +13,9 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection.Single { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } - + + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return true; } public bool CheckDeviceCaps(Test test, OutputPath devices, out string message) diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Compound/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Compound/Component.cs index 5965db49e..5fe0d4087 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Compound/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Compound/Component.cs @@ -12,6 +12,9 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvance.Compound public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/HeatMeters/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/HeatMeters/Component.cs index 193984440..b790ed208 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/HeatMeters/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvance.HeatMeters private static readonly ILog log = LogManager.GetLogger(typeof(Component)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } public bool DoTransitions() { return true; } public bool CheckDeviceCaps(Test test, OutputPath devices, out string message) diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Single/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Single/Component.cs index cd5c3105c..96965cf69 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Single/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/Single/Component.cs @@ -17,6 +17,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvance.Single public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool IsSupportedCollector(IComponent component) { return (component is IProcedureCameraCollect); } + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return true; } public bool CheckDeviceCaps(Test test, OutputPath devices, out string message) diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/Single/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/Single/Component.cs index 5af2f197a..9dca8cea5 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/Single/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/Single/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvanceCollect.Single public class Component : ComponentBase, GenericDevices.ITestMethod, IProcedureCameraCollect { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.volume; public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } private Procedure parentProcedure; diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Compound/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Compound/Component.cs index 7a78b8390..44d665871 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Compound/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Compound/Component.cs @@ -14,6 +14,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.Compound private static readonly ILog log = LogManager.GetLogger(typeof(Component)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; } public bool DoTransitions() { return true; } public bool CheckDeviceCaps(Test test, OutputPath devices, out string message) diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/HeatMeters/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/HeatMeters/Component.cs index 0c38aec23..ea817b40b 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/HeatMeters/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/HeatMeters/Component.cs @@ -13,7 +13,9 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } - + + public FlowType MethodFlowType => FlowType.volume; + public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; } public bool DoTransitions() { return true; } public bool CheckDeviceCaps(Test test, OutputPath devices, out string message) diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Single/Component.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Single/Component.cs index b7c86676b..7ba3bfa87 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Single/Component.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionPoseidon/Single/Component.cs @@ -12,6 +12,9 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.Single public class Component : ComponentBase, GenericDevices.ITestMethod { private static readonly ILog log = LogManager.GetLogger(typeof(Component)); + + public FlowType MethodFlowType => FlowType.mass; + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/CommCompletedEventArgs.cs b/TBF/Rig/TestMethods/iPerlCommunication/CommCompletedEventArgs.cs index c23bb0a47..b0bec23db 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/CommCompletedEventArgs.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/CommCompletedEventArgs.cs @@ -31,7 +31,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication ThreadId, WMNr0, (Ihead != null) ? Ihead.Name : "null", - Wm.WMPosition, + (Wm != null) ? Wm.WMPosition : -1, (CommMessage != null) ? CommMessage : "null", CommErr); } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/OpticalHeadTest.cs b/TBF/Rig/TestMethods/iPerlCommunication/OpticalHeadTest.cs index 4bbf6e05b..9eaa28552 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/OpticalHeadTest.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/OpticalHeadTest.cs @@ -1,4 +1,4 @@ -using Config.Resources; +using Config.Resources; using log4net; using Sensus.iPerl.RfidCom.Helper; using Sensus.iPerl.RfidCom.Services; @@ -7,8 +7,6 @@ using System; using System.Threading; using TBF.Rig.Hart.Common; using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; -using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication; -using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations; using static Sensus.iPerl.NfcHandler.MCI_Protocol; namespace TBF.Rig.TestMethods.iPerlCommunication @@ -28,7 +26,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication try { byte[] pcb = null; - int readRetVal = IPerlCorrections.ReadRequestPort(SmartCommunicationForm.TestMethodCfg, iHead, RegisterReaders.CommonRR.MessageID.Configuration, Sensus.iPerl.NfcHandler.MCI_Protocol.StructName.Configuration, 16, 5, out pcb); + int readRetVal = iPerlCommunicationForm.ReadRequestPort(iHead, MessageID.Configuration, Sensus.iPerl.NfcHandler.MCI_Protocol.StructName.Configuration, 16, 5, out pcb); if (readRetVal == 0) { return RfidHelper.HexLiteral2Unsigned(RfidHelper.SwapHexcode(BitConverter.ToString(pcb).Replace("-", string.Empty))).ToString(); @@ -45,7 +43,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication internal static string SetActiveMode(IperlHead iHead) { byte[] cmd = new byte[1] { (byte)Command.SetActiveMode }; - if (0 == IPerlCorrections.WriteRequestPort(SmartCommunicationForm.TestMethodCfg, iHead, RegisterReaders.CommonRR.MessageID.Command, StructName.Command, 0, 1, cmd)) + if (0 == iPerlCommunicationForm.WriteRequestPort(iHead, MessageID.Command, StructName.Command, 0, 1, cmd)) { return "OK"; } @@ -58,7 +56,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication internal static string SetTestMode(IperlHead iHead) { byte[] cmd = new byte[1] { (byte)Command.SetTestMode }; - if (0 == IPerlCorrections.WriteRequestPort(SmartCommunicationForm.TestMethodCfg, iHead, RegisterReaders.CommonRR.MessageID.Command, StructName.Command, 0, 1, cmd)) + if (0 == iPerlCommunicationForm.WriteRequestPort(iHead, MessageID.Command, StructName.Command, 0, 1, cmd)) { return "OK"; } @@ -73,7 +71,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication { try { - int retValue = IPerlCorrections.WriteRequestPort(SmartCommunicationForm.TestMethodCfg, iHead, RegisterReaders.CommonRR.MessageID.RadioPassthrough, StructName.RadioParams, 0x1898, 1, new byte[] { (byte)3 }); // WakeUpInterval + int retValue = iPerlCommunicationForm.WriteRequestPort(iHead, MessageID.RadioPassthrough, StructName.RadioParams, 0x1898, 1, new byte[] { (byte)3 }); // WakeUpInterval return 0 == retValue ? "OK" : "Error"; } catch (Exception ex) @@ -86,7 +84,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication { try { - int retValue = IPerlCorrections.WriteRequestPort(SmartCommunicationForm.TestMethodCfg,iHead, RegisterReaders.CommonRR.MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, 1, new byte[] { (byte)1 }); // System Status + int retValue = iPerlCommunicationForm.WriteRequestPort(iHead, MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, 1, new byte[] { (byte)1 }); // System Status return 0 == retValue ? "OK" : "Error"; } catch (Exception ex) diff --git a/TBF/Rig/TestMethods/iPerlCommunication/TestMethod.cs b/TBF/Rig/TestMethods/iPerlCommunication/TestMethod.cs index 211239883..947a10445 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/TestMethod.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/TestMethod.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using log4net; using Common; using Config.Entities; -using TBF.Rig.Generic; using TBF.Rig.GenericDevices; using TBF.Rig.Sequences; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication; @@ -14,18 +13,20 @@ using TBF.UiBridge; namespace TBF.Rig.TestMethods.iPerlCommunication { - public class TestMethod : SmartComponentBase, ISimultTestMethod, ISequenceCondition, ISessionDataMngmnt + public class TestMethod : SmartComponentBase, ISimultTestMethod, ISequenceCondition, ISessionDataMngmnt, ITestMethodSmart { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); - public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + public FlowType MethodFlowType => FlowType.volume; - public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } + + public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; } public bool DoTransitions() { return false; } - public bool SimultWithPrevious { get { return _testMethodCfgIPerl.TestParams.SimultWithPrevious; } } - public bool SimultWithNext { get { return _testMethodCfgIPerl.TestParams.SimultWithNext; } } + public bool SimultWithPrevious { get { return testMethodCfg.TestParams.SimultWithPrevious; } } + public bool SimultWithNext { get { return testMethodCfg.TestParams.SimultWithNext; } } #region Configuration Change Handling @@ -42,18 +43,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication { CfgChangeHandler += delegate(object sender, CfgChangeArgs args) { - TestMethodCfg_IPerl tmpCfgIPerl = args.Cfg as TestMethodCfg_IPerl; - if (tmpCfgIPerl != null && tmpCfgIPerl.Name.Equals(Name)) + TestMethodCfg tmpCfg = args.Cfg as TestMethodCfg; + if (tmpCfg != null && tmpCfg.Name.Equals(Name)) { if (args.Command == CfgChangeCmd.CfgChange) { - _testMethodCfgIPerl.CommTimeout = tmpCfgIPerl.CommTimeout; - _testMethodCfgIPerl.DelayBetweenRetries = tmpCfgIPerl.DelayBetweenRetries; - _testMethodCfgIPerl.MaxCommRetries = tmpCfgIPerl.MaxCommRetries; - _testMethodCfgIPerl.IperlCheckErrorsToStop = tmpCfgIPerl.IperlCheckErrorsToStop; - _testMethodCfgIPerl.UseWebService = tmpCfgIPerl.UseWebService; - _testMethodCfgIPerl.BaseUrl = tmpCfgIPerl.BaseUrl; - _testMethodCfgIPerl.RelativeUrl = tmpCfgIPerl.RelativeUrl; + testMethodCfg.CommTimeout = tmpCfg.CommTimeout; + testMethodCfg.DelayBetweenRetries = tmpCfg.DelayBetweenRetries; + testMethodCfg.MaxCommRetries = tmpCfg.MaxCommRetries; + testMethodCfg.IperlCheckErrorsToStop = tmpCfg.IperlCheckErrorsToStop; + testMethodCfg.UseWebService = tmpCfg.UseWebService; + testMethodCfg.BaseUrl = tmpCfg.BaseUrl; + testMethodCfg.RelativeUrl = tmpCfg.RelativeUrl; } } }; @@ -62,7 +63,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication #endregion Configuration Change Handling - readonly TestMethodCfg_IPerl _testMethodCfgIPerl; + readonly TestMethodCfg testMethodCfg; public bool[] IperlCommMilestone; IList sequenceConditionOps; @@ -75,7 +76,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication public TestMethod(Generic.IComponentCfg cfg) : base(cfg) { - _testMethodCfgIPerl = cfg as TestMethodCfg_IPerl; + testMethodCfg = cfg as TestMethodCfg; CreateMilestonesAndConditions(); } @@ -110,7 +111,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication { if (DebugLevel == DebugMode.Normal) { - return (new iPerlCommunicationSeq()).Execute(test, repetNr, this, _testMethodCfgIPerl.TestParams); + return (new iPerlCommunicationSeq()).Execute(test, repetNr, this, testMethodCfg.TestParams); } else { diff --git a/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfg_IPerl.cs b/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfg.cs similarity index 94% rename from TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfg_IPerl.cs rename to TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfg.cs index 39242cfc5..99f50111b 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfg_IPerl.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfg.cs @@ -14,9 +14,9 @@ using TBF.Rig.TestMethods.SmartMeterFlyingStartMassCollection; namespace TBF.Rig.TestMethods.iPerlCommunication { [XmlRoot("TestMethodCfg")] // Add this attribute to match the XML root - public class TestMethodCfg_IPerl : ComponentCfgBase, IiPerlTestMethodCfg + public class TestMethodCfg : ComponentCfgBase, IiPerlTestMethodCfg { - public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestMethodCfg_IPerl) })[0]; + public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestMethodCfg) })[0]; public override XmlSerializer GetSerializer() { return Serializer; } public IComponentCfgCtrl GetControl(IList cmpntEntities) { return new TestMethodCfgCtrl(); } @@ -30,7 +30,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication } /// Private parameterless constructor invoked by all other (public) constructors - TestMethodCfg_IPerl() + TestMethodCfg() { Name = "SmartCommunication"; ParentName = string.Empty; @@ -49,7 +49,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication TestParams = CreateTestParamsProvider() as iPerlCommunicationParams; } - public TestMethodCfg_IPerl(IComponentFactory factory) + public TestMethodCfg(IComponentFactory factory) : this() { this.Factory = factory; diff --git a/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfgCtrl.cs b/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfgCtrl.cs index fe1e8a86f..033152d15 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfgCtrl.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/TestMethodCfgCtrl.cs @@ -7,7 +7,6 @@ using Common; using Config.Entities; using TBF.Rig.Generic; using TBF.Resources; -using TBF.Rig.RegisterReaders.CommonRR.IPerl; namespace TBF.Rig.TestMethods.iPerlCommunication { @@ -15,13 +14,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication { public bool ShowMore { get { return false; } } - TestMethodCfg_IPerl config; + TestMethodCfg config; public IComponentCfg Config { get { return config as IComponentCfg; } set { - config = value as TestMethodCfg_IPerl; + config = value as TestMethodCfg; Redraw(); } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/TestMethodFactory.cs b/TBF/Rig/TestMethods/iPerlCommunication/TestMethodFactory.cs index 437c86575..d72ececac 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/TestMethodFactory.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/TestMethodFactory.cs @@ -9,18 +9,16 @@ namespace TBF.Rig.TestMethods.iPerlCommunication public class TestMethodFactory : IComponentFactory { public string ClassName { get { return GetType().Namespace.Substring(8); } } - - public override string ToString() { return ClassName; } public IComponent DummyComponent() { return new TestMethod(); } public IComponent GetComponent(IComponentCfg cfg, IList components) { return new TestMethod(cfg); } - public IComponentCfg DefaultConfig() { return new TestMethodCfg_IPerl(this); } + public IComponentCfg DefaultConfig() { return new TestMethodCfg(this); } public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) { - return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg_IPerl.Serializer, component, this); + return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg.Serializer, component, this); } } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs b/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs new file mode 100644 index 000000000..4a11bcfa7 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs @@ -0,0 +1,351 @@ +/// +/// Copyright (c) 2015-2021 Sensus Metering Systems +/// + +using System; +using System.Globalization; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer; + +namespace TBF.Rig.TestMethods.iPerlCommunication.common +{ + public enum OptoTelegramFlags : byte + { + OK = 0, + OK_TestStart, + OK_TestEnd, + InvalidTelegram, /// Wrong telegram format of checksum error + SyncError, + } + + public class OptoTelegramRaw + { + public static readonly int Length = 42; + private static CultureInfo culture; + + + /// + /// Strobed value + /// + public static decimal TestStartTimestampDec; + + /// + /// Stored values + /// + public OptoTelegramFlags Flags; + + public DateTime DateTime; /// From PC + public float RefFlow; /// [m3/h] + public int Counter; + + public Int32 EmfRaw; /// Signed EMF from iPerl opto data + public Int16 MagneticFieldRaw; + public Int16 FlowRaw; + public double VolumeRaw; + public double VolumeRawExt; + public Int16 Impedance; + public double Timestamp; + public double TimestampExt; + public byte CheckSum; + + /// + /// Calculated values + /// + public double EMF() + { + return 0.000000333 * (double)EmfRaw; + } + public double MagneticField() { return (double)MagneticFieldRaw; } + public double Flow(double scalingFactor) { return 0.225 * scalingFactor * (double)FlowRaw; } + public double Volume(double scalingFactor) { return 0.0000625 * scalingFactor * (double)VolumeRawExt; } + public Int32 FlipTime() { return Impedance; } + public decimal TimestampDec() { return (decimal)TimestampExt / (decimal)8192; } + public double VolumeDelta(double scalingFactor, OptoTelegramRaw previous) { return (previous == null) ? 0 : Volume(scalingFactor) - previous.Volume(scalingFactor); } + public decimal TimeDelta() { return TimestampDec() - TestStartTimestampDec; } + public string Label() + { + if (Flags == OptoTelegramFlags.OK_TestStart) return "#### start test ####"; + else if (Flags == OptoTelegramFlags.OK_TestEnd) return "#### end of test ####"; + else return string.Empty; + } + + + static OptoTelegramRaw() + { + culture = CultureInfo.CreateSpecificCulture("DE"); /// This is to use comma as decimal number separator + } + + public OptoTelegramRaw() + { + } + + /// + /// Parses optical telegram and returns OptoTelegramRaw object + /// + /// + /// Create a configuration structure from a complete byte array + /// + /// Telegram description: + /// + /// AAAAAA[tab]BBBB[tab]CCCC[tab]DDDDDD[tab]EEEE[tab]FFFFFFFF[tab]GG[cr][lf] (42 bytes) + /// + /// Data Comment Type Calculate to decimal + /// ---------------------------------------------------------------- + /// AAAAAA EMF Int24 Value * 0.000000333 + /// BBBB Magnetic field Int16 Value + /// CCCC Flow Int16 Value * 0.225 * Scalig factor + /// DDDDDD Volume Int24 Value / 16000 * Scaling factor + /// EEEE Impedance Int16 Value + /// FFFFFFFF Timestamp Uint32 Value / 8192 + /// GG Checksum Byte + /// ---------------------------------------------------------------- + /// + /// Example: + /// FFFFFE 51EA 0000 65324E 0087 F6319DFF 86 + /// FFDD3A 51F9 0000 65324E 0088 F631A60B 45 + /// ... + /// + /// A complete byte array data + /// true = telegram OK, false = telegram NOK + // public bool UpdateFromString(string telegram, int counter, float refFlow, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast, bool isLog = false) + // { + // DateTime = DateTime.Now; + // Counter = counter; + // RefFlow = refFlow; + // + // if ((telegram == null) || (telegram.Length < Length) || + // (telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') || + // (telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') || + // (!isLog && (telegram[40] != '\r' || telegram[41] != '\n'))) + // { + // Flags = OptoTelegramFlags.InvalidTelegram; + // return false; + // } + // + // UInt32 uEmfRaw; + // bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out uEmfRaw); + // EmfRaw = (uEmfRaw > 0x7FFFFF) ? ((int)uEmfRaw - 0x1000000) : (int)uEmfRaw; + // + // bool f2 = Int16.TryParse(telegram.Substring(7, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out MagneticFieldRaw); + // bool f3 = Int16.TryParse(telegram.Substring(12, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out FlowRaw); + // bool f4 = UInt32.TryParse(telegram.Substring(17, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out VolumeRaw); + // bool f5 = Int16.TryParse(telegram.Substring(24, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Impedance); + // bool f6 = UInt32.TryParse(telegram.Substring(29, 8), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Timestamp); + // bool f7 = byte.TryParse(telegram.Substring(38, 2), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out CheckSum); + // + // byte calculatedCheckSum = 0; + // for (int i = 0; i < Length - 4; i++) + // { + // calculatedCheckSum += (byte)telegram[i]; + // } + // + // bool allOk = f1 && f2 && f3 && f4 && f5 && f6 && f7 && (calculatedCheckSum == CheckSum); + // + // if (allOk) + // { + // /// + // /// Cope with 'VolumeRaw' overflow + // /// + // Int64 uncorrected = (Int64)(((UInt64)volumeRawExtLast & 0xFFFFFFFFFF000000UL) | VolumeRaw); + // if (Math.Abs(uncorrected - volumeRawExtLast) <= 0x800000L) + // { + // VolumeRawExt = volumeRawExtLast = uncorrected; + // } + // else if (Math.Abs(uncorrected + 0x1000000L - volumeRawExtLast) <= 0x800000L) + // { + // VolumeRawExt = volumeRawExtLast = uncorrected + 0x1000000L; + // } + // else if (Math.Abs(uncorrected - 0x1000000L - volumeRawExtLast) <= 0x800000L) + // { + // VolumeRawExt = volumeRawExtLast = uncorrected - 0x1000000L; + // } + // else + // { + // VolumeRawExt = volumeRawExtLast = uncorrected; + // } + // + // /// + // /// Cope with 'Timestamp' overflow + // /// + // uncorrected = (Int64)(((UInt64)timestampExtLast & 0xFFFFFFFF00000000UL) | Timestamp); + // if (Math.Abs(uncorrected - timestampExtLast) <= 0x80000000L) + // { + // TimestampExt = timestampExtLast = uncorrected; + // } + // else if (Math.Abs(uncorrected + 0x100000000L - timestampExtLast) <= 0x80000000L) + // { + // TimestampExt = timestampExtLast = uncorrected + 0x100000000L; + // } + // else if (Math.Abs(uncorrected - 0x100000000L - timestampExtLast) <= 0x80000000L) + // { + // TimestampExt = timestampExtLast = uncorrected - 0x100000000L; + // } + // else + // { + // TimestampExt = timestampExtLast = uncorrected; + // } + // } + // + // Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram; + // + // return allOk; + // } + + + // -------- TIMESTAMP (seconds) -------- + // bbbbbbbb – unsigned 32 bit ASIC time stamp in 8192 ticks per second– rolls over after 2^32 + private const double TS_TICKS_PER_SEC = 8192.0; + private const double TS_RANGE = 4294967296.0 / TS_TICKS_PER_SEC; // 2^32 / 8192 = 524288 sec + + // -------- VOLUME (liters) -------- + // vvvvvv is unsigned 24-bit, 1 tick = 1/4 ml = 0.00025 L + private const double VOL_LITERS_PER_TICK = 0.00025; // liters per tick + private const double VOL_RANGE = 16777216.0 * VOL_LITERS_PER_TICK; // 2^24 * 0.00025 = 4194.304 L + + // -------- VOLUME (liters) -------- + private const double GAL_TO_LITER = 3.785411784; + + public void UpdateFromSmart( + DiagnosticLedState4Data data, + int counter, + float refFlow, + ref double volumeRawExtLast, + ref double timestampExtLast) + { + DateTime = DateTime.Now; + Counter = counter; + RefFlow = refFlow; + + FlowRaw = data.RawFlow; + VolumeRaw = data.RawVolume; + + // ---- TIMESTAMP RAW (seconds, modulo TS_RANGE) ---- + // If upstream conversion ever produced negative values, normalize them. + double ts = data.AsicTimestamp; // already in seconds, but wraps every TS_RANGE + ts = ts % TS_RANGE; + if (ts < 0) ts += TS_RANGE; + + Timestamp = ts; + + // ---------- VOLUME UNWRAP ---------- + double v = VolumeRaw; + + if (double.IsNaN(volumeRawExtLast)) + { + VolumeRawExt = volumeRawExtLast = v; + } + else + { + // nearest-lap unwrap + //double k = Math.Round(volumeRawExtLast - v) / VOL_RANGE); + if (v < volumeRawExtLast) + { + VolumeRawExt = volumeRawExtLast = v + VOL_RANGE; + } + else + { + VolumeRawExt = volumeRawExtLast = v; + } + } + + // ---------- TIMESTAMP UNWRAP (seconds) ---------- + if (double.IsNaN(timestampExtLast)) + { + TimestampExt = timestampExtLast = ts; + } + else + { + // robust unwrap: choose the smallest jump across the modulo boundary + double lastMod = timestampExtLast % TS_RANGE; + if (lastMod < 0) lastMod += TS_RANGE; + + double delta = ts - lastMod; + + if (delta < -TS_RANGE / 2.0) delta += TS_RANGE; + else if (delta > TS_RANGE / 2.0) delta -= TS_RANGE; + + TimestampExt = timestampExtLast = timestampExtLast + delta; + } + + } + + + + /// + /// Alternative to UpdateFromString(...) when data are flushed + /// + public bool UpdateFromStringDummy(string telegram) + { + DateTime = DateTime.Now; + RefFlow = 0; + + if ((telegram == null) || (telegram.Length < Length) || + (telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') || + (telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') || + (telegram[40] != '\r') || (telegram[41] != '\n')) + { + Flags = OptoTelegramFlags.InvalidTelegram; + return false; + } + + bool f7 = byte.TryParse(telegram.Substring(38, 2), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out CheckSum); + + byte calculatedCheckSum = 0; + for (int i = 0; i < Length - 4; i++) + { + calculatedCheckSum += (byte)telegram[i]; + } + + bool allOk = f7 && (calculatedCheckSum == CheckSum); + + Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram; + + return allOk; + } + + + public void SetFlags(OptoTelegramFlags flags) + { + this.Flags = flags; + } + + + public string ToString(double scalingFactor, OptoTelegramRaw previous) + { + if (Flags == OptoTelegramFlags.SyncError) + { + return "Sychronization error"; + } + else if (Flags == OptoTelegramFlags.InvalidTelegram) + { + return "Invalid telegram"; + } + else /// if (flags == OptoTelegramFlags.OK / OptoTelegramFlags.OK_TestStart / OptoTelegramFlags.OK_TestEnd) + { + return string.Format("{0}:{1}:{2}.{3}\t{4} :\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}\t{14}\t{15}\t{16}\t{17}\t{18}\t{19}\t{20}\t{21}\t{22}", + DateTime.Hour.ToString("D2"), + DateTime.Minute.ToString("D2"), + DateTime.Second.ToString("D2"), + DateTime.Millisecond.ToString("D4"), + Counter, + (EmfRaw & 0x00FFFFFF).ToString("X6"), + MagneticFieldRaw.ToString("X4"), + FlowRaw.ToString("X4"), + VolumeRaw.ToString("X6"), + Impedance.ToString("X4"), + Timestamp.ToString("X8"), + CheckSum.ToString("X2"), + EMF().ToString("F4", culture), + MagneticField().ToString("F0", culture), + Flow(scalingFactor).ToString("F2", culture), + Volume(scalingFactor).ToString("F4", culture), + FlipTime().ToString("F0", culture), + TimestampDec().ToString("F4", culture), + (RefFlow * 1000).ToString("F2", culture), + VolumeDelta(scalingFactor, previous).ToString("F4", culture), + TimeDelta().ToString("F3", culture), + scalingFactor.ToString("F1", culture), + Label()); + } + } + } +} diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrame.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrame.cs new file mode 100644 index 000000000..7730399e9 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrame.cs @@ -0,0 +1,25 @@ +using System; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol +{ + public sealed class IperlHatFrame + { + public byte Start { get; } + public byte Direction { get; } + public byte End { get; } + public byte Length { get; } + + public byte[] CommandInformation { get; } + public byte[] Payload { get; } + + public IperlHatFrame(byte start, byte direction, byte length, byte[] commandBytes, byte[] payload, byte end) + { + Start = start; + Direction = direction; + Length = length; + CommandInformation = commandBytes ?? Array.Empty(); + Payload = payload ?? Array.Empty(); + End = end; + } + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameBuilder.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameBuilder.cs new file mode 100644 index 000000000..078d526f4 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameBuilder.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol +{ + public sealed class IperlHatFrameBuilder + { + + private byte _direction; + private readonly List _commandBytes = new List(); + private readonly List _payload = new List(); + + public IperlHatFrameBuilder RequestResponse(bool enabled) + { + _direction = enabled ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Write : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Read; + return this; + } + + public IperlHatFrameBuilder AddCommand(ProtocolCommand command) + { + _commandBytes.Add((byte)command); + return this; + } + + public IperlHatFrameBuilder AddSubCommand(ProtocolCommand subCommand) + { + if (_commandBytes.Count == 0 || + _commandBytes[0] != (byte)ProtocolCommand.DeviceSpecific) + throw new InvalidOperationException( + "Sub-command is only valid for DeviceSpecific (0xFD) commands."); + + _commandBytes.Add((byte)subCommand); + return this; + } + + public IperlHatFrameBuilder AddSubCommand(ProtocolStatuses subCommand) + { + if (_commandBytes.Count == 0 || + _commandBytes[0] != (byte)ProtocolCommand.SetState) + throw new InvalidOperationException( + "Sub-command is only valid for SetState (0xA1) commands."); + + _commandBytes.Add((byte)subCommand); + return this; + } + + public IperlHatFrameBuilder AddDeviceCommand( + ProtocolDeviceSubCommand subCommand) + { + _commandBytes.Add((byte)ProtocolCommand.DeviceSpecific); + _commandBytes.Add((byte)subCommand); + return this; + } + + public IperlHatFrameBuilder SetVersionCommand() + { + _commandBytes.Add((byte)ProtocolCommand.Question); + _payload.AddRange(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Version); + return this; + } + + public IperlHatFrameBuilder AddPayload(byte[] payload) + { + if (payload != null) + _payload.AddRange(payload); + + return this; + } + + public IperlHatFrameBuilder AddPayload(DiagnosticLedState state) + { + _payload.Add((byte)state); + + return this; + } + + public IperlHatFrameBuilder AddPayload(byte payload) + { + _payload.Add(payload); + + return this; + } + + public IperlHatFrameBuilder AddDiagnosticLedState(DiagnosticLedState state) + { + RequestResponse(true); + AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState); + AddPayload((byte)state); + return this; + } + + public IperlHatFrameBuilder AddNullTerminatedAscii(string text) + { + if (!string.IsNullOrEmpty(text)) + _commandBytes.AddRange( + System.Text.Encoding.ASCII.GetBytes(text)); + + _commandBytes.Add(0x00); + return this; + } + + public IperlHatFrame BuildFrame() + { + if (_commandBytes.Count == 0) + throw new InvalidOperationException("No command specified."); + + byte length = (byte)(4 + _commandBytes.Count + _payload.Count); // 4 = START + dirrection + LEN + END + + + return new IperlHatFrame( + TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start, + _direction, + length, + _commandBytes.ToArray(), + _payload.ToArray(), + TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End); + } + + public byte[] BuildBytes() + { + IperlHatFrame frame = BuildFrame(); + + if (frame.CommandInformation.Length > 0 && frame.CommandInformation[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question) + { + var bytes = new List + { + frame.Start, + frame.Direction, + }; + + bytes.AddRange(frame.CommandInformation); + bytes.AddRange(frame.Payload); + bytes.Add(frame.End); + + return bytes.ToArray(); + } + else + { + var bytes = new List + { + frame.Start, + frame.Direction, + frame.Length, + }; + + bytes.AddRange(frame.CommandInformation); + bytes.AddRange(frame.Payload); + bytes.Add(frame.End); + + return bytes.ToArray(); + } + } + + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameParser.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameParser.cs new file mode 100644 index 000000000..e57dafadd --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameParser.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol +{ + public sealed class IperlHatFrameParser + { + + public IperlHatResponse Parse(byte[] data) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + + if (data.Length < 5) + throw new FormatException("Frame too short."); + + + + if (data[0] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start) + { + //if version parse version + if (data[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question) + { + //Define Question answer + var prefix = new List{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question }; + var end = new List{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End }; + + if (IsPrefixValid(data, prefix, end)) + { + //whole payload may be like "vers: Harry T:B800, V:06.06.01, FW:190215, 7ECE, B1.6.01, HW:4, Serial:0" + prefix = new List{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question }; + byte[] payloadVersion = ExtractPayloadUsePrefix(data, prefix, end); + return new IperlHatResponse(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question, payloadVersion.Length > 0 ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusOk : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusNok, payloadVersion); + } + } + + throw new FormatException("Invalid START byte."); + } + + if (data[1] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Read) + throw new FormatException("Frame is no Response."); + + byte length = data[2]; + if (length != data.Length) + throw new FormatException("Length mismatch."); + + byte direction = data[1]; + byte status = data[3]; + + var prefixCommand = new List{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start,direction,length,status }; + var endCommand = new List{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End }; + + byte[] payload = ExtractPayloadUsePrefix(data,prefixCommand,endCommand); + + return new IperlHatResponse(0x00, status, payload); + } + + + private static byte[] ExtractPayloadUsePrefix(byte[] data, List prefix, List end) + { + // payload exists only if frame longer than: + // START + DIRECTION + LEN + CTRL + END = 5 bytes + // OR VERSION_START + VERSION = 5 bytes + if (data.Length <= 5) + return Array.Empty(); + + //check prefix is equal + int prefixLength = prefix.Count; + byte[] commandPrefix = new byte[prefixLength]; + Buffer.BlockCopy(data, 0, commandPrefix, 0, prefixLength); + + if (StartsWithPrefix(end, commandPrefix)) + { + return Array.Empty(); + } + + int payloadLength = data.Length - (prefix.Count + end.Count); + byte[] payload = new byte[payloadLength]; + Buffer.BlockCopy(data, prefix.Count, payload, 0, payloadLength); + return payload; + } + + private static bool IsPrefixValid(byte[] data, List prefix, List end) + { + int prefixLength = prefix.Count; + // payload exists only if frame longer than: + // OR VERSION_START + VERSION = 5 bytes - "?VERS" version implemented + if (data.Length <= prefixLength) // need be and on END + return false; + + //check prefix is equal + byte[] commandPrefix = new byte[prefixLength]; + Buffer.BlockCopy(data, 0, commandPrefix, 0, prefixLength); + + if (StartsWithPrefix(end, commandPrefix)) + { + return false; + } + + return true; + } + + private static bool StartsWithPrefix(List data, byte[] prefix) + { + if (data.Count < prefix.Length) + return false; + + for (int i = 0; i < prefix.Length; i++) + { + if (data[i] != prefix[i]) + return false; + } + + return true; + } + + private static byte[] ExtractVersionPayload(byte[] data) + { + // payload exists only if frame longer than: + // START + LEN + CTRL + STATUS + CHK_HI + CHK_LO = 6 bytes + if (data.Length <= 5) + return Array.Empty(); + + int payloadLength = data.Length - 4; + byte[] payload = new byte[payloadLength]; + Buffer.BlockCopy(data, 5, payload, 0, payloadLength); + return payload; + } + } + + +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatProtocol.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatProtocol.cs new file mode 100644 index 000000000..2cc4b1c4e --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatProtocol.cs @@ -0,0 +1,10 @@ +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol +{ + public static class IperlHatProtocol + { + public const byte START = 0x0D; + + // Control bits (CNTRL1) + public const byte RESPONSE_FLAG = 0x08; // RF + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatProtocolConstants.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatProtocolConstants.cs new file mode 100644 index 000000000..4e055e384 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatProtocolConstants.cs @@ -0,0 +1,15 @@ +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol +{ + public static class IperlHatProtocolConstants + { + public const byte Start = 0x53; //'S' + public const byte Write = 0x57; // 'W' + public const byte Read = 0x52; // 'R' + public const byte End = 0x0D; //'.' + public const byte Question = (byte)0x3F; // '?' + public static readonly byte[] Version = {0x76, 0x65, 0x72, 0x73 }; // 'v' 'e' 'r' 's' + + public const byte StatusOk = 0x01; + public const byte StatusNok = 0x00; + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatResponse.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatResponse.cs new file mode 100644 index 000000000..b1ca70750 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatResponse.cs @@ -0,0 +1,94 @@ +using System; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol +{ + public sealed class IperlHatResponse + { + public byte Control { get; } //classic control byte - valid for question now + private byte Status { get; } + public byte[] Payload { get; } + + public bool IsOk => Status == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusOk; + + public IperlHatResponse(byte control, byte status, byte[] payload) + { + Control = control; + Status = status; + Payload = payload ?? Array.Empty(); + } + + public int GetResponse(ref bool isInt) + { + if (Payload.Length > 0 && Payload.Length <= 1) + { + isInt = true; + return Payload[0]; + } + + isInt = false; + return 0xFD; + } + + public T GetResponse(out bool ok) where T : struct + { + ok = false; + + // we expect exactly 1 byte payload + if (Payload == null || Payload.Length != 1) + return default; + + byte raw = Payload[0]; + + Type t = typeof(T); + + // ----- BYTE ----- + if (t == typeof(byte)) + { + ok = true; + return (T)(object)raw; + } + + // ----- INT ----- + if (t == typeof(int)) + { + ok = true; + return (T)(object)(int)raw; + } + + // ----- USHORT ----- + if (t == typeof(ushort)) + { + ok = true; + return (T)(object)(ushort)raw; + } + + // ----- ENUM ----- + if (t.IsEnum) + { + // check if value exists in enum + if (!Enum.IsDefined(t, raw)) + return default; + + ok = true; + return (T)Enum.ToObject(t, raw); + } + + // unsupported type + return default; + } + + public string GetAsciiPayload() + { + if (Payload.Length == 0) + return null; + + int length = Array.IndexOf(Payload, (byte)0x00); + if (length < 0) + length = Payload.Length; + + return System.Text.Encoding.ASCII.GetString(Payload, 0, length); + } + } + + +} \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/DiagnosticLedParser.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/DiagnosticLedParser.cs similarity index 84% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/DiagnosticLedParser.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/DiagnosticLedParser.cs index 993697110..2c7e07b94 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/DiagnosticLedParser.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/DiagnosticLedParser.cs @@ -1,8 +1,8 @@ using System; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed { public sealed class DiagnosticLedParser { @@ -13,12 +13,12 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed _state = state; } - public DiagnosticLedData ParseLine(string line) + public DiagnosticLedData ParseLine(string line, bool checkLineTermination = true) { if (string.IsNullOrEmpty(line)) throw new ArgumentNullException(nameof(line)); - if (!line.EndsWith("\r\n")) + if (checkLineTermination && !line.EndsWith("\r\n")) throw new FormatException("Invalid diagnostic LED line termination"); string trimmed = line.TrimEnd('\r', '\n'); diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/DiagnosticLedState.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/DiagnosticLedState.cs new file mode 100644 index 000000000..033b93658 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/DiagnosticLedState.cs @@ -0,0 +1,100 @@ +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed +{ + /// + /// Diagnostic LED output mode. + /// + /// Determines the format and content of high-speed serial diagnostic data + /// emitted by the meter when the diagnostic LED is enabled. + /// + /// + /// Each state corresponds to a specific TAB-separated ASCII HEX frame layout + /// as defined in the iPERL TouchRead protocol documentation. + /// + /// + /// See + /// diagnostic LED States. + /// + /// + public enum DiagnosticLedState : byte + { + /// + /// Diagnostic LED OFF - State #0. + /// + /// Basic diagnostic output containing raw ADC, field strength, + /// flow rate, volume accumulator, and capacitor voltage. + /// + /// + StateOFF = 0x00, + + /// + /// Diagnostic LED State #1. + /// + /// Basic diagnostic output containing raw ADC, field strength, + /// flow rate, volume accumulator, and capacitor voltage. + /// + /// + State1 = 0x01, + + /// + /// Diagnostic LED State #2. + /// + /// Extends State #1 with LCD volume, meter state, + /// and low-flow cutoff indication. + /// + /// + State2 = 0x02, + + /// + /// Diagnostic LED State #3. + /// + /// Extends State #1 with field calibration value, + /// ASIC timestamp, and field drive time. + /// + /// + State3 = 0x03, + + /// + /// Diagnostic LED State #4. + /// + /// Extended diagnostic output including mean flow rate, + /// field measurements, integrator calibration values, + /// and ASIC state. + /// + /// + State4 = 0x04, + + /// + /// Diagnostic LED State #5. + /// + /// Extends State #4 with water impedance measurement. + /// + /// + State5 = 0x05, + + /// + /// Diagnostic LED State #6. + /// + /// Extends State #5 with electrode delta, spike detection data, + /// pipe status, LCD volume, and additional ASIC state. + /// + /// + State6 = 0x06, + + /// + /// Diagnostic LED State #7. + /// + /// Extends State #6 with raw ADC before offset correction, + /// detrended ADC value, imaginary water impedance, + /// electrode voltage noise, and ADC offset learning status. + /// + /// + State7 = 0x07, + + /// + /// Unknown state. + /// + StatusUnknown = 0xFF, + } +} diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedData.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedData.cs similarity index 75% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedData.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedData.cs index b53ad0f71..edc2c561e 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedData.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedData.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Base class for all Diagnostic LED data frames. @@ -39,6 +39,9 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed /// public abstract class DiagnosticLedData { + const double GalToLiterConversion = 3.785411784D; + public abstract int GetByteCount(); + /// /// Raw diagnostic LED line exactly as received from the meter, /// including checksum and CRLF. @@ -63,10 +66,35 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed public short RawFlow { get; protected set; } /// - /// Unsigned 24-bit raw volume accumulation in units of ¼ milliliter per bit. + /// Unsigned 24-bit raw volume accumulation in units of ¼ milliliter per bit. it is in Gal * 2 /// - public uint RawVolume { get; protected set; } - + public uint RawVolume1to4 { get; protected set; } // in 1/4 ml Gal * 2 + + /// + /// Raw volume in liters + /// + public double RawVolume // in liter + { + get + { + double volume = (RawVolume1to4 * 0.00025) ; // convert to liters + return volume; + } + } + + /// + /// Raw volume in Gal + /// + public double RawVolumeInGal // in Gal + { + get + { + double volume = (RawVolume1to4 * 4.0) / 1000.0F; // convert to Gal + //volume = (volume / GalToLiterConversion) / 2; // convert to liter + return volume; + } + } + /// /// Unsigned 16-bit millivolt delta measured on the field drive capacitor. /// diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedFrameSpec.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedFrameSpec.cs new file mode 100644 index 000000000..d034dcaef --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedFrameSpec.cs @@ -0,0 +1,37 @@ +using System; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer +{ + public static class DiagnosticLedFrameSpec + { + public static int GetExpectedAsciiLength(DiagnosticLedState state) + { + switch (state) + { + case DiagnosticLedState.State1: return 33; + case DiagnosticLedState.State2: return 48; + case DiagnosticLedState.State3: return 50; + case DiagnosticLedState.State4: return 84; + case DiagnosticLedState.State5: return 89; + case DiagnosticLedState.State6: return 112; + case DiagnosticLedState.State7: return 139; + default: throw new ArgumentOutOfRangeException(nameof(state)); + } + } + + public static int GetExpectedFieldCount(DiagnosticLedState state) + { + switch (state) + { + case DiagnosticLedState.State1: return 6; + case DiagnosticLedState.State2: return 9; + case DiagnosticLedState.State3: return 9; + case DiagnosticLedState.State4: return 15; + case DiagnosticLedState.State5: return 16; + case DiagnosticLedState.State6: return 21; + case DiagnosticLedState.State7: return 26; + default: throw new ArgumentOutOfRangeException(nameof(state)); + } + } + } +} \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState1Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState1Data.cs similarity index 68% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState1Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState1Data.cs index e905a4e8c..651a7637b 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState1Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState1Data.cs @@ -1,6 +1,6 @@ -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #1 data frame. @@ -33,8 +33,26 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed Adc24 = DiagnosticHex.ParseInt24(f[0]); FieldStrength = DiagnosticHex.ParseUInt16(f[1]); RawFlow = DiagnosticHex.ParseInt16(f[2]); - RawVolume = DiagnosticHex.ParseUInt24(f[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(f[3]); CapacitorMv = DiagnosticHex.ParseUInt16(f[4]); } + + public override string ToString() + { + return $"DiagnosticLedState1Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}"; + } + + /// + /// Format: xxxxxx aaaa yyyy vvvvvv cccc ss + /// Chars total = 26 + /// Tabs = 5 + /// CRLF = 2 + /// Total bytes = 33 + /// + /// Total bytes + public override int GetByteCount() + { + return 33; + } } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState2Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState2Data.cs similarity index 77% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState2Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState2Data.cs index d4eac87a8..f5364d6ae 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState2Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState2Data.cs @@ -1,6 +1,6 @@ -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #2 data frame. @@ -59,7 +59,7 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed Adc24 = DiagnosticHex.ParseInt24(fields[0]); FieldStrength = DiagnosticHex.ParseUInt16(fields[1]); RawFlow = DiagnosticHex.ParseInt16(fields[2]); - RawVolume = DiagnosticHex.ParseUInt24(fields[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]); // ---- State #2 specific ---- @@ -67,6 +67,24 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed MeterState = DiagnosticHex.ParseByte(fields[6]); IsLowFlowCutoff = DiagnosticHex.ParseByte(fields[7]) != 0; } + + public override string ToString() + { + return $"DiagnosticLedState2Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}, LcdVolume={LcdVolume}, MeterState={MeterState}, IsLowFlowCutoff={IsLowFlowCutoff}"; + } + + /// + /// Format: xxxxxx aaaa yyyy vvvvvv cccc gggggggg mm ff ss + /// Chars total = 38 + /// Tabs = 8 + /// CRLF = 2 + /// Total bytes = 48 + /// + /// Total bytes + public override int GetByteCount() + { + return 48; + } } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState3Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState3Data.cs similarity index 77% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState3Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState3Data.cs index 070c100f9..fb000f1dd 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState3Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState3Data.cs @@ -1,6 +1,6 @@ -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #3 data frame. @@ -59,7 +59,7 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed Adc24 = DiagnosticHex.ParseInt24(fields[0]); FieldStrength = DiagnosticHex.ParseUInt16(fields[1]); RawFlow = DiagnosticHex.ParseInt16(fields[2]); - RawVolume = DiagnosticHex.ParseUInt24(fields[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]); // ---- State #3 specific fields ---- @@ -67,5 +67,23 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed AsicTimestamp = DiagnosticHex.ParseUInt32(fields[6]); FieldDriveTimeUs = DiagnosticHex.ParseByte(fields[7]); } + + public override string ToString() + { + return $"DiagnosticLedState3Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}"; + } + + /// + /// Format: xxxxxx aaaa yyyy vvvvvv cccc tttt bbbbbbbb ff ss + /// Chars total = 40 + /// Tabs = 8 + /// CRLF = 2 + /// Total bytes = 50 + /// + /// Total bytes + public override int GetByteCount() + { + return 50; + } } } diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState4Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState4Data.cs similarity index 65% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState4Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState4Data.cs index 46c737059..bb0df1c27 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState4Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState4Data.cs @@ -1,6 +1,6 @@ -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #4 data frame. @@ -13,7 +13,7 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed /// 0 – xxxxxxsigned 24-bit ADC value /// 1 – aaaaunsigned 16-bit Field strength /// 2 – yyyysigned 16-bit Raw flow rate (1/4 ml per bit) - /// 3 – vvvvvvunsigned 24-bit Raw volume accumulation + /// 3 – vvvvvvunsigned 24 bit raw volume accumulation in ¼ ml per bit /// 4 – ccccunsigned 16-bit Capacitor mV delta /// 5 – ttttunsigned 16-bit Field calibration /// 6 – bbbbbbbbunsigned 32-bit ASIC timestamp @@ -30,7 +30,19 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed public sealed class DiagnosticLedState4Data : DiagnosticLedData { public ushort FieldCalibration { get; } - public uint AsicTimestamp { get; } + + /// + /// ASIC timestamp in seconds + /// + public double AsicTimestamp + { + get { return AsicTimestampTicks / 8192; } //4096.0; } + } + + /// + /// ASIC timestamp in units of 1 / 4096 seconds. + /// + public uint AsicTimestampTicks { get; } public byte FieldDriveTimeUs { get; } public int MeanFlowRate { get; } @@ -50,12 +62,13 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed Adc24 = DiagnosticHex.ParseInt24(fields[0]); FieldStrength = DiagnosticHex.ParseUInt16(fields[1]); RawFlow = DiagnosticHex.ParseInt16(fields[2]); - RawVolume = DiagnosticHex.ParseUInt24(fields[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); //1/4 ml Gal double CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]); // ---- State #4 specific ---- FieldCalibration = DiagnosticHex.ParseUInt16(fields[5]); - AsicTimestamp = DiagnosticHex.ParseUInt32(fields[6]); + + AsicTimestampTicks = DiagnosticHex.ParseUInt32(fields[6]); FieldDriveTimeUs = DiagnosticHex.ParseByte(fields[7]); MeanFlowRate = unchecked((int)DiagnosticHex.ParseUInt32(fields[8])); @@ -68,6 +81,24 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed AsicState = DiagnosticHex.ParseByte(fields[13]); } + + public override string ToString() + { + return $"DiagnosticLedState4Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, RawVolume1to4 = {RawVolume1to4}, RawVolumeGal={RawVolumeInGal}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}, MeanFlowRate={MeanFlowRate}, Field1Measurement={Field1Measurement}, Field2Measurement={Field2Measurement}, IntegratorCalibrationPositive={IntegratorCalibrationPositive}, IntegratorCalibrationNegative={IntegratorCalibrationNegative}, AsicState={AsicState}, RawLine={RawLine}"; + } + + /// + /// Format: xxxxxx aaaa yyyy vvvvvv cccc tttt bbbbbbbb mmmmmmmm ff gggg hhhh cccc nnnn qq ss + /// Chars total = 68 + /// Tabs = 14 + /// CRLF = 2 + /// Total bytes = 84 + /// + /// Total bytes + public override int GetByteCount() + { + return 84; + } } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState5Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState5Data.cs similarity index 79% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState5Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState5Data.cs index 2835d04fc..a18b926d3 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState5Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState5Data.cs @@ -1,6 +1,6 @@ -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #5 data frame. @@ -69,7 +69,7 @@ public sealed class DiagnosticLedState5Data : DiagnosticLedData Adc24 = DiagnosticHex.ParseInt24(fields[0]); FieldStrength = DiagnosticHex.ParseUInt16(fields[1]); RawFlow = DiagnosticHex.ParseInt16(fields[2]); - RawVolume = DiagnosticHex.ParseUInt24(fields[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]); // ---- State #5 specific ---- @@ -88,6 +88,24 @@ public sealed class DiagnosticLedState5Data : DiagnosticLedData AsicState = DiagnosticHex.ParseByte(fields[13]); WaterImpedance = DiagnosticHex.ParseInt16(fields[14]); } + + public override string ToString() + { + return $"DiagnosticLedState5Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}, MeanFlowRate={MeanFlowRate}, Field1Measurement={Field1Measurement}, Field2Measurement={Field2Measurement}, IntegratorCalibrationPositive={IntegratorCalibrationPositive}, IntegratorCalibrationNegative={IntegratorCalibrationNegative}, AsicState={AsicState}, WaterImpedance={WaterImpedance}"; + } + + /// + /// Format: xxxxxx aaaa yyyy vvvvvv cccc tttt bbbbbbbb mmmmmmmm ff iiii ss + /// Chars total = 72 + /// Tabs = 15 + /// CRLF = 2 + /// Total bytes = 89 + /// + /// Total bytes + public override int GetByteCount() + { + return 89; + } } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState6Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState6Data.cs similarity index 82% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState6Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState6Data.cs index 46a853867..5303a3417 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState6Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState6Data.cs @@ -1,7 +1,7 @@ using System; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #6 data frame. @@ -69,7 +69,7 @@ public sealed class DiagnosticLedState6Data : DiagnosticLedData Adc24 = DiagnosticHex.ParseInt24(fields[0]); FieldStrength = DiagnosticHex.ParseUInt16(fields[1]); RawFlow = DiagnosticHex.ParseInt16(fields[2]); - RawVolume = DiagnosticHex.ParseUInt24(fields[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]); // ---- State #6 specific ---- @@ -129,6 +129,24 @@ public sealed class DiagnosticLedState6Data : DiagnosticLedData return (SpikeDetectionStatus)SpikeDetection; } } + + public override string ToString() + { + return $"DiagnosticLedState6Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}, MeanFlowRate={MeanFlowRate}, Field1Measurement={Field1Measurement}, Field2Measurement={Field2Measurement}, IntegratorCalibrationPositive={IntegratorCalibrationPositive}, IntegratorCalibrationNegative={IntegratorCalibrationNegative}, AsicState0={AsicState0}, WaterImpedance={WaterImpedance}, SpikeDetection={SpikeDetection}, PipeStatus={PipeStatus}, LcdVolume={LcdVolume}, AsicState1={AsicState1}"; + } + + /// + /// Format: xxxxxx aaaa yyyy vvvvvv cccc tttt bbbbbbbb mmmmmmmm ff iiii rrrr pp ll dddddddd oo ss + /// Chars total = 90 + /// Tabs = 20 + /// CRLF = 2 + /// Total bytes = 112 + /// + /// Total bytes + public override int GetByteCount() + { + return 112; + } } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState7Data.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState7Data.cs similarity index 81% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState7Data.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState7Data.cs index e2ea42dff..37341581a 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/DiagnosticLedState7Data.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/DiagnosticLedState7Data.cs @@ -1,6 +1,6 @@ -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { /// /// Diagnostic LED State #7 data frame. @@ -98,7 +98,7 @@ public sealed class DiagnosticLedState7Data : DiagnosticLedData Adc24 = DiagnosticHex.ParseInt24(fields[0]); FieldStrength = DiagnosticHex.ParseUInt16(fields[1]); RawFlow = DiagnosticHex.ParseInt16(fields[2]); - RawVolume = DiagnosticHex.ParseUInt24(fields[3]); + RawVolume1to4 = DiagnosticHex.ParseUInt24(fields[3]); CapacitorMv = DiagnosticHex.ParseUInt16(fields[4]); // ---- State #6 fields ---- @@ -132,6 +132,24 @@ public sealed class DiagnosticLedState7Data : DiagnosticLedData ElectrodeVoltageNoise = DiagnosticHex.ParseUInt16(fields[23]); AdcOffsetLearningStatus = DiagnosticHex.ParseByte(fields[24]); } + + public override string ToString() + { + return $"DiagnosticLedState7Data: Adc24={Adc24}, FieldStrength={FieldStrength}, RawFlow={RawFlow}, RawVolume={RawVolume}, CapacitorMv={CapacitorMv}, FieldCalibration={FieldCalibration}, AsicTimestamp={AsicTimestamp}, FieldDriveTimeUs={FieldDriveTimeUs}, MeanFlowRate={MeanFlowRate}, Field1Measurement={Field1Measurement}, Field2Measurement={Field2Measurement}, IntegratorCalibrationPositive={IntegratorCalibrationPositive}, IntegratorCalibrationNegative={IntegratorCalibrationNegative}, AsicState0={AsicState0}, WaterImpedance={WaterImpedance}, ElectrodeDeltaMv={ElectrodeDeltaMv}, SpikeDetection={SpikeDetection}, PipeStatus={PipeStatus}, LcdVolume={LcdVolume}, AsicState1={AsicState1}, RawAdcBeforeOffset={RawAdcBeforeOffset}, DetrendedAdc={DetrendedAdc}, ImaginaryWaterImpedance={ImaginaryWaterImpedance}, ElectrodeVoltageNoise={ElectrodeVoltageNoise}, AdcOffsetLearningStatus={AdcOffsetLearningStatus}"; + } + + /// + /// Format: + /// Chars total = 112 + /// Tabs = 25 + /// CRLF = 2 + /// Total bytes = 139 + /// + /// Total bytes + public override int GetByteCount() + { + return 139; + } } } \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/PipeStatus.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/PipeStatus.cs similarity index 65% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/PipeStatus.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/PipeStatus.cs index 8a64ac23c..ce229feb9 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/PipeStatus.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/PipeStatus.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { public enum PipeStatus : byte { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/SpikeDetectionStatus.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/SpikeDetectionStatus.cs similarity index 67% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/SpikeDetectionStatus.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/SpikeDetectionStatus.cs index 5a5a700b4..ba1d8d324 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/parserer/SpikeDetectionStatus.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/parserer/SpikeDetectionStatus.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer { public enum SpikeDetectionStatus : byte { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/utils/DiagnosticChecksum.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnosticChecksum.cs similarity index 76% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/utils/DiagnosticChecksum.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnosticChecksum.cs index 3d9b5e4cd..34abc6571 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/utils/DiagnosticChecksum.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnosticChecksum.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils { internal static class DiagnosticChecksum { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/utils/DiagnosticHex.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnosticHex.cs similarity index 91% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/utils/DiagnosticHex.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnosticHex.cs index b08549f7a..fefd02486 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/utils/DiagnosticHex.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnosticHex.cs @@ -1,6 +1,6 @@ using System; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.utils +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils { internal static class DiagnosticHex { diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnostigLedDataByUnit.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnostigLedDataByUnit.cs new file mode 100644 index 000000000..960594c52 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/diagnosticLed/utils/DiagnostigLedDataByUnit.cs @@ -0,0 +1,49 @@ +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer; +using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils +{ + public class DiagnostigLedDataByUnit + { + private readonly Common.Unit _unitFlow; + private readonly Common.Unit _unitVolume; + private readonly DiagnosticLedState4Data _data; + + public DiagnostigLedDataByUnit(Common.Unit unitFlow, Common.Unit unitVolume, DiagnosticLedState4Data data) + { + this._unitFlow = unitFlow; + this._unitVolume = unitVolume; + this._data = data; + } + + public Common.Unit Unit => _unitVolume; + public DiagnosticLedState4Data Data => _data; + + public double RawFlow { + get { return UnitVolume(_unitFlow, _data.RawFlow); } + } + + public double RawVolume + { + get { return Common.Units.ConvertFrom(_unitVolume, _data.RawVolume); } + } + + public double AsicTimestamp + { + get { return _data.AsicTimestamp; } + } + + public static double UnitVolume(Common.Unit unit, double volume) + { + return Common.Units.ConvertFrom(unit, volume); /// 1 liter + } + + public static uint DeltaTicks(uint oldTicks, uint newTicks) + { + return newTicks >= oldTicks + ? newTicks - oldTicks + : uint.MaxValue - oldTicks + newTicks + 1; + } + + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/HexFormatter.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/HexFormatter.cs new file mode 100644 index 000000000..e87448abe --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/HexFormatter.cs @@ -0,0 +1,175 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger +{ + public static class HexFormatter + { + /// + /// Byte to hex string. + /// Formats a single byte as 0xNN. + /// Example: 0x0D + /// + public static string ToHex(byte value) + { + return "0x" + value.ToString("X2"); + } + + /// + /// int to byte - securely + /// + /// + /// + /// + public static byte ToHexByte(int value) + { + if (value < 0 || value > 255) + throw new ArgumentOutOfRangeException(nameof(value), + "Value must be between 0 and 255."); + + return (byte)value; + } + + /// + /// Formats a byte array as 0xNN 0xNN ... + /// + public static string ToHex(byte[] data) + { + if (data == null || data.Length == 0) + return ""; + + var sb = new System.Text.StringBuilder(); + + for (int i = 0; i < data.Length; i++) + { + if (i > 0) + sb.Append(' '); + + sb.Append("0x"); + sb.Append(data[i].ToString("X2")); + } + + return sb.ToString(); + } + + /// + /// Formats a byte array exactly as shown in serial terminals. + /// Example: "0D 04 08 01 00 1A" + /// + public static string ToSerialHex(byte[] data) + { + if (data == null || data.Length == 0) + return string.Empty; + + var sb = new System.Text.StringBuilder(); + + for (int i = 0; i < data.Length; i++) + { + if (i > 0) + sb.Append(' '); + + sb.Append(data[i].ToString("X2")); + } + + return sb.ToString(); + } + + + public static string ToHexWithAscii(byte value) + { + char c = (value >= 32 && value <= 126) ? (char)value : '.'; + return $"0x{value:X2} ('{c}')"; + } + + public static string ToSerialHexWithAscii(byte[] data) + { + if (data == null || data.Length == 0) + return string.Empty; + + var hex = new StringBuilder(data.Length * 3); + var ascii = new StringBuilder(data.Length); + + foreach (byte b in data) + { + hex.Append(b.ToString("X2")).Append(' '); + + // Printable ASCII range + if (b >= 32 && b <= 126) + { + ascii.Append((char)b); + } + // Binary numbers 0–9 -> show digit + else if (b <= 9) + { + ascii.Append((char)('0' + b)); + } + else + { + ascii.Append('.'); + } + } + + // remove last trailing space in hex + if (hex.Length > 0) + hex.Length--; + + return $"{hex} | {ascii}"; + } + + + + public static string ToHex(int value) + { + return $"0x{(byte)value:X2}"; + } + + public static byte[] IntToBytesBE(int value, int byteCount) + { + var result = new byte[byteCount]; + + for (int i = 0; i < byteCount; i++) + result[byteCount - 1 - i] = (byte)(value >> (8 * i)); + + return result; + } + + public static byte[] IntToBytesLE(int value, int byteCount) + { + var result = new byte[byteCount]; + + for (int i = 0; i < byteCount; i++) + result[i] = (byte)(value >> (8 * i)); + + return result; + } + + public static byte[] AsciiToBytes(string text) + { + return string.IsNullOrEmpty(text) + ? Array.Empty() + : System.Text.Encoding.ASCII.GetBytes(text); + } + + /// + /// Converts a hex string to a byte array. + /// Like: string hex = "3F 76 65 72 73 3A 20 48 61 72 72 79 20 54 3A 42 38 30 30 2C 20"; + /// + /// + /// + /// + public static byte[] HexStringToByteArray(string hex) + { + if (hex == null) + throw new ArgumentNullException(nameof(hex)); + + return hex + .Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .Select(b => byte.Parse(b, NumberStyles.HexNumber, CultureInfo.InvariantCulture)) + .ToArray(); + } + + } + +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/IpelHatCommandDecoder.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/IpelHatCommandDecoder.cs new file mode 100644 index 000000000..65bed0d29 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/IpelHatCommandDecoder.cs @@ -0,0 +1,21 @@ +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger +{ + public class IpelHatCommandDecoder + { + public static string DescribeCommand(byte command) + { + return ""; + } + + public static string DescribeDirection(byte direction) + { + if (direction == IperlHatProtocol.IperlHatProtocolConstants.Write) + return "(WRITE - OUTGOING)"; + + if (direction == IperlHatProtocol.IperlHatProtocolConstants.Read) + return "(READ - INCOMING)"; + + return "INVALID CONTROL BITS (unsupported pattern)"; + } + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/IperlHatLogger.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/IperlHatLogger.cs new file mode 100644 index 000000000..63724f3ae --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/IperlHatLogger.cs @@ -0,0 +1,85 @@ +using System; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger +{ + public static class IperlHatLogger + { + public static string DescribeTx(byte[] frame) + { + if (frame == null || frame.Length < 5) + return "Invalid frame"; + + if (frame[2] == IperlHatProtocol.IperlHatProtocolConstants.Question) + { + return + "TX Frame\n" + + $" START : {HexFormatter.ToHex(frame[0])}\n" + + $" DIRECTION : {HexFormatter.ToHex(frame[1])} ({IpelHatCommandDecoder.DescribeDirection(frame[1])})\n" + + $" COMMAND : {HexFormatter.ToHexWithAscii(frame[2])}\n" + + $" INFO : {HexFormatter.ToSerialHexWithAscii(GetInformatioQuestion(frame))}\n" + + $" END : {HexFormatter.ToHex(frame[frame.Length - 1])}\n" + + $" RAW : {HexFormatter.ToHex(frame)}"; + } + else + { + return + "TX Frame\n" + + $" START : {HexFormatter.ToHex(frame[0])}\n" + + $" DIRECTION : {HexFormatter.ToHex(frame[1])} ({HexFormatter.ToHexWithAscii(frame[1])}) {IpelHatCommandDecoder.DescribeDirection(frame[1])}\n" + + $" LEN : {HexFormatter.ToHex(frame[2])} - {(int)frame[2]}\n" + + $" COMMAND : {HexFormatter.ToHexWithAscii(frame[3])}\n" + + $" INFO : {HexFormatter.ToSerialHexWithAscii(GetInformation(frame))}\n" + + $" END : {HexFormatter.ToHex(frame[frame.Length - 1])}\n" + + $" RAW : {HexFormatter.ToHex(frame)}"; + } + } + + //payload + private static byte[] GetInformation(byte[] frame) + { + int infoLength = frame.Length - 5; // START + DIRECTION + LEN + COMMAND + END + if (infoLength <= 0) + return Array.Empty(); + + var info = new byte[infoLength]; + Buffer.BlockCopy(frame, 4, info, 0, infoLength); + return info; + } + + //payload for question + private static byte[] GetInformatioQuestion(byte[] frame) + { + int infoLength = frame.Length - 4; // START + DIRECTION + COMMAND + END + if (infoLength <= 0) + return Array.Empty(); + + var info = new byte[infoLength]; + Buffer.BlockCopy(frame, 3, info, 0, infoLength); + return info; + } + + public static string DescribeRx(byte[] frame, TouchReadResponse response) + { + return + "RX Frame\n" + + $" START : {HexFormatter.ToHex(frame[0])}\n" + + $" LEN : {HexFormatter.ToHex(frame[1])} ({frame[1]})\n" + + $" CONTROL : {HexFormatter.ToHex(response.Control)}\n" + + $" STATUS : {HexFormatter.ToHex(response.Status)} ({DescribeStatus(response.Status)})\n" + + $" PAYLOAD : {HexFormatter.ToHex(response.Payload)}\n" + + $" RAW : {HexFormatter.ToHex(frame)}"; + } + + private static string DescribeStatus(byte status) + { + switch (status) + { + case 0x01: return "Command complete, no errors"; + case 0x02: return "Unable to execute"; + case 0x04: return "Unsupported control bits"; + default: return "Unknown status"; + } + } + } +} \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/hexLogger/TouchReadControlDecoder.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/TouchReadControlDecoder.cs similarity index 82% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/hexLogger/TouchReadControlDecoder.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/TouchReadControlDecoder.cs index c747e5a1b..2d2a3d0dd 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/hexLogger/TouchReadControlDecoder.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/TouchReadControlDecoder.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.hexLogger +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger { public static class TouchReadControlDecoder { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/hexLogger/TouchReadLogger.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/TouchReadLogger.cs similarity index 93% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/hexLogger/TouchReadLogger.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/TouchReadLogger.cs index 11fa0e017..372adfe55 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/hexLogger/TouchReadLogger.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/hexLogger/TouchReadLogger.cs @@ -1,6 +1,7 @@ using System; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.hexLogger +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger { public static class TouchReadLogger { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ITouchReadLedParser.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/ITouchReadLedParser.cs similarity index 62% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ITouchReadLedParser.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/ITouchReadLedParser.cs index fc8907e67..b3cac3b6e 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ITouchReadLedParser.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/ITouchReadLedParser.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.led +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.led { public interface ITouchReadLedParser { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ShortVariableLedParser.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/ShortVariableLedParser.cs similarity index 85% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ShortVariableLedParser.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/ShortVariableLedParser.cs index 0ba81be12..7947029cc 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ShortVariableLedParser.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/ShortVariableLedParser.cs @@ -1,6 +1,6 @@ using System.Globalization; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.led +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.led { public class ShortVariableLedParser : ITouchReadLedParser { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedData.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/TouchReadLedData.cs similarity index 96% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedData.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/TouchReadLedData.cs index 8064ae507..427ccf1a1 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedData.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/TouchReadLedData.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.led +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.led { /// /// Parsed data from a unidirectional TouchRead LED message. diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedMessage.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/TouchReadLedMessage.cs similarity index 88% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedMessage.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/TouchReadLedMessage.cs index 3d15579f6..abb0ef647 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedMessage.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/led/TouchReadLedMessage.cs @@ -1,6 +1,6 @@ using System; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.led +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.led { public class TouchReadLedMessage { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadCommand.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolCommand.cs similarity index 91% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadCommand.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolCommand.cs index 6ea8862fe..5b6758817 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadCommand.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolCommand.cs @@ -1,11 +1,11 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons { /// /// Common iPERL TouchRead bidirectional commands. /// These commands consist of a single-byte command code /// placed in the Information field. /// - public enum TouchReadCommand : byte + public enum ProtocolCommand : byte { /// /// Simple (legacy) commands (e.g. View Factory ID = 0x01) @@ -129,6 +129,12 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 /// Device-specific command prefix. /// Must be followed by a device sub-command byte. /// - DeviceSpecific = 0xFD + DeviceSpecific = 0xFD, + + /// + /// Question - specific switch to add additional payload request like "vers" + /// Mandatory add payload + /// + Question = 0x3F, } } \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolDeviceSubCommand.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolDeviceSubCommand.cs new file mode 100644 index 000000000..3e83e13b0 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolDeviceSubCommand.cs @@ -0,0 +1,203 @@ +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons +{ + /// + /// Device-specific TouchRead sub-commands. + /// These sub-commands are used together with the + /// (0xFD) command. + /// + public enum ProtocolDeviceSubCommand : byte + { + // ========================================================== + // System / Time + // ========================================================== + + /// + /// View system time. + /// Returns uint32 seconds since 2000-01-01 00:00:00. + /// + ViewSystemTime = 0x10, + + /// + /// Set system time. + /// Payload: uint32 seconds since 2000-01-01. + /// If set to zero, the meter resets and erases data. + /// Protected by meter seal. + /// + SetSystemTime = 0x11, + + // ========================================================== + // Alarm Mask / Alarm Configuration + // ========================================================== + + /// View alarm mask (lower 16 bits). + ViewAlarmMask = 0x31, + + /// Set alarm mask (lower 16 bits). + SetAlarmMask = 0x32, + + /// View alarm persistence period (days). + ViewPersistence = 0x33, + + /// Set alarm persistence period (days). + SetPersistence = 0x34, + + /// View leak duration (hours). + ViewLeakDuration = 0x35, + + /// Set leak duration (hours). + SetLeakDuration = 0x36, + + /// View current alarm states. + ViewAlarms = 0x37, + + /// Set alarm states (protected by meter seal). + SetAlarms = 0x38, + + // ========================================================== + // Manufacture / Counters + // ========================================================== + + /// View manufacture date. + ViewManufactureDate = 0x39, + + /// Set manufacture date (protected by meter seal). + SetManufactureDate = 0x3A, + + /// View seconds idle. + ViewSecondsIdle = 0x3B, + + /// View seconds active. + ViewSecondsActive = 0x3D, + + /// View seconds used. + ViewSecondsUsed = 0x3F, + + // ========================================================== + // Snapshot / Datalog + // ========================================================== + + /// View snapshot data. + ViewSnapshotData = 0x41, + + /// View datalog duration. + ViewDatalogDuration = 0x43, + + /// Set datalog duration. + SetDatalogDuration = 0x44, + + /// Read datalog. + ReadDatalog = 0x45, + + /// Clear datalog. + ClearDatalog = 0x46, + + // ========================================================== + // History + // ========================================================== + + /// View history mask. + ViewHistoryMask = 0x47, + + /// Set history mask. + SetHistoryMask = 0x48, + + /// Read history. + ReadHistory = 0x49, + + /// Clear history. + ClearHistory = 0x4A, + + // ========================================================== + // Diagnostics / Status + // ========================================================== + + /// View diagnostics. + ViewDiagnostics = 0x4B, + + /// Reset diagnostics. + ResetDiagnostics = 0x4C, + + /// View status file. + ViewStatusFile = 0x4F, + + /// Set status file (protected by meter seal). + SetStatusFile = 0x50, + + // ========================================================== + // Calibration / Configuration + // ========================================================== + + /// View calibration structure. + ViewCalibrationStructure = 0x51, + + /// Set calibration structure (protected by meter seal). + SetCalibrationStructure = 0x52, + + /// View calibration. + ViewCalibration = 0x53, + + /// Set calibration (protected by meter seal). + SetCalibration = 0x54, + + /// View reboot count. + ViewRebootCount = 0x55, + + /// Set reboot count (protected by meter seal). + SetRebootCount = 0x56, + + /// View temperature. + ViewTemperature = 0x57, + + /// Set temperature (protected by meter seal). + SetTemperature = 0x58, + + // ========================================================== + // Diagnostic LED / Hardware + // ========================================================== + + /// + /// Set diagnostic LED state. + /// Enables or disables high-speed LED serial output. + /// + /// See + /// diagnostic LED output modes. + /// + /// + SetDiagnosticLEDState = 0x60, + + + // ========================================================== + // Build / Firmware Info + // ========================================================== + + /// View iPERL build information. + ViewIPerlBuild = 0x65, + + /// Set iPERL build (protected by meter seal). + SetIPerlBuild = 0x66, + + // ========================================================== + // Bootloader (DANGEROUS – use with care) + // ========================================================== + + /// Enter bootloader mode. + EnterBootloader = 0x81, + + /// Read FLASH memory. + ReadFlash = 0x82, + + /// Erase all FLASH memory. + EraseAll = 0x83, + + /// Erase FLASH segment. + EraseSegment = 0x84, + + /// Update firmware code. + UpdateCode = 0x85, + + /// Exit bootloader mode. + ExitBootloader = 0x86 + } +} diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolStatuses.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolStatuses.cs new file mode 100644 index 000000000..e4c014548 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ProtocolStatuses.cs @@ -0,0 +1,13 @@ +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons +{ + public enum ProtocolStatuses : byte + { + Idle = 0x01, + Active = 0x02, + EndOfLife = 0x03, + MeterTest = 0x04, + MeterTestEMF = 0x05, + + Unknown = 0x00 + } +} \ No newline at end of file diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrame.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrame.cs similarity index 88% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrame.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrame.cs index 1b9fb04f9..00c1afaf8 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrame.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrame.cs @@ -1,6 +1,6 @@ using System; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol { public sealed class TouchReadFrame { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameBuilder.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrameBuilder.cs similarity index 73% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameBuilder.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrameBuilder.cs index dbe7ebb47..ed3827970 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameBuilder.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrameBuilder.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol { public sealed class TouchReadFrameBuilder { @@ -15,16 +17,16 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 return this; } - public TouchReadFrameBuilder AddCommand(TouchReadCommand command) + public TouchReadFrameBuilder AddCommand(ProtocolCommand command) { _information.Add((byte)command); return this; } - public TouchReadFrameBuilder AddSubCommand(TouchReadDeviceSubCommand subCommand) + public TouchReadFrameBuilder AddSubCommand(ProtocolDeviceSubCommand subCommand) { if (_information.Count == 0 || - _information[0] != (byte)TouchReadCommand.DeviceSpecific) + _information[0] != (byte)ProtocolCommand.DeviceSpecific) throw new InvalidOperationException( "Sub-command is only valid for DeviceSpecific (0xFD) commands."); @@ -33,9 +35,9 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 } public TouchReadFrameBuilder AddDeviceCommand( - TouchReadDeviceSubCommand subCommand) + ProtocolDeviceSubCommand subCommand) { - _information.Add((byte)TouchReadCommand.DeviceSpecific); + _information.Add((byte)ProtocolCommand.DeviceSpecific); _information.Add((byte)subCommand); return this; } @@ -47,6 +49,14 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 return this; } + + public TouchReadFrameBuilder AddDiagnosticLedState(DiagnosticLedState state) + { + _information.Add((byte)ProtocolCommand.DeviceSpecific); + _information.Add((byte)ProtocolDeviceSubCommand.SetDiagnosticLEDState); + _information.Add((byte)state); + return this; + } public TouchReadFrameBuilder AddNullTerminatedAscii(string text) { @@ -104,7 +114,7 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 return bytes.ToArray(); } - private static ushort CalculateChecksum(IEnumerable data) + public static ushort CalculateChecksum(IEnumerable data) { ushort sum = 0; foreach (var b in data) diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameParser.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrameParser.cs similarity index 95% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameParser.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrameParser.cs index 0755a2f22..e11ec1d6d 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameParser.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadFrameParser.cs @@ -1,6 +1,6 @@ using System; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol { public sealed class TouchReadFrameParser { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadProtocol.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadProtocol.cs similarity index 69% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadProtocol.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadProtocol.cs index 9200decb9..2c44f4a09 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadProtocol.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadProtocol.cs @@ -1,4 +1,4 @@ -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol { public static class TouchReadProtocol { diff --git a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadResponse.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadResponse.cs similarity index 90% rename from TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadResponse.cs rename to TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadResponse.cs index c58d08dc7..20e12f26a 100644 --- a/TBF/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadResponse.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/wiredProtocol/TouchReadResponse.cs @@ -1,6 +1,6 @@ using System; -namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4 +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol { public sealed class TouchReadResponse { diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/OpthoHeadService.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/OpthoHeadService.cs new file mode 100644 index 000000000..08372dd45 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/OpthoHeadService.cs @@ -0,0 +1,10 @@ +using log4net; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication +{ + public class OpthoHeadService + { + + + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/OptoHeadTest.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/OptoHeadTest.cs new file mode 100644 index 000000000..2d33dc278 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/OptoHeadTest.cs @@ -0,0 +1,369 @@ +using System; +using System.IO.Ports; +using Common; +using log4net; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils; +using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication +{ + public class OptoHeadTest : IDisposable + { + //protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); + private static readonly ILog log = LogManager.GetLogger(typeof(OptoHeadTest)); + + private IperlHead iperlHead; + private SerialDriver serialDriver; + + public static SerialDriver BuildConnection(IperlHead iHead) + { + return new SerialDriverBuilder() + .WithPort($"COM{iHead.RfidComPortNr}") + .WithBaudRate(2400) + .WithDataBits(8) + .WithParity(Parity.None) + .WithStopBits(StopBits.One) + .WithTimeouts(4000, 2000) + .BuildAndConnect(); + + } + + public OptoHeadTest(IperlHead iperlHead) + { + this.iperlHead = iperlHead; + } + + public void CloseConnection() + { + if (serialDriver != null) + serialDriver.CloseConnection(); + serialDriver = null; + } + + public bool ReadSerialNr() + { + try + { + if (iperlHead != null) + { + if (serialDriver == null) + serialDriver = BuildConnection(iperlHead); + + log.Debug("ReadSerialNr called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver); + RadioService headService = new RadioService(serialDriver); + string serialNo = headService.ReadRequest_PCB(ref iperlHead); + if (!string.IsNullOrEmpty(serialNo)) + { + log.Info($"Success Serial No: {serialNo} on COM{iperlHead.RfidComPortNr} serialDriver: {serialDriver}"); + return true; + } + } + } + catch (Exception ex) + { + log.Error($"ReadSerialNr(COM{iperlHead.RfidComPortNr}) - Exception:" + ex.Message); + } + + return false; + } + + public string ReadRequest_PCB() + { + if (iperlHead.DebugLevel == DebugMode.Simulate) + { + return "-OK Simulated response-"; + } + + try + { + if (iperlHead != null) + { + if (serialDriver == null) + serialDriver = BuildConnection(iperlHead); + + RadioService headService = new RadioService(serialDriver); + string serialNo = headService.ReadRequest_PCB(ref iperlHead); + log.Info($"PCB Number: {serialNo} on COM{iperlHead.RfidComPortNr} serialDriver: {serialDriver}"); + return serialNo; + } + } + catch (Exception ex) + { + log.Error("ReadRequest_PCB() - Exception:" + ex.StackTrace); + return (ex.Message.ToString()); + } + + return ""; + } + + /// + /// Set Test mode + /// + /// + /// + public bool SetTestMode() + { + log.Debug("SetTestMode called for iHead: " + iperlHead.ToString()); + bool activityModeActive = SetActivityMode_Active(); + bool optActiveMode = SetOptTestMode(); + + log.Debug("SetTestMode result: optoMod-> " + optActiveMode + " meterModeActive ->" + activityModeActive); + return (optActiveMode && activityModeActive); + } + + /// + /// Set Active mode + /// + /// + /// + public bool SetActiveMode() + { + log.Debug("SetActiveMode called for iHead: " + iperlHead.ToString()); + bool optActiveMode = SetOptActiveMode(iperlHead); + //bool activityModeIdle = SetActivityMode_Idle(); + + return optActiveMode; + } + + /// + /// Set Idle mode - only + /// + /// + /// + public bool SetIdleMode() + { + log.Debug("SetIdleMode called for iHead: " + iperlHead.ToString()); + bool activityModeIdle = SetActivityMode_Idle(); + + return activityModeIdle; + } + + /// + /// Set Test mode - string response + /// + /// + /// + /// + public string SetTestMode(ref bool isTestModeSuccessful) + { + if (iperlHead.DebugLevel == DebugMode.Simulate) + { + isTestModeSuccessful = true; + return "-OK Simulated response-"; + } + + try + { + bool testMode = SetTestMode(); + isTestModeSuccessful = testMode; + return testMode ? "Set Test Mode - OK" : "Set Test Mode - FAILED"; + }catch (Exception ex) + { + log.Error("SetTestMode() - Exception:" + ex.StackTrace); + return "Set Test Mode - Exception"; + } + } + + + + /// + /// Set Optical -> Test mode + /// + /// + /// + /// + private bool SetOptTestMode() + { + try + { + if (iperlHead != null) + { + if (serialDriver == null) + serialDriver = BuildConnection(iperlHead); + + RadioService headService = new RadioService(serialDriver); + bool optTestMode = headService.SetOptTestMode(iperlHead); + if (iperlHead.ConfigStruct != null) + iperlHead.ConfigStruct.OpthoStatusMode = optTestMode ? DiagnosticLedState.State4 : DiagnosticLedState.StatusUnknown; + return optTestMode; + } + } + catch (Exception ex) + { + log.Error("SetOptTestMode() - Exception:" + ex.StackTrace); + } + return false; + } + + /// + /// Set Active mode - string response + /// + /// + /// + /// + public string SetActiveMode(ref bool isTestModeSuccessful) + { + if (iperlHead.DebugLevel == DebugMode.Simulate) + { + isTestModeSuccessful = true; + return "-OK Simulated response-"; + } + + try + { + bool activeMode = SetActiveMode(); + isTestModeSuccessful = activeMode; + return activeMode ? "Set Active Mode - OK" : "Set Active Mode - FAILED"; + } + catch (Exception ex) + { + log.Error("SetActiveMode() - Exception:" + ex.StackTrace); + return "Set Active Mode - Exception"; + } + } + /// + /// Set Optical -> Active mode + /// + /// + /// + /// + private bool SetOptActiveMode(IperlHead iHead) + { + try + { + if (iHead != null) + { + if (serialDriver == null) + serialDriver = BuildConnection(iHead); + + RadioService headService = new RadioService(serialDriver); + return headService.SetOptActiveMode(iHead); + } + } + catch (Exception ex) + { + log.Error("SetOptActiveMode() - Exception:" + ex.StackTrace); + } + + return false; + } + + /// + /// Set activity mode to active + /// + /// + /// + /// + private bool SetActivityMode_Active() + { + try + { + if (iperlHead != null) + { + if (serialDriver == null) + serialDriver = BuildConnection(iperlHead); + + log.Debug("SetActivityMode_Active called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver); + RadioService headService = new RadioService(serialDriver); + return headService.SetActivityMode_Active(iperlHead); + } + } + catch (Exception ex) + { + log.Error("SetActivityMode_Active() - Exception:" + ex.StackTrace); + } + + return false; + } + + /// + /// Set activity mode to idle + /// + /// + /// + /// + private bool SetActivityMode_Idle() + { + try + { + if (iperlHead != null) + { + if (serialDriver == null) + serialDriver = BuildConnection(iperlHead); + + log.Debug("SetActivityMode_Idle called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver); + + RadioService headService = new RadioService(serialDriver); + return headService.SetActivityMode_Idle(iperlHead); + } + } + catch (Exception ex) + { + log.Error("SetActivityMode_Idle() - Exception:" + ex.StackTrace); + } + + return false; + } + + + public void Dispose() + { + CloseConnection(); + } + + /// + /// Read configuration from iHead + /// DiagnosticLedState is not readable, mus only be set! + /// + /// + /// + /// + public bool ReadConfiguration(DiagnosticLedState ledState ) + { + if (iperlHead.DebugLevel == DebugMode.Simulate) + { + return true; + } + + try + { + + if (iperlHead != null) + { + iperlHead.ConfigStruct = new ConfigStruct(); + + if (serialDriver == null) + serialDriver = BuildConnection(iperlHead); + + RadioService headService = new RadioService(serialDriver); + iperlHead.ConfigStruct.PCBNumberString = headService.ReadRequest_PCB(ref iperlHead); + iperlHead.ConfigStruct.StatusMode = headService.GetActivityStatusMode(iperlHead); + iperlHead.ConfigStruct.Unit = headService.GetUnit(iperlHead); + + if (ledState != DiagnosticLedState.StatusUnknown) // do set + { + iperlHead.ConfigStruct.OpthoStatusMode = headService.SetOptoStatusMode(iperlHead, ledState); + } + else + { + iperlHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StatusUnknown; + } + + iperlHead.ConfigStruct.Version = headService.GetVersion(iperlHead); + + return true; + } + + else + { + return false; + } + } + catch (Exception ex) + { + return false; + } + } + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs new file mode 100644 index 000000000..7a17fbf16 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs @@ -0,0 +1,318 @@ +using log4net; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; +using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils; +using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication +{ + public class RadioService + { + private static readonly ILog log = LogManager.GetLogger(typeof(RadioService)); + + static string okResponse = "Command complete, no errors"; + static string errorResponse = "Unable to execute"; + + private ISerialDriver serialDriver; + public RadioService(SerialDriver serialDriver) + { + this.serialDriver = serialDriver; + log.Debug("RadioService created with serialDriver= " + serialDriver + ""); + } + + public RadioService(ISerialDriver serialDriver) + { + this.serialDriver = serialDriver; + log.Debug("RadioService created with serialDriver= " + serialDriver + ""); + } + + public string ReadRequest_PCB(ref IperlHead iHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + var request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.ViewFactoryId) + .BuildBytes(); + + + byte[] rawData = serialDriver.SendAndWait(request, 10000); + if (rawData == null) + return null; + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + if (decoded.IsOk) + { + string asciiPayload = decoded.GetAsciiPayload(); + if (iHead.ConfigStruct != null) // store mechanism + { + iHead.ConfigStruct.PCBNumberString = asciiPayload; + } + return asciiPayload; + } + + return null; + } + + public ProtocolStatuses GetActivityStatusMode(IperlHead iHead) + { + if (!serialDriver.IsOpen()) + serialDriver.Open(); + + var request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.ViewState) + .BuildBytes(); + + byte[] rawData = serialDriver.SendAndWait(request, 10000); + if (rawData == null) + return ProtocolStatuses.Unknown; + + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + + if (!decoded.IsOk) + return ProtocolStatuses.Unknown; + + ProtocolStatuses statusMode = decoded.GetResponse(out bool isOK); + + if (!isOK) + return ProtocolStatuses.Unknown; // wrong payload + + return statusMode; + } + + public DiagnosticLedState SetOptoStatusMode(IperlHead iHead, DiagnosticLedState opthoStatusMode) + { + if (!serialDriver.IsOpen()) + serialDriver.Open(); + + var request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState) + .AddPayload(opthoStatusMode) + .BuildBytes(); + + byte[] rawData = serialDriver.SendAndWait(request, 10000); + if (rawData == null) + return DiagnosticLedState.StatusUnknown; + + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + + log.Debug("SetOptoStatusMode isOK: " + decoded.IsOk); + // if is response ok - it set it correctly + if (!decoded.IsOk) + return DiagnosticLedState.StatusUnknown; + + return opthoStatusMode; + } + + + private static ushort SafeIntToUShort(int value) + { + if (value < ushort.MinValue || value > ushort.MaxValue) + return 0xFD; // your error code + + return (ushort)value; + } + + + public string GetVersion(IperlHead iHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.Question) + .AddPayload(IperlHatProtocolConstants.Version) + .BuildBytes(); + + + byte[] rawData = serialDriver.SendAndWait(request, 10000); + if (rawData == null) + return ""; + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + log.Debug("GetVersion isOK: " + decoded.IsOk); + if (decoded.IsOk) + { + return decoded.GetAsciiPayload(); + } + + return ""; + } + + + public bool SetActivityMode_Active(IperlHead iHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + //Set LED to state 4 + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.SetState) + .AddSubCommand(ProtocolStatuses.Active) // Active + .BuildBytes(); + + byte[] rawData = serialDriver.SendAndWait(request, 5000); + if (rawData == null) + return false; + + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + log.Debug("SetActivityMode_Active isOK: " + decoded.IsOk); + if (decoded.IsOk && iHead.ConfigStruct != null) + { + iHead.ConfigStruct.StatusMode = ProtocolStatuses.Active; + } + return decoded.IsOk; + } + + public bool SetActivityMode_Idle(IperlHead iHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + //Set Activity State Idle + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.SetState) + .AddSubCommand(ProtocolStatuses.Idle) + .BuildBytes(); + + byte[] rawData = serialDriver.SendAndWait(request, 5000); + if (rawData == null) + return false; + + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + log.Debug("SetActivityMode_Idle isOK: " + decoded.IsOk); + if (decoded.IsOk && iHead.ConfigStruct != null) + { + iHead.ConfigStruct.StatusMode = ProtocolStatuses.Idle; + } + return decoded.IsOk; + } + + public bool SetOptTestMode(IperlHead iHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + //Set LED to state 4 + var request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState) + .AddPayload(DiagnosticLedState.State4) + .BuildBytes(); + + byte[] rawData = serialDriver.SendAndWait(request, 5000); + if (rawData == null) + return false; + + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + bool isOk = decoded.IsOk; + log.Debug("SetOptTestMode isOK: " + isOk); + if (decoded.IsOk && iHead.ConfigStruct != null) + { + iHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.State4; + } + return isOk; + + } + + /// + /// stop data streaming by LED + /// + /// + /// + public bool SetOptActiveMode(IperlHead iHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + //Set LED to state 1 + var request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState) + .AddPayload(DiagnosticLedState.StateOFF) + .BuildBytes(); + + byte[] rawData = serialDriver.SendAndWait(request, 5000); + if (rawData == null) + return false; + + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + log.Debug("SetOptActiveMode isOK: " + decoded.IsOk); + if (decoded.IsOk && iHead.ConfigStruct != null) + { + iHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StateOFF; + } + return decoded.IsOk; + } + + public string GetUnit(IperlHead iperlHead) + { + if (!serialDriver.IsOpen()) + { + serialDriver.Open(); + } + + var request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.ViewFactoryId) + .BuildBytes(); + + + byte[] rawData = serialDriver.SendAndWait(request, 10000); + if (rawData == null) + return null; + + // parse rawData + var parser = new IperlHatFrameParser(); + IperlHatResponse decoded = parser.Parse(rawData); + if (decoded.IsOk) + { + string asciiPayload = decoded.GetAsciiPayload(); + if (iperlHead.ConfigStruct != null) // store mechanism + { + iperlHead.ConfigStruct.Unit = asciiPayload; + } + return asciiPayload; + } + + return null; + } + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/ISerialDriver.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/ISerialDriver.cs new file mode 100644 index 000000000..e75c5c0f9 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/ISerialDriver.cs @@ -0,0 +1,9 @@ +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils +{ + public interface ISerialDriver + { + bool IsOpen(); + bool Open(); + byte[] SendAndWait(byte[] request, int timeout); + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs new file mode 100644 index 000000000..c08d803a5 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Ports; +using System.Threading; +using FluentNHibernate.Conventions; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils +{ + public class SerialDriver : IDisposable, ISerialDriver + { + readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(SerialDriver)); + public string ErrorMessage { get; private set; } + private List SerialPortReadBuffer = new List(); + + private SerialPort _serialPort; + private readonly List _binMessages = new List(); + private bool _isReading; + + // Stored configuration (used by Builder) + private readonly string _portName; + private readonly int _baudRate; + private readonly int _dataBits; + private readonly Parity _parity; + private readonly StopBits _stopBits; + private readonly int _readTimeout; + private readonly int _writeTimeout; + + private readonly ManualResetEvent _responseReceived = new ManualResetEvent(false); + + #region Constructors + + // Default constructor (legacy support) + public SerialDriver() + { + _serialPort = new SerialPort(); + } + + // Builder constructor + internal SerialDriver( + string portName, + int baudRate, + int dataBits, + Parity parity, + StopBits stopBits, + int readTimeout, + int writeTimeout) + { + _portName = portName; + _baudRate = baudRate; + _dataBits = dataBits; + _parity = parity; + _stopBits = stopBits; + _readTimeout = readTimeout; + _writeTimeout = writeTimeout; + } + + #endregion + + #region Open / Close + + // Builder-based open + public bool Open() + { + return OpenConnection( + _portName, + _baudRate, + _dataBits, + _parity, + _stopBits, + _readTimeout, + _writeTimeout + ); + } + + // Legacy API (unchanged) + public bool OpenConnection( + string comPort, + int baudrate, + int dataBits, + Parity parity, + StopBits stopbits, + int readTimeout = 1000, + int writeTimeout = 1000) + { + lock (this) + { + CloseConnection(); + + try + { + ErrorMessage = string.Empty; + + _serialPort = new SerialPort(comPort, baudrate, parity, dataBits, stopbits) + { + ReadTimeout = readTimeout, + WriteTimeout = writeTimeout + }; + + _serialPort.DataReceived += DataReceivedHandler; + _serialPort.Open(); + } + catch (Exception ex) + { + ErrorMessage = $"COM error: Open failed {comPort}. {ex.Message}"; + return false; + } + + if (!_serialPort.IsOpen) + { + ErrorMessage = $"COM error: Can't open {comPort}."; + return false; + } + + log.Debug("SerialDriver opened successfully for port: " + comPort); + } + return true; + } + + public void CloseConnection() + { + if (_serialPort != null) + { + _serialPort.DataReceived -= DataReceivedHandler; + if (_serialPort.IsOpen) + _serialPort.Close(); + + _serialPort.Dispose(); + _serialPort = null; + } + } + + public bool IsOpen() => _serialPort?.IsOpen == true; + + #endregion + + #region Send / Receive + + public bool SendMessage(byte[] sendDataBytes, int length, int readTimeout = 1000, int writeTimeout = 1000) + { + if (!IsOpen()) return false; + if (sendDataBytes.Length == 0) return true; + + try + { + PrepareReading(); + + _serialPort.WriteTimeout = writeTimeout; + _serialPort.ReadTimeout = readTimeout; + _serialPort.Write(sendDataBytes, 0, length); + + _isReading = true; + + var stopwatch = Stopwatch.StartNew(); + while (_isReading) + { + if (stopwatch.ElapsedMilliseconds > readTimeout) + { + ErrorMessage = "COM error: Receive timeout"; + return false; + } + } + } + catch (Exception ex) + { + ErrorMessage = $"COM error: Transmit failed {_serialPort.PortName}. {ex.Message}"; + return false; + } + + return true; + } + + private void PrepareReading() + { + _serialPort.DiscardInBuffer(); + _binMessages.Clear(); + _responseReceived.Reset(); + SerialPortReadBuffer.Clear(); + _isReading = true; + } + + public byte[] GetRawData() + { + return _binMessages.ToArray(); + } + + private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) + { + lock (this) + { + if (_serialPort == null || !_serialPort.IsOpen) return; + + try + { + //Thread.Sleep(5); + + if (!SerialPortReadBuffer.IsEmpty()) + { + SerialPortReadBuffer.Clear(); + } + + int iWordCounter = 0; + bool isStart = false; + bool isQuestion = false; + int iLength = 0; + while (true)//_serialPort.BytesToRead > 0 + { + byte readByte = (byte)_serialPort.ReadByte(); + + //I have START + if (readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.Start) + { + iWordCounter++; + isStart = true; + } + // I have QUESTION + if (readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.Question) + { + iWordCounter++; + isQuestion = true; + } + //I count length from start + if (iWordCounter > 0) + iWordCounter++; + + if (iWordCounter > 0) + { + //Store byte to data + SerialPortReadBuffer.Add(readByte); + } + // we have length + if (iLength == 0 && isStart && SerialPortReadBuffer.Count > 2 ) + { + iLength = (int)SerialPortReadBuffer[2]; + } + + //If we have enough bytes + if (isStart && iLength > 0 + && (SerialPortReadBuffer.Count >= iLength || + readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.End + ) + ) + { + break; + } + //if we read END + if (isQuestion && readByte == C4.IperlHatProtocol.IperlHatProtocolConstants.End) + { + break; + } + } + + if (SerialPortReadBuffer.Count > 0) + { + _binMessages.AddRange(SerialPortReadBuffer.ToArray()); + _responseReceived.Set(); + } + } + catch (TimeoutException te) + { + // Ignore shutdown race conditions + } + finally + { + _isReading = false; + } + } + } + + public byte[] SendAndWait(byte[] data, int timeoutMs) + { + if (!IsOpen()) + throw new InvalidOperationException("Serial port not open"); + + log.Debug("SendAndWait() - TX: " + HexFormatter.ToHex(data)); + PrepareReading(); + _serialPort.Write(data, 0, data.Length); + + if (!_responseReceived.WaitOne(timeoutMs)) + { + log.Error("SendAndWait() - Response timeout! Details: " + + " SerialPortReadBuffer: " + HexFormatter.ToHex(SerialPortReadBuffer.ToArray()) + + " _binMessages" + HexFormatter.ToHex(_binMessages.ToArray()) + + "_responseReceived: " + _responseReceived.WaitOne(0) + ); + + ErrorMessage = "COM error: response timeout"; + return null; + } + + return GetRawData(); + } + + + #endregion + + public void Dispose() + { + CloseConnection(); + } + + public override string ToString() + { + return "SerialDriver: " + _serialPort.PortName + " (opened status:" + _serialPort.IsOpen +")"; + } + } +} diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriverBuilder.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriverBuilder.cs new file mode 100644 index 000000000..3e9c9aa00 --- /dev/null +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriverBuilder.cs @@ -0,0 +1,82 @@ +using System; +using System.IO.Ports; + +namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils +{ + public class SerialDriverBuilder + { + private string _portName; + private int _baudRate = 9600; + private int _dataBits = 8; + private Parity _parity = Parity.None; + private StopBits _stopBits = StopBits.One; + private int _readTimeout = 1000; + private int _writeTimeout = 1000; + + public SerialDriverBuilder WithPort(string portName) + { + _portName = portName; + return this; + } + + public SerialDriverBuilder WithBaudRate(int baudRate) + { + _baudRate = baudRate; + return this; + } + + public SerialDriverBuilder WithDataBits(int dataBits) + { + _dataBits = dataBits; + return this; + } + + public SerialDriverBuilder WithParity(Parity parity) + { + _parity = parity; + return this; + } + + public SerialDriverBuilder WithStopBits(StopBits stopBits) + { + _stopBits = stopBits; + return this; + } + + public SerialDriverBuilder WithTimeouts(int readTimeout, int writeTimeout) + { + _readTimeout = readTimeout; + _writeTimeout = writeTimeout; + return this; + } + + /// + /// Build driver WITHOUT opening connection + /// + public SerialDriver Build() + { + return new SerialDriver( + _portName, + _baudRate, + _dataBits, + _parity, + _stopBits, + _readTimeout, + _writeTimeout + ); + } + + /// + /// Build driver AND open connection + /// + public SerialDriver BuildAndConnect() + { + var driver = Build(); + if (!driver.Open()) + { + throw new InvalidOperationException(driver.ErrorMessage); + } + return driver; + } + } +} \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs similarity index 68% rename from TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.cs rename to TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs index c1d2f592e..767dc30e9 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs @@ -20,6 +20,9 @@ using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; using Results.Entities; using static Sensus.iPerl.NfcHandler.MCI_Protocol; using System.Threading.Tasks; +using TBF.Rig.TestMethods.iPerlCommunication.communication; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; namespace TBF.Rig.TestMethods.iPerlCommunication { @@ -48,9 +51,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication } - public partial class iPerlCommunicationFormTestMethod : Form, GenericDevices.IHasCompleted + public partial class iPerlCommunicationForm : Form, GenericDevices.IHasCompleted { - private static readonly ILog log = LogManager.GetLogger(typeof(iPerlCommunicationFormTestMethod)); + private static readonly ILog log = LogManager.GetLogger(typeof(iPerlCommunicationForm)); protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); const int Hz2CorrFactorsAddr = 0x1875; /// Used by Reset2HzCorrection(...) and Write2HzCorrection(...) @@ -61,6 +64,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication 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"; @@ -112,21 +117,22 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Value returned by readRequestPort(...) public static int ReadRequestPort(IperlHead iperlHead, MessageID messageID, StructName structName, int offset, int length, out byte[] buffer) { - Thread.Sleep(Math.Max(250, CfgIPerl.DelayBetweenRetries)); + Thread.Sleep(Math.Max(250, cfg.DelayBetweenRetries)); if (iperlHead.DebugLevel == DebugMode.FailureDuringOperation) iperlHead.DebugLevel = DebugMode.Normal; if (iperlHead.DebugLevel != DebugMode.Normal) // Simulation { - return SimulationServices.ReadRequest(CfgIPerl, iperlHead, messageID, offset, length, out buffer); + throw new Exception("ReadRequestPort() is not supported in simulation mode."); + //return SimulationServices.ReadRequest(cfg, iperlHead, messageID, offset, length, out buffer); } - if (iperlHead.CommInterface == CommunicationInterface.NFC.ToDescription()) // NFC Interface + if (iperlHead.CommInterface == CommunicationInterface.NFC) // NFC Interface { - return NfcServices.ReadRequest(CfgIPerl, iperlHead, structName, offset, length, out buffer); + return NfcServices.ReadRequest(cfg, iperlHead, structName, offset, length, out buffer); } else // RFID Interface { - return RfidServices.ReadRequest(CfgIPerl, iperlHead, messageID, offset, length, out buffer); + return RfidServices.ReadRequest(cfg, iperlHead, messageID, offset, length, out buffer); } } @@ -137,21 +143,21 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Value returned by writeRequestPort(...) public static int WriteRequestPort(IperlHead iperlHead, MessageID messageID, StructName structName, int offset, int length, byte[] buffer) { - Thread.Sleep(Math.Max(250, CfgIPerl.DelayBetweenRetries)); + Thread.Sleep(Math.Max(250, cfg.DelayBetweenRetries)); if (iperlHead.DebugLevel == DebugMode.FailureDuringOperation) iperlHead.DebugLevel = DebugMode.Normal; if (iperlHead.DebugLevel != DebugMode.Normal) // Simulation { - return SimulationServices.WriteRequest(CfgIPerl, iperlHead, messageID, offset, length, buffer); + return SimulationServices.WriteRequest(cfg, iperlHead, messageID, offset, length, buffer); } - if (iperlHead.CommInterface == CommunicationInterface.NFC.ToDescription()) // NFC Interface + if (iperlHead.CommInterface == CommunicationInterface.NFC) // NFC Interface { - return NfcServices.WriteRequest(CfgIPerl, iperlHead, structName, offset, length, buffer); + return NfcServices.WriteRequest(cfg, iperlHead, structName, offset, length, buffer); } else // RFID Interface { - return RfidServices.WriteRequest(CfgIPerl, iperlHead, messageID, offset, length, buffer); + return RfidServices.WriteRequest(cfg, iperlHead, messageID, offset, length, buffer); } } #endregion iPerl_Head_RFID_Interface: ReadRequestPort, WriteRequestPort @@ -192,7 +198,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// RFID multiplexer PCB / RFID serial port and worker thread related variables /// static TestMethod testMethod; - public static TestMethodCfg_IPerl CfgIPerl; + public static TestMethodCfg cfg; static IList tests; static IList multiTestParams; @@ -208,22 +214,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Parameterless constructor (without watermeters, threads) - public iPerlCommunicationFormTestMethod() + public iPerlCommunicationForm() { InitializeComponent(); - - this.Icon = Properties.Resources.TBF_icon; - } /// /// Constructor for checkBox states (active/inactive iPerl head) editing. /// /// Initial check box states - public iPerlCommunicationFormTestMethod(bool isCheckBoxesEditMode) + public iPerlCommunicationForm(bool isCheckBoxesEditMode) : this() { - iPerlCommunicationFormTestMethod.CfgIPerl = new TestMethodCfg_IPerl(null); // default iPerl Head communication params + iPerlCommunicationForm.cfg = new TestMethodCfg(null); // default iPerl Head communication params if (isCheckBoxesEditMode) { checkBoxesEditMode = true; @@ -255,7 +258,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Constructor for one iPerlCommunication 'test' /// /// Number of text boxes for serial numbers - public iPerlCommunicationFormTestMethod(TestMethod testMethod, Test test, iPerlCommunicationParams testParams) + public iPerlCommunicationForm(TestMethod testMethod, Test test, iPerlCommunicationParams testParams) : this(testMethod, new List { test }, new List { testParams }) { } @@ -264,15 +267,15 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Constructor for multiple iPerlCommunication 'tests' /// /// Number of text boxes for serial numbers - public iPerlCommunicationFormTestMethod(TestMethod testMethod, IList tests, IList multiTestParams) + public iPerlCommunicationForm(TestMethod testMethod, IList tests, IList multiTestParams) : this() { checkBoxesEditMode = false; - iPerlCommunicationFormTestMethod.testMethod = testMethod; - iPerlCommunicationFormTestMethod.CfgIPerl = testMethod.Cfg as TestMethodCfg_IPerl; - iPerlCommunicationFormTestMethod.tests = tests; - iPerlCommunicationFormTestMethod.multiTestParams = multiTestParams; + iPerlCommunicationForm.testMethod = testMethod; + iPerlCommunicationForm.cfg = testMethod.Cfg as TestMethodCfg; + iPerlCommunicationForm.tests = tests; + iPerlCommunicationForm.multiTestParams = multiTestParams; if (multiTestParams.Count > 0) { @@ -350,13 +353,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// group numbers are >=1, lastGroup == 0 means there is no group lastGroup = 0; - foreach (var iPerl in iPerlCommunicationFormTestMethod.iperlHeads) + foreach (var iPerl in iPerlCommunicationForm.iperlHeads) { if (iPerl.Group > lastGroup) lastGroup = iPerl.Group; } workerThreads = new List(); - for (int i = 0; i < CfgIPerl.NrThreads; i++) + for (int i = 0; i < cfg.NrThreads; i++) { Thread thread = new Thread(Worker); thread.CurrentCulture = CultureInfo.CurrentCulture; @@ -365,7 +368,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication } muxBrdOrGroup14Nrs = new List(); - foreach (var iPerl in iPerlCommunicationFormTestMethod.iperlHeads) + foreach (var iPerl in iPerlCommunicationForm.iperlHeads) { if (!muxBrdOrGroup14Nrs.Contains(iPerl.MuxBoardNrOrGroup14)) muxBrdOrGroup14Nrs.Add(iPerl.MuxBoardNrOrGroup14); } @@ -674,7 +677,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication #if TURA_SPECIAL int threadIx = threadID; /// Just one thread for TURA_SPECIAL #else - for (int threadIx = threadID; threadIx < threadID + 4; threadIx += CfgIPerl.NrThreads) + for (int threadIx = threadID; threadIx < threadID + 4; threadIx += cfg.NrThreads) #endif { bool wmFound = false; @@ -707,48 +710,15 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// if ((ihead == null) || ihead.Disabled || !ckbState[wmNr0]) error = CommErr.HeadDisabledByUser; #if IPERL + 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(ReadConfigurationStr.ToLower())) error = ReadConfiguration(ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == ReadCalibrationStr.ToLower()) error = ReadCalibration(ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == ReadCalibrationV4Str.ToLower()) error = ReadCalibrationV4(ihead, wm, ref resultStr); - else if (currentActivity.ToLower().Contains(WriteCalibrationFactorStr.ToLower())) error = WriteCalibrationFactor(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower().Contains(WriteCalibrationV4FactorsStr.ToLower())) error = WriteCalibrationV4Factors(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == NormalizeCalibrationFactorStr.ToLower()) error = NormalizeCalibrationFactor(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == NormalizeCalibrationV4FactorsStr.ToLower()) error = NormalizeCalibrationV4Factors(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == ReadQ2CorrectionStr.ToLower()) error = ReadQ2Correction(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == ResetQ2CorrectionStr.ToLower()) error = ResetQ2Correction(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == WriteDefaultQ2CorrectionsStr.ToLower()) error = WriteDefaultQ2Corrections(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == InitOrReadQ2CorrectionsStr.ToLower()) error = InitOrReadQ2Corrections(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == WriteQ2CorrectionStr.ToLower()) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Standard, null); - else if (currentActivity.ToLower() == WriteQ2CorrectionAltStr.ToLower()) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Dewa, null); - else if (currentActivity.ToLower().Contains(WriteQ2CorrectionGreeceStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Greece, currentActivity.Substring(WriteQ2CorrectionGreeceStr.Length).Trim()); - else if (currentActivity.ToLower().Contains(WriteQ2CorrectionRLStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.RL, currentActivity.Substring(WriteQ2CorrectionRLStr.Length).Trim()); - else if (currentActivity.ToLower().Contains(WriteQ2CorrectionLRStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.LR, currentActivity.Substring(WriteQ2CorrectionLRStr.Length).Trim()); - else if (currentActivity.ToLower() == WriteQ2CorrectionIncl05Str.ToLower()) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Standard_incl_05, null); - else if (currentActivity.ToLower() == WriteQ2CorrectionPlusIncl05Str.ToLower()) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Standard_plus_incl_05, null); - else if (currentActivity.ToLower() == WriteQ2CorrectionAltIncl05Str.ToLower()) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Dewa_incl_05, null); - else if (currentActivity.ToLower() == WriteQ2CorrectionPlusAltIncl05Str.ToLower()) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Dewa_plus_incl_05, null); - else if (currentActivity.ToLower().Contains(WriteQ2CorrectionGreeceIncl05Str.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Greece_incl_05, currentActivity.Substring(WriteQ2CorrectionGreeceIncl05Str.Length).Trim()); - else if (currentActivity.ToLower().Contains(WriteQ2CorrectionRLIncl05Str.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.RL_incl_05, currentActivity.Substring(WriteQ2CorrectionRLIncl05Str.Length).Trim()); - else if (currentActivity.ToLower().Contains(WriteQ2CorrectionLRIncl05Str.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.LR_incl_05, currentActivity.Substring(WriteQ2CorrectionLRIncl05Str.Length).Trim()); - else if (currentActivity.ToLower().Contains(UpdateBothQ2FactorsTestRLOnlyStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.UpdateBothQ2FactorsTestRLDir, null); - else if (currentActivity.ToLower().Contains(UpdateBothQ2FactorsTestLROnlyStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.UpdateBothQ2FactorsTestLRDir, null); - else if (currentActivity.ToLower().Contains(UpdateQ2CorrectionsStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Update, currentActivity.Substring(UpdateQ2CorrectionsStr.Length).Trim()); - else if (currentActivity.ToLower().Contains(ConditnlUpdateQ2CorrectionsStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.ConditionalUpdate, currentActivity.Substring(ConditnlUpdateQ2CorrectionsStr.Length).Trim()); - else if (currentActivity.ToLower().Contains(ConditnlUpdateQ2CorrRLStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.ConditionalUpdateRL, currentActivity.Substring(ConditnlUpdateQ2CorrRLStr.Length).Trim()); - else if (currentActivity.ToLower().Contains(ConditnlUpdateQ2CorrLRStr.ToLower())) error = CalculateAndWriteQ2Corrections(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.ConditionalUpdateLR, currentActivity.Substring(ConditnlUpdateQ2CorrLRStr.Length).Trim()); - else if (currentActivity.ToLower() == Reset2HzCorrectionStr.ToLower()) error = Reset2HzCorrection(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == Write2HzCorrectionStr.ToLower()) error = Write2HzCorrection(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == GetDefaultQ2CorrectionsStr.ToLower()) error = GetQ2PreCorrectionsFormRest(threadID, ihead, wm, ref resultStr); - else if (currentActivity.ToLower() == DewaReworkRLStr.ToLower()) error = DewaRework(ihead, wm, FlowDir.R_L, ref resultStr); - else if (currentActivity.ToLower() == DewaReworkLRStr.ToLower()) error = DewaRework(ihead, wm, FlowDir.L_R, ref resultStr); - else if (currentActivity.ToLower().Contains(StartTestingSealedMetersStr.ToLower())) error = StartTestingSealedMeter(ihead, wm, ref resultStr); - else if (currentActivity.ToLower().Contains(EndTestingSealedMetersStr.ToLower())) error = EndTestingSealedMeter(ihead, wm, ref resultStr); else if (currentActivity.ToLower().Contains(SimulateCmd.ToLower())) error = Simulate(ihead, wm, ref resultStr); #endif else @@ -837,6 +807,58 @@ namespace TBF.Rig.TestMethods.iPerlCommunication } } + private CommErr ReadSerialNr(int threadId, IperlHead 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 ConfigStruct(); + } + if (ihead.CommFailed || ihead.ConfigStruct == null) return CommErr.CommFailed; + + //I will do communication to meter now + + CommErr error = CommErr.Read; + if (ihead.OptoHeadTest.ReadSerialNr()) + { + log.Debug("ReadSerialNr successful"); + resultStr = string.Format($"Serial No: {ihead.OptoHeadTest.ReadRequest_PCB()}"); + error = CommErr.None; + } + else + { + resultStr = "Failed Read Serial No"; + } + + return error; + } + + private CommErr SetIdleMode(int threadId, IperlHead 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 @@ -850,6 +872,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// true on success static CommErr ReadConfiguration(IperlHead 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). @@ -861,22 +886,35 @@ namespace TBF.Rig.TestMethods.iPerlCommunication 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 - byte[] config = null; - readRetVal = ReadRequestPort(ihead, MessageID.Configuration, StructName.Configuration, 0, ConfigStruct.Length, out config); - if (readRetVal == 0) + + if (ihead.OptoHeadTest.ReadConfiguration(DiagnosticLedState.State4)) { error = CommErr.None; - ihead.ConfigStruct = ConfigStruct.FromByteArray(config); - resultStr = ihead.ConfigStruct.ToString(1); + //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 + Math.Max(0, Math.Min(readRetVal, 4)); + return error; } @@ -892,90 +930,50 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// true on success static CommErr SetTestMode(int threadId, IperlHead 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 ConfigStruct(); + } if (ihead.CommFailed || ihead.ConfigStruct == null) return CommErr.CommFailed; - Byte testModeConfig = 0xA0; /// Default value + //I will do communication to meter now + + DiagnosticLedState testModeConfig = DiagnosticLedState.State4; /// Default value /// - if (multiTestParams[currentActivityStep].Activity.Length > SetTestModeStr.Length) + + if (ihead.OptoHeadTest.SetTestMode()) { - string testModeConfigStr = multiTestParams[currentActivityStep].Activity.Substring(SetTestModeStr.Length + 1); - UInt16 byteVal; - if (UInt16.TryParse(testModeConfigStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byteVal) && byteVal <= 255) - { - testModeConfig = (Byte)byteVal; /// Update with specified value - } + log.Debug($" Iperl:{ihead.Name}, test mode activated now"); } + - if (ihead.ConfigStruct.MeterState == MeterState.Test && ihead.ConfigStruct.TestModeConfig == testModeConfig) + 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($" Iperl:{ihead.Name}, status: {resultStr}"); return CommErr.None; } /// Communication necessary CommErr error = CommErr.None; - - if (error==CommErr.None && (ihead.ConfigStruct.TestModeConfig != testModeConfig) && (ihead.ConfigStruct.MeterState != MeterState.Active)) - { - /// Switch to Active mode in order to change TestModeConfig - error = CommErr.CmdActive; - byte[] cmd = new byte[1] { (byte)Command.SetActiveMode }; - if (0 == WriteRequestPort(ihead, MessageID.Command, StructName.Command, 0, 1, cmd)) - { - error = CommErr.None; - } - - /// Delay min. 250 ms - Thread.Sleep(Math.Max(250, CfgIPerl.DelayBetweenRetries)); - } - - if (error == CommErr.None && (ihead.ConfigStruct.TestModeConfig != testModeConfig)) - { - /// Change the TestModeConfig if necessary - error = CommErr.Write; - byte[] tstMdCfg = new byte[1] { testModeConfig }; - if (0 == WriteRequestPort(ihead, MessageID.Configuration, StructName.Configuration, 21, 1, tstMdCfg)) - { - ihead.ConfigStruct.Update(21, tstMdCfg); - error = CommErr.None; - } - - /// Delay min. 250 ms - Thread.Sleep(Math.Max(250, CfgIPerl.DelayBetweenRetries)); - } - - if (error == CommErr.None) - { - /// Switch to test mode - error = CommErr.CmdTest; - byte[] cmd = new byte[1] { (byte)Command.SetTestMode }; - if (0 == WriteRequestPort(ihead, MessageID.Command, StructName.Command, 0, 1, cmd)) - { - error = CommErr.None; - } - - /// Delay min. 250 ms - Thread.Sleep(Math.Max(250, CfgIPerl.DelayBetweenRetries)); - } - + /// Now the meter should be in the Test mode ... verify if (error == CommErr.None) { /// Verify the configuration - Thread.Sleep(2000); // RFID: 1000 ms is enough, NFC needs min 2000 ms error = CommErr.Verify; - byte[] config = null; - int retVal = ReadRequestPort(ihead, MessageID.Configuration, StructName.Configuration, 0, ConfigStruct.Length, out config); - if (0 == retVal) + + + if ((ihead.ConfigStruct.MeterState == ProtocolStatuses.Active) && + (ihead.ConfigStruct.TestModeConfig == testModeConfig)) { - ihead.ConfigStruct = ConfigStruct.FromByteArray(config); - if ((ihead.ConfigStruct.MeterState == MeterState.Test) && (ihead.ConfigStruct.TestModeConfig == testModeConfig)) - { - error = CommErr.None; - resultStr = ihead.ConfigStruct.ToString(1); - } + error = CommErr.None; + resultStr = ihead.ConfigStruct.GetActiveModeString(); } + } return error; @@ -991,44 +989,25 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// true on success static CommErr SetActiveMode(int threadId, IperlHead ihead, ref string resultStr) { + log.Debug("SetActiveMode threadId=" + threadId); CommErr error = CommErr.CmdActive; /// Switch to active mode - byte[] cmd = new byte[1] { (byte)Command.SetActiveMode }; - if (0 == WriteRequestPort(ihead, MessageID.Command, StructName.Command, 0, 1, cmd)) + + if (ihead.OptoHeadTest.SetActiveMode()) { error = CommErr.None; } -#if VERIFY_ACTIVE_MODE - if (error == CommErr.None) - { - error = CommErr.Verify; - /// Read configuration - byte[] cfg_0_3 = null; - if (ihead.ConfigStruct == null) - { - if (0 == ReadRequestPort(threadId, ihead, MessageID.Configuration, 0, 4, out cfg_0_3)) - { - ihead.ConfigStruct.Update(0, cfg_0_3); - if (ihead.ConfigStruct.MeterState == MeterState.Active) - { - error = CommErr.None; - resultStr = ihead.ConfigStruct.ToString(1); - } - } - } - } -#else if (error == CommErr.None) { if (ihead.ConfigStruct == null) resultStr = "OK (Config not available)"; else - resultStr = ihead.ConfigStruct.ToString(1); + resultStr = ihead.ConfigStruct.GetActiveModeString(); } -#endif + return error; } @@ -1040,32 +1019,32 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Water meter object /// String passed to caller /// true on success - static CommErr ReadCalibration(IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (ihead.CommFailed) return CommErr.CommFailed; - - CommErr error = CommErr.Read; - int readRetVal = 0; - - /// Read calibration - byte[] calib = null; - readRetVal = ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 0, CalibrationStruct.Length, out calib); - if (readRetVal == 0) - { - ihead.CalibrationStruct = CalibrationStruct.FromByteArray(calib); - - if (wm.OrigCalibFactor == 0) - { - wm.OrigCalibFactor = ihead.CalibrationStruct.Calibration; - wm.FWVersion = ihead.CalibrationStruct.FWVersionStr(); - } - - resultStr = ihead.CalibrationStruct.ToString(); - error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType; - } - - return error + Math.Max(0, Math.Min(readRetVal, 4)); - } + // static CommErr ReadCalibration(IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (ihead.CommFailed) return CommErr.CommFailed; + // + // CommErr error = CommErr.Read; + // int readRetVal = 0; + // + // /// Read calibration + // byte[] calib = null; + // readRetVal = ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 0, CalibrationStruct.Length, out calib); + // if (readRetVal == 0) + // { + // ihead.CalibrationStruct = CalibrationStruct.FromByteArray(calib); + // + // if (wm.OrigCalibFactor == 0) + // { + // wm.OrigCalibFactor = ihead.CalibrationStruct.Calibration; + // wm.FWVersion = ihead.CalibrationStruct.FWVersionStr(); + // } + // + // resultStr = ihead.CalibrationStruct.ToString(); + // error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType; + // } + // + // return error + Math.Max(0, Math.Min(readRetVal, 4)); + // } /// @@ -1074,33 +1053,33 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Water meter object /// String passed to caller /// true on success - static CommErr ReadCalibrationV4(IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (ihead.CommFailed) return CommErr.CommFailed; - - CommErr error = CommErr.Read; - int readRetVal = 0; - - /// Read calibration - byte[] calib = null; - readRetVal = ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 0, CalibrationStructV4.Length, out calib); - if (readRetVal == 0) - { - ihead.CalibrationStructV4 = CalibrationStructV4.FromByteArray(calib); - - if ((wm.OrigCalibFactor == 0) && (wm.OrigCalibFactorLNA == 0)) - { - wm.OrigCalibFactor = ihead.CalibrationStructV4.Calibration; - wm.OrigCalibFactorLNA = ihead.CalibrationStructV4.CalibrationLNA; - wm.FWVersion = ihead.CalibrationStructV4.FWVersionStr(); - } - - resultStr = ihead.CalibrationStructV4.ToString(); - error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType; - } - - return error + Math.Max(0, Math.Min(readRetVal, 4)); - } + // static CommErr ReadCalibrationV4(IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (ihead.CommFailed) return CommErr.CommFailed; + // + // CommErr error = CommErr.Read; + // int readRetVal = 0; + // + // /// Read calibration + // byte[] calib = null; + // readRetVal = ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 0, CalibrationStructV4.Length, out calib); + // if (readRetVal == 0) + // { + // ihead.CalibrationStructV4 = CalibrationStructV4.FromByteArray(calib); + // + // if ((wm.OrigCalibFactor == 0) && (wm.OrigCalibFactorLNA == 0)) + // { + // wm.OrigCalibFactor = ihead.CalibrationStructV4.Calibration; + // wm.OrigCalibFactorLNA = ihead.CalibrationStructV4.CalibrationLNA; + // wm.FWVersion = ihead.CalibrationStructV4.FWVersionStr(); + // } + // + // resultStr = ihead.CalibrationStructV4.ToString(); + // error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType; + // } + // + // return error + Math.Max(0, Math.Min(readRetVal, 4)); + // } /// @@ -1112,130 +1091,130 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Water meter object /// String passed to caller /// true on success - static CommErr WriteCalibrationFactor(int threadId, IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (ihead.CommFailed || (ihead.CalibrationStruct == null)) return CommErr.CommFailed; - - /// - /// Parse calibration factor (1 argument) or calibration factor limits (2 arguments) - /// - UInt16 newCalibFactor = 0; - if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationFactorStr.Length) - { - UInt16 factorLimitLo; - UInt16 factorLimitHi; - UInt16 val; - - string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationFactorStr.Length + 1); - string[] arguments = calibFactrorStr.Split(new char[] { ' ' }); - - if (arguments.Length >= 2 && - UInt16.TryParse(arguments[0], out factorLimitLo) && factorLimitLo > 0 && - UInt16.TryParse(arguments[1], out factorLimitHi) && factorLimitHi > 0) - { - /// - /// Lower and upper limits for the calibration factor are specified as iPerlCommunication activity arguments - /// - if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest; - - newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, factorLimitLo, factorLimitHi); - } - else if (arguments.Length == 1 && UInt16.TryParse(arguments[0], out val) && val > 0) - { - /// - /// Calibration factor value is specified as an iPerlCommunication activity argument - /// - newCalibFactor = val; /// Update with specified value - } - else if (arguments.Length == 1 && wm.GetTestData(arguments[0]) != null) - { - /// - /// Adjustment test name is specified as an iPerlCommunication activity argument - /// - Results.Entities.TestData adjustTestData = wm.GetTestData(arguments[0]); - Results.Entities.MeterTestRslt adjustTestRslt; - if (adjustTestData == null) - { - return CommErr.MissingTest; - } - else if (adjustTestData.Repeats == 1) - { - /// Find a test result if Repeats == 1 - adjustTestRslt = wm.GetMeterTestRslt(arguments[0]); - - if (adjustTestRslt == null || !adjustTestRslt.TestDone) return CommErr.MissingTest; - } - else - { - /// Calculate a summarized test result if Repeats > 1 - adjustTestRslt = new Results.Entities.MeterTestRslt(); - for (int i = 1; i <= adjustTestData.Repeats; i++) - { - Results.Entities.MeterTestRslt oneMTR = wm.GetMeterTestRslt(Utils.TestTitle(adjustTestData, i)); - if (oneMTR == null || !oneMTR.TestDone) return CommErr.MissingTest; - - adjustTestRslt.VolumeMeter += oneMTR.VolumeMeter; - adjustTestRslt.VolumeRef += oneMTR.VolumeRef; - } - } - - newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi); - } - else - { - /// - /// Otherwise the last test is supposed to be an adjustment test - /// - if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest; - - newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi); - } - } - else - { - /// - /// No iPerlCommunication activity arguments --> The last test is supposed to be an adjustment test - /// - if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest; - - newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi); - } - - if (newCalibFactor == 0) return CommErr.OutOfRange; - - /// - /// Start communication with iPerl - /// - CommErr error; - byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) }; - /// - /// Write the new calibration factor (up to cfg.MaxCommRetries tims) - /// - error = CommErr.Write; - if (0 == WriteRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, data)) - { - /// - /// Read and verify the calibration factor - /// - error = CommErr.ReadAfterWrite; - byte[] calib_2_3 = null; - if (0 == ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, out calib_2_3)) - { - error = CommErr.Verify; - if (calib_2_3 != null && calib_2_3.Length == 2 && data[0] == calib_2_3[0] && data[1] == calib_2_3[1]) - { - error = CommErr.None; - ihead.CalibrationStruct.Update(data, 2); - wm.CalibFactor = newCalibFactor; - resultStr = ihead.CalibrationStruct.ToString(); - } - } - } - - ihead.CalibrationStruct.Update(data, 2); - - return error; - } + // static CommErr WriteCalibrationFactor(int threadId, IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (ihead.CommFailed || (ihead.CalibrationStruct == null)) return CommErr.CommFailed; + // + // /// + // /// Parse calibration factor (1 argument) or calibration factor limits (2 arguments) + // /// + // UInt16 newCalibFactor = 0; + // if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationFactorStr.Length) + // { + // UInt16 factorLimitLo; + // UInt16 factorLimitHi; + // UInt16 val; + // + // string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationFactorStr.Length + 1); + // string[] arguments = calibFactrorStr.Split(new char[] { ' ' }); + // + // if (arguments.Length >= 2 && + // UInt16.TryParse(arguments[0], out factorLimitLo) && factorLimitLo > 0 && + // UInt16.TryParse(arguments[1], out factorLimitHi) && factorLimitHi > 0) + // { + // /// + // /// Lower and upper limits for the calibration factor are specified as iPerlCommunication activity arguments + // /// + // if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest; + // + // newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, factorLimitLo, factorLimitHi); + // } + // else if (arguments.Length == 1 && UInt16.TryParse(arguments[0], out val) && val > 0) + // { + // /// + // /// Calibration factor value is specified as an iPerlCommunication activity argument + // /// + // newCalibFactor = val; /// Update with specified value + // } + // else if (arguments.Length == 1 && wm.GetTestData(arguments[0]) != null) + // { + // /// + // /// Adjustment test name is specified as an iPerlCommunication activity argument + // /// + // Results.Entities.TestData adjustTestData = wm.GetTestData(arguments[0]); + // Results.Entities.MeterTestRslt adjustTestRslt; + // if (adjustTestData == null) + // { + // return CommErr.MissingTest; + // } + // else if (adjustTestData.Repeats == 1) + // { + // /// Find a test result if Repeats == 1 + // adjustTestRslt = wm.GetMeterTestRslt(arguments[0]); + // + // if (adjustTestRslt == null || !adjustTestRslt.TestDone) return CommErr.MissingTest; + // } + // else + // { + // /// Calculate a summarized test result if Repeats > 1 + // adjustTestRslt = new Results.Entities.MeterTestRslt(); + // for (int i = 1; i <= adjustTestData.Repeats; i++) + // { + // Results.Entities.MeterTestRslt oneMTR = wm.GetMeterTestRslt(Utils.TestTitle(adjustTestData, i)); + // if (oneMTR == null || !oneMTR.TestDone) return CommErr.MissingTest; + // + // adjustTestRslt.VolumeMeter += oneMTR.VolumeMeter; + // adjustTestRslt.VolumeRef += oneMTR.VolumeRef; + // } + // } + // + // newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi); + // } + // else + // { + // /// + // /// Otherwise the last test is supposed to be an adjustment test + // /// + // if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest; + // + // newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi); + // } + // } + // else + // { + // /// + // /// No iPerlCommunication activity arguments --> The last test is supposed to be an adjustment test + // /// + // if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest; + // + // newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi); + // } + // + // if (newCalibFactor == 0) return CommErr.OutOfRange; + // + // /// + // /// Start communication with iPerl + // /// + // CommErr error; + // byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) }; + // /// + // /// Write the new calibration factor (up to cfg.MaxCommRetries tims) + // /// + // error = CommErr.Write; + // if (0 == WriteRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, data)) + // { + // /// + // /// Read and verify the calibration factor + // /// + // error = CommErr.ReadAfterWrite; + // byte[] calib_2_3 = null; + // if (0 == ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, out calib_2_3)) + // { + // error = CommErr.Verify; + // if (calib_2_3 != null && calib_2_3.Length == 2 && data[0] == calib_2_3[0] && data[1] == calib_2_3[1]) + // { + // error = CommErr.None; + // ihead.CalibrationStruct.Update(data, 2); + // wm.CalibFactor = newCalibFactor; + // resultStr = ihead.CalibrationStruct.ToString(); + // } + // } + // } + // + // ihead.CalibrationStruct.Update(data, 2); + // + // return error; + // } /// @@ -1247,159 +1226,159 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Water meter object /// String passed to caller /// true on success - static CommErr WriteCalibrationV4Factors(int threadId, IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (ihead.CommFailed || (ihead.CalibrationStructV4 == null)) return CommErr.CommFailed; - - /// - /// Parse calibration factor (1 argument) or calibration factor limits (2 arguments) - /// - UInt16 newCalibFactor = 0; - UInt16 newCalibFactorLNA = 0; - if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationV4FactorsStr.Length) - { - UInt16 factorLimitLo = 0; - UInt16 factorLimitHi = 0; - UInt16 lnaFactorLimitLo = 0; - UInt16 lnaFactorLimitHi = 0; - Results.Entities.TestData adjustTestData = null; - Results.Entities.TestData lnaAdjustTestData = null; - Results.Entities.MeterTestRslt adjustTestRslt = null; - Results.Entities.MeterTestRslt lnaAdjustTestRslt = null; - - string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationV4FactorsStr.Length + 1); - string[] arguments = calibFactrorStr.Split(new char[] { ' ' }); - - if (arguments.Length == 6) - { - if (!wm.TryGetTestData(arguments[0], out adjustTestData) || - !UInt16.TryParse(arguments[1], out factorLimitLo) || factorLimitLo <= 0 && - !UInt16.TryParse(arguments[2], out factorLimitHi) || factorLimitHi <= 0 && - !wm.TryGetTestData(arguments[3], out lnaAdjustTestData) || - !UInt16.TryParse(arguments[4], out lnaFactorLimitLo) || lnaFactorLimitLo <= 0 && - !UInt16.TryParse(arguments[5], out lnaFactorLimitHi) || lnaFactorLimitHi <= 0) - { - return CommErr.WrongArguments; - } - else - { - adjustTestRslt = GetAverageTestRslt(wm, adjustTestData); - lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData); - - if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null)) - { - return CommErr.MissingTest; - } - - newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi); - newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi); - } - } - else if (arguments.Length == 4) - { - if (!wm.TryGetTestData(arguments[0], out adjustTestData) || - !wm.TryGetTestData(arguments[1], out lnaAdjustTestData) || - !UInt16.TryParse(arguments[2], out lnaFactorLimitLo) || lnaFactorLimitLo <= 0 && - !UInt16.TryParse(arguments[3], out lnaFactorLimitHi) || lnaFactorLimitHi <= 0) - { - return CommErr.WrongArguments; - } - else - { - factorLimitLo = ihead.FactorLimitLo; - factorLimitHi = ihead.FactorLimitHi; - - adjustTestRslt = GetAverageTestRslt(wm, adjustTestData); - lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData); - - if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null)) - { - return CommErr.MissingTest; - } - - newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi); - newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi); - } - } - else if (arguments.Length == 2) - { - if (!wm.TryGetTestData(arguments[0], out adjustTestData) || - !wm.TryGetTestData(arguments[1], out lnaAdjustTestData)) - { - return CommErr.WrongArguments; - } - else - { - factorLimitLo = ihead.FactorLimitLo; - factorLimitHi = ihead.FactorLimitHi; - lnaFactorLimitLo = ihead.FactorLimitLo; - lnaFactorLimitHi = ihead.FactorLimitHi; - - adjustTestRslt = GetAverageTestRslt(wm, adjustTestData); - lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData); - - if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null)) - { - return CommErr.MissingTest; - } - - newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi); - newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi); - } - } - else - { - return CommErr.WrongArguments; - } - } - else - { - return CommErr.WrongArguments; - } - - if (newCalibFactor == 0 || newCalibFactorLNA == 0) return CommErr.OutOfRange; - - /// - /// Start communication with iPerl - /// - CommErr error; - byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) }; - byte[] dataLNA = new byte[2] { (byte)(newCalibFactorLNA & 0x00FF), (byte)((newCalibFactorLNA >> 8) & 0x00FF) }; - /// - /// Write the new calibration factor (up to cfg.MaxCommRetries tims) - /// - error = CommErr.Write; - if (0 == WriteRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, data) && - 0 == WriteRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 34, 2, dataLNA)) - { - /// - /// Read and verify the calibration factor - /// - error = CommErr.ReadAfterWrite; - byte[] calib_2_3 = null; - byte[] calib_34_35 = null; - if (0 == ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, out calib_2_3) && - 0 == ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 34, 2, out calib_34_35)) - { - error = CommErr.Verify; - if (calib_2_3 != null && calib_2_3.Length == 2 && data[0] == calib_2_3[0] && data[1] == calib_2_3[1] && - calib_34_35 != null && calib_34_35.Length == 2 && dataLNA[0] == calib_34_35[0] && dataLNA[1] == calib_34_35[1]) - { - error = CommErr.None; - ihead.CalibrationStructV4.Update(data, 2); - ihead.CalibrationStructV4.Update(dataLNA, 34); - wm.CalibFactor = newCalibFactor; - wm.CalibFactorLNA = newCalibFactorLNA; - resultStr = ihead.CalibrationStructV4.ToString(); - } - } - } - - ihead.CalibrationStructV4.Update(data, 2); - ihead.CalibrationStructV4.Update(dataLNA, 34); - - return error; - } + // static CommErr WriteCalibrationV4Factors(int threadId, IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (ihead.CommFailed || (ihead.CalibrationStructV4 == null)) return CommErr.CommFailed; + // + // /// + // /// Parse calibration factor (1 argument) or calibration factor limits (2 arguments) + // /// + // UInt16 newCalibFactor = 0; + // UInt16 newCalibFactorLNA = 0; + // if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationV4FactorsStr.Length) + // { + // UInt16 factorLimitLo = 0; + // UInt16 factorLimitHi = 0; + // UInt16 lnaFactorLimitLo = 0; + // UInt16 lnaFactorLimitHi = 0; + // Results.Entities.TestData adjustTestData = null; + // Results.Entities.TestData lnaAdjustTestData = null; + // Results.Entities.MeterTestRslt adjustTestRslt = null; + // Results.Entities.MeterTestRslt lnaAdjustTestRslt = null; + // + // string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationV4FactorsStr.Length + 1); + // string[] arguments = calibFactrorStr.Split(new char[] { ' ' }); + // + // if (arguments.Length == 6) + // { + // if (!wm.TryGetTestData(arguments[0], out adjustTestData) || + // !UInt16.TryParse(arguments[1], out factorLimitLo) || factorLimitLo <= 0 && + // !UInt16.TryParse(arguments[2], out factorLimitHi) || factorLimitHi <= 0 && + // !wm.TryGetTestData(arguments[3], out lnaAdjustTestData) || + // !UInt16.TryParse(arguments[4], out lnaFactorLimitLo) || lnaFactorLimitLo <= 0 && + // !UInt16.TryParse(arguments[5], out lnaFactorLimitHi) || lnaFactorLimitHi <= 0) + // { + // return CommErr.WrongArguments; + // } + // else + // { + // adjustTestRslt = GetAverageTestRslt(wm, adjustTestData); + // lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData); + // + // if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null)) + // { + // return CommErr.MissingTest; + // } + // + // newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi); + // newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi); + // } + // } + // else if (arguments.Length == 4) + // { + // if (!wm.TryGetTestData(arguments[0], out adjustTestData) || + // !wm.TryGetTestData(arguments[1], out lnaAdjustTestData) || + // !UInt16.TryParse(arguments[2], out lnaFactorLimitLo) || lnaFactorLimitLo <= 0 && + // !UInt16.TryParse(arguments[3], out lnaFactorLimitHi) || lnaFactorLimitHi <= 0) + // { + // return CommErr.WrongArguments; + // } + // else + // { + // factorLimitLo = ihead.FactorLimitLo; + // factorLimitHi = ihead.FactorLimitHi; + // + // adjustTestRslt = GetAverageTestRslt(wm, adjustTestData); + // lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData); + // + // if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null)) + // { + // return CommErr.MissingTest; + // } + // + // newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi); + // newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi); + // } + // } + // else if (arguments.Length == 2) + // { + // if (!wm.TryGetTestData(arguments[0], out adjustTestData) || + // !wm.TryGetTestData(arguments[1], out lnaAdjustTestData)) + // { + // return CommErr.WrongArguments; + // } + // else + // { + // factorLimitLo = ihead.FactorLimitLo; + // factorLimitHi = ihead.FactorLimitHi; + // lnaFactorLimitLo = ihead.FactorLimitLo; + // lnaFactorLimitHi = ihead.FactorLimitHi; + // + // adjustTestRslt = GetAverageTestRslt(wm, adjustTestData); + // lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData); + // + // if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null)) + // { + // return CommErr.MissingTest; + // } + // + // newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi); + // newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi); + // } + // } + // else + // { + // return CommErr.WrongArguments; + // } + // } + // else + // { + // return CommErr.WrongArguments; + // } + // + // if (newCalibFactor == 0 || newCalibFactorLNA == 0) return CommErr.OutOfRange; + // + // /// + // /// Start communication with iPerl + // /// + // CommErr error; + // byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) }; + // byte[] dataLNA = new byte[2] { (byte)(newCalibFactorLNA & 0x00FF), (byte)((newCalibFactorLNA >> 8) & 0x00FF) }; + // /// + // /// Write the new calibration factor (up to cfg.MaxCommRetries tims) + // /// + // error = CommErr.Write; + // if (0 == WriteRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, data) && + // 0 == WriteRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 34, 2, dataLNA)) + // { + // /// + // /// Read and verify the calibration factor + // /// + // error = CommErr.ReadAfterWrite; + // byte[] calib_2_3 = null; + // byte[] calib_34_35 = null; + // if (0 == ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 2, 2, out calib_2_3) && + // 0 == ReadRequestPort(ihead, MessageID.Calibration, StructName.Calibration, 34, 2, out calib_34_35)) + // { + // error = CommErr.Verify; + // if (calib_2_3 != null && calib_2_3.Length == 2 && data[0] == calib_2_3[0] && data[1] == calib_2_3[1] && + // calib_34_35 != null && calib_34_35.Length == 2 && dataLNA[0] == calib_34_35[0] && dataLNA[1] == calib_34_35[1]) + // { + // error = CommErr.None; + // ihead.CalibrationStructV4.Update(data, 2); + // ihead.CalibrationStructV4.Update(dataLNA, 34); + // wm.CalibFactor = newCalibFactor; + // wm.CalibFactorLNA = newCalibFactorLNA; + // resultStr = ihead.CalibrationStructV4.ToString(); + // } + // } + // } + // + // ihead.CalibrationStructV4.Update(data, 2); + // ihead.CalibrationStructV4.Update(dataLNA, 34); + // + // return error; + // } /// @@ -1638,28 +1617,28 @@ namespace TBF.Rig.TestMethods.iPerlCommunication switch (ihead.MeterType) { case MeterType.DN15: - q2corrRL = CfgIPerl.DfltQ2c_15_rl; - q2corrLR = CfgIPerl.DfltQ2c_15_lr; + q2corrRL = cfg.DfltQ2c_15_rl; + q2corrLR = cfg.DfltQ2c_15_lr; break; case MeterType.DN20: - q2corrRL = CfgIPerl.DfltQ2c_20_rl; - q2corrLR = CfgIPerl.DfltQ2c_20_lr; + q2corrRL = cfg.DfltQ2c_20_rl; + q2corrLR = cfg.DfltQ2c_20_lr; break; case MeterType.DN25: - q2corrRL = CfgIPerl.DfltQ2c_25_63_rl; - q2corrLR = CfgIPerl.DfltQ2c_25_63_lr; + q2corrRL = cfg.DfltQ2c_25_63_rl; + q2corrLR = cfg.DfltQ2c_25_63_lr; break; case MeterType.DN25_Q3_10: - q2corrRL = CfgIPerl.DfltQ2c_25_10_rl; - q2corrLR = CfgIPerl.DfltQ2c_25_10_lr; + q2corrRL = cfg.DfltQ2c_25_10_rl; + q2corrLR = cfg.DfltQ2c_25_10_lr; break; case MeterType.DN32: - q2corrRL = CfgIPerl.DfltQ2c_32_rl; - q2corrLR = CfgIPerl.DfltQ2c_32_lr; + q2corrRL = cfg.DfltQ2c_32_rl; + q2corrLR = cfg.DfltQ2c_32_lr; break; case MeterType.DN40: - q2corrRL = CfgIPerl.DfltQ2c_40_rl; - q2corrLR = CfgIPerl.DfltQ2c_40_lr; + q2corrRL = cfg.DfltQ2c_40_rl; + q2corrLR = cfg.DfltQ2c_40_lr; break; default: q2corrRL = 0; @@ -1742,28 +1721,28 @@ namespace TBF.Rig.TestMethods.iPerlCommunication switch (ihead.MeterType) { case MeterType.DN15: - q2corrRL = CfgIPerl.DfltQ2c_15_rl; - q2corrLR = CfgIPerl.DfltQ2c_15_lr; + q2corrRL = cfg.DfltQ2c_15_rl; + q2corrLR = cfg.DfltQ2c_15_lr; break; case MeterType.DN20: - q2corrRL = CfgIPerl.DfltQ2c_20_rl; - q2corrLR = CfgIPerl.DfltQ2c_20_lr; + q2corrRL = cfg.DfltQ2c_20_rl; + q2corrLR = cfg.DfltQ2c_20_lr; break; case MeterType.DN25: - q2corrRL = CfgIPerl.DfltQ2c_25_63_rl; - q2corrLR = CfgIPerl.DfltQ2c_25_63_lr; + q2corrRL = cfg.DfltQ2c_25_63_rl; + q2corrLR = cfg.DfltQ2c_25_63_lr; break; case MeterType.DN25_Q3_10: - q2corrRL = CfgIPerl.DfltQ2c_25_10_rl; - q2corrLR = CfgIPerl.DfltQ2c_25_10_lr; + q2corrRL = cfg.DfltQ2c_25_10_rl; + q2corrLR = cfg.DfltQ2c_25_10_lr; break; case MeterType.DN32: - q2corrRL = CfgIPerl.DfltQ2c_32_rl; - q2corrLR = CfgIPerl.DfltQ2c_32_lr; + q2corrRL = cfg.DfltQ2c_32_rl; + q2corrLR = cfg.DfltQ2c_32_lr; break; case MeterType.DN40: - q2corrRL = CfgIPerl.DfltQ2c_40_rl; - q2corrLR = CfgIPerl.DfltQ2c_40_lr; + q2corrRL = cfg.DfltQ2c_40_rl; + q2corrLR = cfg.DfltQ2c_40_lr; break; default: q2corrRL = 0; @@ -2266,80 +2245,80 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Arrow direction /// String passed to caller /// true on success - static CommErr DewaRework(IperlHead ihead, WaterMeter wm, FlowDir flowDir, ref string resultStr) - { - if (ihead.CommFailed) return CommErr.CommFailed; - - byte arrow = (flowDir == FlowDir.L_R) ? (byte)1 : (byte)2; /// L-R is reverse flow (=1), R-L is forward flow (=2)(default) - - List dataToBeWritten = new List - { - new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC.ToDescription()? 33:0x19A1, new byte[] { (byte)0xA5 }, "Open Sealing"), // ????? - new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC.ToDescription()? 5:0x1985, new byte[] { arrow }, "Arrow"), - new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC.ToDescription()? 28:0x199C, new byte[5], "Clear S/N"), - new iPerlDataWrite(MessageID.Configuration, StructName.Configuration, 0x0015, new byte[] { (byte)0xA0 }, "Test mode config = A0"), - new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC.ToDescription()? 14:0x198E, new byte[] { (byte)(2510 & 0xFF), (byte)((2510 >> 8) & 0xFF) }, "Receipt mean current") - }; - - // check meter status: 1-Idle, 2-Active, 3-Test, 4-End Of Life - if (0 == ReadRequestPort(ihead, MessageID.Configuration, StructName.Configuration, 1, 1, out byte[] rdData)) - { - int eMeterState = (int)((SByte)rdData[0]); - switch (eMeterState) - { - case 1: // Idle -> Test -> Active - dataToBeWritten.Add(new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetTestMode }, "Set test mode")); - dataToBeWritten.Add(new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode")); - break; - case 3: // Test Mode -> Active - dataToBeWritten.Add(new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode")); - break; - } - } - - dataToBeWritten.Add(new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, new byte[] { (byte)1 }, "System Status")); - dataToBeWritten.Add(new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioParams, 0x1898, new byte[] { (byte)3 }, "WakeUpInterval")); - dataToBeWritten.Add(new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioParams, 0x18A2, new byte[] { (byte)0x4A, (byte)0x53, (byte)0x3B, (byte)0x8F, - (byte)0x70, (byte)0x31, (byte)0xC2, (byte)0x5D, - (byte)0x6F, (byte)0x2D, (byte)0xE8, (byte)0x07, - (byte)0x6E, (byte)0x0F, (byte)0x97, (byte)0xC3, }, "AES Key Crypted")); - - int successfyllyWrittenFlags = 0; /// Ones in this word represent communication failures, LSB represents the first step - int mask = 1; - foreach (var wData in dataToBeWritten) - { - bool isSuccessfullyWritten = false; - if (0 == WriteRequestPort(ihead, wData.MessageID, wData.StructName, wData.Offset, wData.Data.Length, wData.Data)) - { - isSuccessfullyWritten = true; - } - - if (!isSuccessfullyWritten) - { - /// Communication failed in this step - successfyllyWrittenFlags = (successfyllyWrittenFlags | mask); - } - - mask = (mask << 1); /// Adjust the mask for the next step - } - - if (successfyllyWrittenFlags == 0) - { - /// Success - if (ihead.ConfigStruct != null) - { - ihead.ConfigStruct.MeterState = MeterState.Active; - ihead.ConfigStruct.TestModeConfig = (byte)0xA0; - } - - resultStr = "OK"; - return CommErr.None; - } - else - { - return CommErr.Write; - } - } + // static CommErr DewaRework(IperlHead ihead, WaterMeter wm, FlowDir flowDir, ref string resultStr) + // { + // if (ihead.CommFailed) return CommErr.CommFailed; + // + // byte arrow = (flowDir == FlowDir.L_R) ? (byte)1 : (byte)2; /// L-R is reverse flow (=1), R-L is forward flow (=2)(default) + // + // List dataToBeWritten = new List + // { + // new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC? 33:0x19A1, new byte[] { (byte)0xA5 }, "Open Sealing"), // ????? + // new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC? 5:0x1985, new byte[] { arrow }, "Arrow"), + // new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC? 28:0x199C, new byte[5], "Clear S/N"), + // new iPerlDataWrite(MessageID.Configuration, StructName.Configuration, 0x0015, new byte[] { (byte)0xA0 }, "Test mode config = A0"), + // new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC? 14:0x198E, new byte[] { (byte)(2510 & 0xFF), (byte)((2510 >> 8) & 0xFF) }, "Receipt mean current") + // }; + // + // // check meter status: 1-Idle, 2-Active, 3-Test, 4-End Of Life + // if (0 == ReadRequestPort(ihead, MessageID.Configuration, StructName.Configuration, 1, 1, out byte[] rdData)) + // { + // int eMeterState = (int)((SByte)rdData[0]); + // switch (eMeterState) + // { + // case 1: // Idle -> Test -> Active + // dataToBeWritten.Add(new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetTestMode }, "Set test mode")); + // dataToBeWritten.Add(new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode")); + // break; + // case 3: // Test Mode -> Active + // dataToBeWritten.Add(new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode")); + // break; + // } + // } + // + // dataToBeWritten.Add(new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, new byte[] { (byte)1 }, "System Status")); + // dataToBeWritten.Add(new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioParams, 0x1898, new byte[] { (byte)3 }, "WakeUpInterval")); + // dataToBeWritten.Add(new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioParams, 0x18A2, new byte[] { (byte)0x4A, (byte)0x53, (byte)0x3B, (byte)0x8F, + // (byte)0x70, (byte)0x31, (byte)0xC2, (byte)0x5D, + // (byte)0x6F, (byte)0x2D, (byte)0xE8, (byte)0x07, + // (byte)0x6E, (byte)0x0F, (byte)0x97, (byte)0xC3, }, "AES Key Crypted")); + // + // int successfyllyWrittenFlags = 0; /// Ones in this word represent communication failures, LSB represents the first step + // int mask = 1; + // foreach (var wData in dataToBeWritten) + // { + // bool isSuccessfullyWritten = false; + // if (0 == WriteRequestPort(ihead, wData.MessageID, wData.StructName, wData.Offset, wData.Data.Length, wData.Data)) + // { + // isSuccessfullyWritten = true; + // } + // + // if (!isSuccessfullyWritten) + // { + // /// Communication failed in this step + // successfyllyWrittenFlags = (successfyllyWrittenFlags | mask); + // } + // + // mask = (mask << 1); /// Adjust the mask for the next step + // } + // + // if (successfyllyWrittenFlags == 0) + // { + // /// Success + // if (ihead.ConfigStruct != null) + // { + // ihead.ConfigStruct.StatusMode = ProtocolStatuses.Active; + // ihead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.State4; + // } + // + // resultStr = "OK"; + // return CommErr.None; + // } + // else + // { + // return CommErr.Write; + // } + // } /// /// Start testing a sealed meter @@ -2348,68 +2327,68 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Water meter object /// String passed to caller /// true on success - static CommErr StartTestingSealedMeter(IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (ihead.CommFailed) return CommErr.CommFailed; - - Byte testModeConfig = 0xA0; /// Default value - /// - if (multiTestParams[currentActivityStep].Activity.Length > StartTestingSealedMetersStr.Length) - { - string testModeConfigStr = multiTestParams[currentActivityStep].Activity.Substring(StartTestingSealedMetersStr.Length + 1); - UInt16 byteVal; - if (UInt16.TryParse(testModeConfigStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byteVal) && byteVal <= 255) - { - testModeConfig = (Byte)byteVal; /// Update with specified value - } - } - - iPerlDataWrite[] dataToBeWritten = new iPerlDataWrite[] - { - new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC.ToDescription()? 33:0x19A1, new byte[] { (byte)0xA5 }, "Open Sealing"), /// 0x5A=sealed, 0xA5=unsealed ?????? - new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, new byte[] { (byte)1 }, "System Status"), - new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode"), - new iPerlDataWrite(MessageID.Configuration, StructName.Configuration, 0x0015, new byte[] { testModeConfig }, string.Format("Test mode config = {0:X2}", testModeConfig)), - }; - - if (ihead.ConfigStruct != null) ihead.OrigTestModeConfig = ihead.ConfigStruct.TestModeConfig; - - int successfyllyWrittenFlags = 0; /// Ones in this word represent communication failures, LSB represents the first step - int mask = 1; - foreach (var wData in dataToBeWritten) - { - bool isSuccessfullyWritten = false; - if (0 == WriteRequestPort(ihead, wData.MessageID, wData.StructName, wData.Offset, wData.Data.Length, wData.Data)) - { - isSuccessfullyWritten = true; - } - - if (!isSuccessfullyWritten) - { - /// Communication failed in this step - successfyllyWrittenFlags = (successfyllyWrittenFlags | mask); - } - - mask = (mask << 1); /// Adjust the mask for the next step - } - - if (successfyllyWrittenFlags == 0) - { - /// Success - if (ihead.ConfigStruct != null) - { - ihead.ConfigStruct.MeterState = MeterState.Active; - ihead.ConfigStruct.TestModeConfig = (byte)0xA0; - } - - resultStr = "OK"; - return CommErr.None; - } - else - { - return CommErr.Write; - } - } + // static CommErr StartTestingSealedMeter(IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (ihead.CommFailed) return CommErr.CommFailed; + // + // Byte testModeConfig = 0xA0; /// Default value + // /// + // if (multiTestParams[currentActivityStep].Activity.Length > StartTestingSealedMetersStr.Length) + // { + // string testModeConfigStr = multiTestParams[currentActivityStep].Activity.Substring(StartTestingSealedMetersStr.Length + 1); + // UInt16 byteVal; + // if (UInt16.TryParse(testModeConfigStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byteVal) && byteVal <= 255) + // { + // testModeConfig = (Byte)byteVal; /// Update with specified value + // } + // } + // + // iPerlDataWrite[] dataToBeWritten = new iPerlDataWrite[] + // { + // new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC? 33:0x19A1, new byte[] { (byte)0xA5 }, "Open Sealing"), /// 0x5A=sealed, 0xA5=unsealed ?????? + // new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, new byte[] { (byte)1 }, "System Status"), + // new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode"), + // new iPerlDataWrite(MessageID.Configuration, StructName.Configuration, 0x0015, new byte[] { testModeConfig }, string.Format("Test mode config = {0:X2}", testModeConfig)), + // }; + // + // if (ihead.ConfigStruct != null) ihead.OrigTestModeConfig = ihead.ConfigStruct.TestModeConfig; + // + // int successfyllyWrittenFlags = 0; /// Ones in this word represent communication failures, LSB represents the first step + // int mask = 1; + // foreach (var wData in dataToBeWritten) + // { + // bool isSuccessfullyWritten = false; + // if (0 == WriteRequestPort(ihead, wData.MessageID, wData.StructName, wData.Offset, wData.Data.Length, wData.Data)) + // { + // isSuccessfullyWritten = true; + // } + // + // if (!isSuccessfullyWritten) + // { + // /// Communication failed in this step + // successfyllyWrittenFlags = (successfyllyWrittenFlags | mask); + // } + // + // mask = (mask << 1); /// Adjust the mask for the next step + // } + // + // if (successfyllyWrittenFlags == 0) + // { + // /// Success + // if (ihead.ConfigStruct != null) + // { + // ihead.ConfigStruct.MeterState = MeterState.Active; + // ihead.ConfigStruct.TestModeConfig = (byte)0xA0; + // } + // + // resultStr = "OK"; + // return CommErr.None; + // } + // else + // { + // return CommErr.Write; + // } + // } /// /// End testing a sealed meter @@ -2418,70 +2397,70 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Water meter object /// String passed to caller /// true on success - static CommErr EndTestingSealedMeter(IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (ihead.CommFailed) return CommErr.CommFailed; + // static CommErr EndTestingSealedMeter(IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (ihead.CommFailed) return CommErr.CommFailed; + // + // Byte testModeConfig = (ihead.OrigTestModeConfig != 0) ? ihead.OrigTestModeConfig : (byte)0x80; /// Restore original value (default is 0x80) + // + // iPerlDataWrite[] dataToBeWritten = new iPerlDataWrite[] + // { + // new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode"), + // new iPerlDataWrite(MessageID.Configuration, StructName.Configuration, 0x0015, new byte[] { testModeConfig }, string.Format("Test mode config = {0:X2}", testModeConfig)), + // new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, new byte[] { (byte)0 }, "System Status"), + // new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC? 33:0x19A1, new byte[] { (byte)0x5A }, "Close Sealing") /// 0x5A=sealed, 0xA5=unsealed ?????? + // }; + // + // int successfyllyWrittenFlags = 0; /// Ones in this word represent communication failures, LSB represents the first step + // int mask = 1; + // foreach (var wData in dataToBeWritten) + // { + // bool isSuccessfullyWritten = false; + // if (0 == WriteRequestPort(ihead, wData.MessageID, wData.StructName, wData.Offset, wData.Data.Length, wData.Data)) + // { + // isSuccessfullyWritten = true; + // } + // + // if (!isSuccessfullyWritten) + // { + // /// Communication failed in this step + // successfyllyWrittenFlags = (successfyllyWrittenFlags | mask); + // } + // + // mask = (mask << 1); /// Adjust the mask for the next step + // } + // + // if (successfyllyWrittenFlags == 0) + // { + // /// Success + // if (ihead.ConfigStruct != null) + // { + // ihead.ConfigStruct.MeterState = MeterState.Active; + // ihead.ConfigStruct.TestModeConfig = (byte)0xA0; + // } + // + // resultStr = "OK"; + // return CommErr.None; + // } + // else + // { + // return CommErr.Write; + // } + // } - Byte testModeConfig = (ihead.OrigTestModeConfig != 0) ? ihead.OrigTestModeConfig : (byte)0x80; /// Restore original value (default is 0x80) - - iPerlDataWrite[] dataToBeWritten = new iPerlDataWrite[] - { - new iPerlDataWrite(MessageID.Command, StructName.Command, 0x0000, new byte[] { (byte)Command.SetActiveMode }, "Set active mode"), - new iPerlDataWrite(MessageID.Configuration, StructName.Configuration, 0x0015, new byte[] { testModeConfig }, string.Format("Test mode config = {0:X2}", testModeConfig)), - new iPerlDataWrite(MessageID.RadioPassthrough, StructName.RadioInfo, 0x1804, new byte[] { (byte)0 }, "System Status"), - new iPerlDataWrite(MessageID.MetrologyMemory, StructName.Calibration, ihead.CommInterface == CommunicationInterface.NFC.ToDescription()? 33:0x19A1, new byte[] { (byte)0x5A }, "Close Sealing") /// 0x5A=sealed, 0xA5=unsealed ?????? - }; - - int successfyllyWrittenFlags = 0; /// Ones in this word represent communication failures, LSB represents the first step - int mask = 1; - foreach (var wData in dataToBeWritten) - { - bool isSuccessfullyWritten = false; - if (0 == WriteRequestPort(ihead, wData.MessageID, wData.StructName, wData.Offset, wData.Data.Length, wData.Data)) - { - isSuccessfullyWritten = true; - } - - if (!isSuccessfullyWritten) - { - /// Communication failed in this step - successfyllyWrittenFlags = (successfyllyWrittenFlags | mask); - } - - mask = (mask << 1); /// Adjust the mask for the next step - } - - if (successfyllyWrittenFlags == 0) - { - /// Success - if (ihead.ConfigStruct != null) - { - ihead.ConfigStruct.MeterState = MeterState.Active; - ihead.ConfigStruct.TestModeConfig = (byte)0xA0; - } - - resultStr = "OK"; - return CommErr.None; - } - else - { - return CommErr.Write; - } - } - - static CommErr GetQ2PreCorrectionsFormRest(int threadId, IperlHead ihead, WaterMeter wm, ref string resultStr) - { - if (!ProcessData.IsQ2PreCorrectionCalculated) - { - ProcessData.IsQ2PreCorrectionCalculated = true; - /*bool success = iPerlCommunicationSeq.GetQ2PreCorrectionsOrBackups(cfg, wm.WMTypeId(), - out ProcessData.CalculatedQ2PreCorrectionLR, - out ProcessData.CalculatedQ2PreCorrectionRL);*/ - } - - resultStr = string.Format("Q2 pre-corrections: LR={0} RL={1}", ProcessData.CalculatedQ2PreCorrectionLR, ProcessData.CalculatedQ2PreCorrectionRL); - return CommErr.None; - } + // static CommErr GetQ2PreCorrectionsFormRest(int threadId, IperlHead ihead, WaterMeter wm, ref string resultStr) + // { + // if (!ProcessData.IsQ2PreCorrectionCalculated) + // { + // ProcessData.IsQ2PreCorrectionCalculated = true; + // /*bool success = iPerlCommunicationSeq.GetQ2PreCorrectionsOrBackups(cfg, wm.WMTypeId(), + // out ProcessData.CalculatedQ2PreCorrectionLR, + // out ProcessData.CalculatedQ2PreCorrectionRL);*/ + // } + // + // resultStr = string.Format("Q2 pre-corrections: LR={0} RL={1}", ProcessData.CalculatedQ2PreCorrectionLR, ProcessData.CalculatedQ2PreCorrectionRL); + // return CommErr.None; + // } static CommErr SetIperlCommMilestoneReached(TestMethod testMethod, ConditionID id, ref string resultStr) { @@ -2734,34 +2713,35 @@ namespace TBF.Rig.TestMethods.iPerlCommunication private async Task ProcessTask(IperlHead iHead, object tag) { string txt = ""; + bool success = false; switch (tag) { case "ReadPCB": - txt = OpticalHeadTest.ReadRequest_PCB(iHead); + txt = iHead.OptoHeadTest.ReadRequest_PCB(); break; case "WriteRequestPort_u8_Customer_Text": - txt = OpticalHeadTest.WriteRequestPort_u8_Customer_Text(iHead); + txt = "Not Supported NOW!";//OpticalHeadTest.WriteRequestPort_u8_Customer_Text(iHead); break; case "OpenSealing": - txt = OpticalHeadTest.OpenSealing(iHead); + txt = "Not Supported NOW!";//OpticalHeadTest.OpenSealing(iHead); break; case "StartTestMode": - txt = OpticalHeadTest.SetTestMode(iHead); + txt = iHead.OptoHeadTest.SetTestMode(ref success); break; case "TurnOffTestMode": - txt = OpticalHeadTest.SetActiveMode(iHead); + txt = iHead.OptoHeadTest.SetActiveMode(ref success); break; case "TurnOffRadio": - txt = OpticalHeadTest.TurnOffRadio(iHead); + txt = "Not Supported NOW!";//OpticalHeadTest.TurnOffRadio(iHead); break; case "SetProductionMode": - txt = OpticalHeadTest.SetProductionMode(iHead); + txt = "Not Supported NOW!";//OpticalHeadTest.SetProductionMode(iHead); break; case "SetRFID": - txt = OpticalHeadTest.SetRfidMode(iHead); + txt = "Not Supported NOW!";//OpticalHeadTest.SetRfidMode(iHead); break; case "SetNFC": - txt = OpticalHeadTest.SetNfcMode(iHead); + txt = "Not Supported NOW!";//OpticalHeadTest.SetNfcMode(iHead); break; } return txt; diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.designer.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs similarity index 99% rename from TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.designer.cs rename to TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs index 25d6628d4..e87740ce6 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.designer.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs @@ -4,7 +4,7 @@ /// namespace TBF.Rig.TestMethods.iPerlCommunication { - partial class iPerlCommunicationFormTestMethod + partial class iPerlCommunicationForm { /// /// Required designer variable. @@ -32,7 +32,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(iPerlCommunicationFormTestMethod)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(iPerlCommunicationForm)); this.wmTextBox2 = new System.Windows.Forms.TextBox(); this.wmLabel2 = new System.Windows.Forms.Label(); this.wmLabel1 = new System.Windows.Forms.Label(); @@ -2585,7 +2585,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.MaximizeBox = false; this.MinimizeBox = false; - this.Name = "iPerlCommunicationFormTestMethod"; + this.Name = "iPerlCommunicationForm"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.Text = "iPerl Communication"; this.TopMost = true; diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.resx b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.resx similarity index 100% rename from TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationFormTestMethod.resx rename to TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.resx diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs index 506dd509a..0e7e78352 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs @@ -10,23 +10,27 @@ using Config.Entities; using TBF.Rig.Generic; using TBF.Resources; using System.Collections.Generic; -using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication; namespace TBF.Rig.TestMethods.iPerlCommunication { - public class iPerlCommunicationParams : TestParamsBase, ITestParams + public class iPerlCommunicationParams : TestParamsBase, IParamsProvider, ITestParams { public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(iPerlCommunicationParams) })[0]; public override XmlSerializer GetSerializer() { return Serializer; } + public string Activity + { + get { return base.Activity; } + set { base.Activity = value; } + } - public string Activity { get; set; } /// Communication activity - public bool SimultWithPrevious { get; set; } - public bool SimultWithNext { get; set; } + /// Communication activity + public bool SimultWithPrevious; + public bool SimultWithNext; public override void InitializeAll() { - Activity = "Read Configuration"; + Activity = iPerlCommunicationForm.ReadConfigurationStr; SimultWithPrevious = false; SimultWithNext = false; } @@ -46,54 +50,56 @@ namespace TBF.Rig.TestMethods.iPerlCommunication if (i == 0) { var retVal = new List(); - retVal.Add(iPerlCommunicationConstants.ReadConfigurationStr); - retVal.Add(string.Format("{0} A0", iPerlCommunicationConstants.SetTestModeStr)); - retVal.Add(string.Format("{0} A4", iPerlCommunicationConstants.SetTestModeStr)); - retVal.Add(iPerlCommunicationConstants.ReadCalibrationStr); - retVal.Add(iPerlCommunicationConstants.ReadCalibrationV4Str); - retVal.Add(iPerlCommunicationConstants.NormalizeCalibrationFactorStr); - retVal.Add(iPerlCommunicationConstants.NormalizeCalibrationV4FactorsStr); - retVal.Add(iPerlCommunicationConstants.GetDefaultQ2CorrectionsStr); - retVal.Add(iPerlCommunicationConstants.ReadQ2CorrectionStr); - retVal.Add(iPerlCommunicationConstants.ResetQ2CorrectionStr); - retVal.Add(iPerlCommunicationConstants.WriteDefaultQ2CorrectionsStr); - retVal.Add(iPerlCommunicationConstants.InitOrReadQ2CorrectionsStr); - retVal.Add(iPerlCommunicationConstants.WriteCalibrationFactorStr); - retVal.Add(iPerlCommunicationConstants.WriteCalibrationV4FactorsStr); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionStr); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionAltStr); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionGreeceStr); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionRLStr); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionLRStr); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionIncl05Str); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionAltIncl05Str); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionPlusIncl05Str); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionPlusAltIncl05Str); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionGreeceIncl05Str); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionRLIncl05Str); - retVal.Add(iPerlCommunicationConstants.WriteQ2CorrectionLRIncl05Str); - retVal.Add(iPerlCommunicationConstants.Q2correctedFromCmd + "Qx"); - retVal.Add(iPerlCommunicationConstants.StrictQ2ErrorCheckStr + "Qx"); - retVal.Add(iPerlCommunicationConstants.Q2correctionCheckCmd); - retVal.Add(iPerlCommunicationConstants.IperlCheckCmd); - retVal.Add(iPerlCommunicationConstants.UpdateBothQ2FactorsTestRLOnlyStr); - retVal.Add(iPerlCommunicationConstants.UpdateBothQ2FactorsTestLROnlyStr); - retVal.Add(iPerlCommunicationConstants.UpdateQ2CorrectionsStr); - retVal.Add(iPerlCommunicationConstants.ConditnlUpdateQ2CorrectionsStr); - retVal.Add(iPerlCommunicationConstants.ConditnlUpdateQ2CorrRLStr); - retVal.Add(iPerlCommunicationConstants.ConditnlUpdateQ2CorrLRStr); + retVal.Add(iPerlCommunicationForm.ReadConfigurationStr); + retVal.Add(iPerlCommunicationForm.ReadSerialNrStr); + retVal.Add(string.Format("{0} A0", iPerlCommunicationForm.SetTestModeStr)); + retVal.Add(string.Format("{0} A4", iPerlCommunicationForm.SetTestModeStr)); + retVal.Add(iPerlCommunicationForm.ReadCalibrationStr); + retVal.Add(iPerlCommunicationForm.ReadCalibrationV4Str); + retVal.Add(iPerlCommunicationForm.NormalizeCalibrationFactorStr); + retVal.Add(iPerlCommunicationForm.NormalizeCalibrationV4FactorsStr); + retVal.Add(iPerlCommunicationForm.GetDefaultQ2CorrectionsStr); + retVal.Add(iPerlCommunicationForm.ReadQ2CorrectionStr); + retVal.Add(iPerlCommunicationForm.ResetQ2CorrectionStr); + retVal.Add(iPerlCommunicationForm.WriteDefaultQ2CorrectionsStr); + retVal.Add(iPerlCommunicationForm.InitOrReadQ2CorrectionsStr); + retVal.Add(iPerlCommunicationForm.WriteCalibrationFactorStr); + retVal.Add(iPerlCommunicationForm.WriteCalibrationV4FactorsStr); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionStr); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionAltStr); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionGreeceStr); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionRLStr); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionLRStr); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionIncl05Str); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionAltIncl05Str); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionPlusIncl05Str); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionPlusAltIncl05Str); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionGreeceIncl05Str); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionRLIncl05Str); + retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionLRIncl05Str); + retVal.Add(iPerlCommunicationSeq.Q2correctedFromCmd + "Qx"); + retVal.Add(iPerlCommunicationSeq.StrictQ2ErrorCheckStr + "Qx"); + retVal.Add(iPerlCommunicationSeq.Q2correctionCheckCmd); + retVal.Add(iPerlCommunicationSeq.IperlCheckCmd); + retVal.Add(iPerlCommunicationForm.UpdateBothQ2FactorsTestRLOnlyStr); + retVal.Add(iPerlCommunicationForm.UpdateBothQ2FactorsTestLROnlyStr); + retVal.Add(iPerlCommunicationForm.UpdateQ2CorrectionsStr); + retVal.Add(iPerlCommunicationForm.ConditnlUpdateQ2CorrectionsStr); + retVal.Add(iPerlCommunicationForm.ConditnlUpdateQ2CorrRLStr); + retVal.Add(iPerlCommunicationForm.ConditnlUpdateQ2CorrLRStr); retVal.Add("Q2 corrected from Q2adj"); retVal.Add("Q2 correction check Q2bc Q2ac"); - retVal.Add(iPerlCommunicationConstants.SetActiveModeStr); + retVal.Add(iPerlCommunicationForm.SetActiveModeStr); + retVal.Add(iPerlCommunicationForm.SetIdleModeStr); retVal.Add("---"); - retVal.Add(iPerlCommunicationConstants.Reset2HzCorrectionStr); - retVal.Add(iPerlCommunicationConstants.Write2HzCorrectionStr); - retVal.Add(iPerlCommunicationConstants.DewaReworkRLStr); - retVal.Add(iPerlCommunicationConstants.DewaReworkLRStr); - retVal.Add(iPerlCommunicationConstants.StartTestingSealedMetersStr); - retVal.Add(iPerlCommunicationConstants.EndTestingSealedMetersStr); - retVal.Add(string.Format("{0} if enabled", iPerlCommunicationConstants.ReadConfigurationStr)); - retVal.Add(string.Format("{0} 80", iPerlCommunicationConstants.SetTestModeStr)); + retVal.Add(iPerlCommunicationForm.Reset2HzCorrectionStr); + retVal.Add(iPerlCommunicationForm.Write2HzCorrectionStr); + retVal.Add(iPerlCommunicationForm.DewaReworkRLStr); + retVal.Add(iPerlCommunicationForm.DewaReworkLRStr); + retVal.Add(iPerlCommunicationForm.StartTestingSealedMetersStr); + retVal.Add(iPerlCommunicationForm.EndTestingSealedMetersStr); + retVal.Add(string.Format("{0} if enabled", iPerlCommunicationForm.ReadConfigurationStr)); + retVal.Add(string.Format("{0} 80", iPerlCommunicationForm.SetTestModeStr)); retVal.Add("iPerl_check prevWorkStep direction q2factors"); for (ConditionID id = ConditionID.A; id < ConditionID.Count; id++) { diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs index 29880f179..81e64bfe4 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs @@ -35,7 +35,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// void OpenIPerlCommForm(iPerlCommunicationSeq myRef, TestMethod method, Test test, iPerlCommunicationParams testParams) { - myRef.modelessDlg = new iPerlCommunicationFormTestMethod(method, test, testParams); + myRef.modelessDlg = new iPerlCommunicationForm(method, test, testParams); myRef.modelessDlg.Show(); } @@ -59,7 +59,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// public IList Execute(Test test, int repetitionNr, TestMethod method, ITestParams testParams) { - TestMethodCfg_IPerl cfgIPerl = method.Cfg as TestMethodCfg_IPerl; + TestMethodCfg cfg = method.Cfg as TestMethodCfg; IList e; /// Events from currently running operations checkUiOp = new Operations.CheckUIOp(true); /// Runs in more then one state @@ -68,7 +68,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication processDataLoggingOp = new TBF.Rig.Operations.ProcessDataLoggingOp(processDataLogger, this, false); string cmd; - if (testParams.Activity.ToLower().Equals(cmd = iPerlCommunicationFormTestMethod.GetDefaultQ2CorrectionsStr.ToLower())) + if (testParams.Activity.ToLower().Equals(cmd = iPerlCommunicationForm.GetDefaultQ2CorrectionsStr.ToLower())) { TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 }); Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted)); @@ -87,9 +87,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication }*/ #endif - if (cfgIPerl.UseWebService) + if (cfg.UseWebService) { - IsQ2PreCorrectionCalculated = GetQ2PreCorrectionsOrBackups(cfgIPerl, wmType, out CalculatedQ2PreCorrectionLR, out CalculatedQ2PreCorrectionRL); + IsQ2PreCorrectionCalculated = GetQ2PreCorrectionsOrBackups(cfg, wmType, out CalculatedQ2PreCorrectionLR, out CalculatedQ2PreCorrectionRL); } /// Generate test results @@ -106,7 +106,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication { if (mtr.TestRslt == tstRslt) { - mtr.Passed = !cfgIPerl.UseWebService || IsQ2PreCorrectionCalculated; + mtr.Passed = !cfg.UseWebService || IsQ2PreCorrectionCalculated; mtr.TestDone = true; break; } @@ -271,7 +271,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, tstRslt)); allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file - if (wrongMetersCount >= cfgIPerl.IperlCheckErrorsToStop) + if (wrongMetersCount >= cfg.IperlCheckErrorsToStop) { State.Create("iPerlCommunicationSeq : Show check result") .AddOperation(new Operations.LargeMessageBoxOp(message)) @@ -409,12 +409,12 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// /// Read default Q2 correction factors from a REST service (= Web service). /// - /// iPerlCommunication component configuration + /// iPerlCommunication component configuration /// Water meter type (WZ Typ) /// Default Q2 correction LR /// Default Q2 correction RL /// true when successful - static bool ReadCorrectionsFromWebService(TestMethodCfg_IPerl cfgIPerl, int wmType, out int q2PreCorrectionLR, out int q2PreCorrectionRL) + static bool ReadCorrectionsFromWebService(TestMethodCfg cfg, int wmType, out int q2PreCorrectionLR, out int q2PreCorrectionRL) { if (wmType == 0) { @@ -426,9 +426,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication try { - GetQ2PreCorrectionClient client = new GetQ2PreCorrectionClient(cfgIPerl.BaseUrl); + GetQ2PreCorrectionClient client = new GetQ2PreCorrectionClient(cfg.BaseUrl); client.GetToken("ReadUser", "sensus", "https://deluh1web03.world.fluidtechnology.net/SensusCore/api/v1/Locations/1/Login2").Wait(); - Q2PreCorrection response = client.GetQ2Correction(string.Format(cfgIPerl.RelativeUrl, wmType)).Result; + Q2PreCorrection response = client.GetQ2Correction(string.Format(cfg.RelativeUrl, wmType)).Result; if (response != null && response.AreDataCalculated) { q2PreCorrectionLR = response.CorrLR; @@ -456,15 +456,15 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// /// Obtain Q2 correction factors from a REST service or from local settings (stored backup values) /// - /// iPerlCommunication component configuration + /// iPerlCommunication component configuration /// Water meter type (WZ Typ) /// Default Q2 correction LR /// Default Q2 correction RL /// true when successful - public static bool GetQ2PreCorrectionsOrBackups(TestMethodCfg_IPerl cfgIPerl, int wmType, out int q2PreCorrectionLR, out int q2PreCorrectionRL) + public static bool GetQ2PreCorrectionsOrBackups(TestMethodCfg cfg, int wmType, out int q2PreCorrectionLR, out int q2PreCorrectionRL) { /// Get Q2 pre-correction values from REST service - bool restOK = ReadCorrectionsFromWebService(cfgIPerl, wmType, out q2PreCorrectionLR, out q2PreCorrectionRL); + bool restOK = ReadCorrectionsFromWebService(cfg, wmType, out q2PreCorrectionLR, out q2PreCorrectionRL); /// Store / load Q2 pre-correction values Point storedValue; diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ConfigStruct.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ConfigStruct.cs index ee19bd1e4..71b928a7f 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ConfigStruct.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ConfigStruct.cs @@ -3,264 +3,203 @@ /// using System; using System.IO; +using System.Text; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { public class ConfigStruct { - public const int Length = 32; + //public const int Length = 32; // dynamic - public Byte Version; /// 0: 1 byte - public MeterState MeterState; /// 1: 1 byte - public UInt32 TargetTimeVeryLowBatt; /// 2: 4 bytes in seconds - public UInt32 TargetTimeLowBatt; /// 6: 4 bytes, in seconds - public UInt32 TestModeTime; /// 10: 4 bytes, Max. test mode time in seconds - public UInt16 EmptyPipeThreshold; /// 14: 2 bytes - public byte[] PCBNumber; /// 16: 5 bytes - public byte TestModeConfig; /// 21: 1 byte - public UInt32 RadioAddress; /// 22: 4 bytes - public UInt16 TempCalibration; /// 26: 2 bytes - public UInt16 AlarmMask; /// 28: 2 bytes, Default 0xA3F7 - public UInt16 ConfigCheckSum; /// 30: 2 bytes + //public Byte Version; // 0: 1 byte + public string PCBNumberString; // dynamic + public ProtocolStatuses StatusMode; // byte + public DiagnosticLedState OpthoStatusMode;// byte + public string Unit; //dynamic + public string Version; // dynamic + public ConfigStruct() { - PCBNumber = new byte[5]; } - public byte[] ToByteArray() + //Optho test status mode + public DiagnosticLedState TestModeConfig { - byte[] result = new byte[Length]; - - result[0] = Version; - result[1] = (byte)MeterState; - - result[2] = (byte)(TargetTimeVeryLowBatt & 0x000000FF); - result[3] = (byte)((TargetTimeVeryLowBatt >> 8) & 0x000000FF); - result[4] = (byte)((TargetTimeVeryLowBatt >> 16) & 0x000000FF); - result[5] = (byte)((TargetTimeVeryLowBatt >> 24) & 0x000000FF); - - result[6] = (byte)(TargetTimeLowBatt & 0x000000FF); - result[7] = (byte)((TargetTimeLowBatt >> 8) & 0x000000FF); - result[8] = (byte)((TargetTimeLowBatt >> 16) & 0x000000FF); - result[9] = (byte)((TargetTimeLowBatt >> 24) & 0x000000FF); - - result[10] = (byte)(TestModeTime & 0x000000FF); - result[11] = (byte)((TestModeTime >> 8) & 0x000000FF); - result[12] = (byte)((TestModeTime >> 16) & 0x000000FF); - result[13] = (byte)((TestModeTime >> 24) & 0x000000FF); - - result[14] = (byte)(EmptyPipeThreshold & 0x00FF); - result[15] = (byte)((EmptyPipeThreshold >> 8) & 0x00FF); - - result[16] = PCBNumber[0]; - result[17] = PCBNumber[1]; - result[18] = PCBNumber[2]; - result[19] = PCBNumber[3]; - result[20] = PCBNumber[4]; - - result[21] = TestModeConfig; - - result[22] = (byte)(RadioAddress & 0x000000FF); - result[23] = (byte)((RadioAddress >> 8) & 0x000000FF); - result[24] = (byte)((RadioAddress >> 16) & 0x000000FF); - result[25] = (byte)((RadioAddress >> 24) & 0x000000FF); - - result[26] = (byte)(TempCalibration & 0x00FF); - result[27] = (byte)((TempCalibration >> 8) & 0x00FF); - - result[28] = (byte)(AlarmMask & 0x00FF); - result[29] = (byte)((AlarmMask >> 8) & 0x00FF); - - result[30] = (byte)(ConfigCheckSum & 0x00FF); - result[31] = (byte)((ConfigCheckSum >> 8) & 0x00FF); - - return result; + get { return OpthoStatusMode; } } - - /// - /// Create a configuration structure from a complete byte array - /// - /// A complete byte array data - /// ConfigStruct or null when byte array was not complete - public static ConfigStruct FromByteArray(byte[] data) + //Activity test status mode + public ProtocolStatuses MeterState { - if (data.Length != Length) return null; - - ConfigStruct result = new ConfigStruct(); - - result.Version = data[0]; - result.MeterState = (MeterState)data[1]; - result.TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2]; - result.TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6]; - result.TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10]; - result.EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]); - result.PCBNumber[0] = data[16]; - result.PCBNumber[1] = data[17]; - result.PCBNumber[2] = data[18]; - result.PCBNumber[3] = data[19]; - result.PCBNumber[4] = data[20]; - result.TestModeConfig = data[21]; - result.RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22]; - result.TempCalibration = (UInt16)(data[27] * 256 + data[26]); - result.AlarmMask = (UInt16)(data[29] * 256 + data[28]); - result.ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]); - - return result; + get + { + return StatusMode; + } } - - /// - /// Update the configuration structure from an incomplete byte array - /// - /// Offset of byte array data in ConfigStruct - /// Byte array data - /// true when successful, false when data are not appropriate - public bool Update(int offset, byte[] data) - { - if (offset == 0 && data.Length == 2) - { - /// iPerl mode of function - Version = data[0]; - MeterState = (MeterState)data[1]; - return true; - } - else if (offset == 0 && data.Length == 4) - { - /// iPerl mode of function and extra 2 bytes - Version = data[0]; - MeterState = (MeterState)data[1]; - return true; - } - else if (offset == 21 && data.Length == 1) - { - /// TestModeConfig value - TestModeConfig = data[21 - offset]; - return true; - } - else if (offset == 0 && data.Length == Length) - { - /// Complete ConfigStruct - Version = data[0]; - MeterState = (MeterState)data[1]; - TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2]; - TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6]; - TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10]; - EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]); - PCBNumber[0] = data[16]; - PCBNumber[1] = data[17]; - PCBNumber[2] = data[18]; - PCBNumber[3] = data[19]; - PCBNumber[4] = data[20]; - TestModeConfig = data[21]; - RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22]; - TempCalibration = (UInt16)(data[27] * 256 + data[26]); - AlarmMask = (UInt16)(data[29] * 256 + data[28]); - ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]); - return true; - } - else - return false; - } + /// /// Returns PCB number string (12 characters, 12 decimal digits) /// /// PCB number STRING - public string GetPcbNrString() - { - return PCBNumber2String(this.PCBNumber); - } + public string GetPcbNrString(){ + return PCBNumberString; + } - /// - /// Converts PCBNumber to string (12 characters, 12 decimal digits) - /// - /// - /// PCB number string - public static string PCBNumber2String(byte[] pcbNumber) - { - if (pcbNumber.Length != 5) return string.Empty; - Int64 number = 0; - for (int i = 4; i >= 0; i--) - { - number = 256 * number + (Int64)pcbNumber[i]; - } - - return number.ToString(); - } + public string GetStatusModeString() + { + return string.Format( + "Config: StatusMode={0}", + StatusMode + ); + } + + public string GetActiveModeString() + { + return string.Format( + "Config: StatusMode={0}, OpthoStatusMode={1}", + StatusMode, + OpthoStatusMode + ); + } public override string ToString() { - return string.Format("Config: V{0} State={1} VLoBattT={2}s LoBattT={3}s TestModeT={4}s EPThld={5} PCB#={6} TMCfg={7} RadioAddr={8} TempCalib={9} AlarmMask={10} CfgCheckSum={11}", - Version, - MeterState, - TargetTimeVeryLowBatt, - TargetTimeLowBatt, - TestModeTime, - EmptyPipeThreshold, - GetPcbNrString(), - TestModeConfig.ToString("X2"), - RadioAddress, - TempCalibration, - AlarmMask.ToString("X4"), - ConfigCheckSum.ToString("X4")); + return string.Format( + "Config: PCB#={0} StatusMode={1} Unit={2} V{3}", + + GetPcbNrString(), + StatusMode, + Unit, + Version + ); } public string ToString(int sel) { - return string.Format("{1} PCB#={6} TMCfg={7}", - Version, - MeterState, - TargetTimeVeryLowBatt, - TargetTimeLowBatt, - TestModeTime, - EmptyPipeThreshold, - GetPcbNrString(), - TestModeConfig.ToString("X2"), - RadioAddress, - TempCalibration, - AlarmMask.ToString("X4"), - ConfigCheckSum.ToString("X4")); + return string.Format( + "Config: PCB#={0} StatusMode={1} Unit={2} V{3}", + + GetPcbNrString(), + StatusMode, + Unit, + Version + ); } public virtual void WriteBinary(BinaryWriter writer) { - writer.Write(Version); - writer.Write((byte)MeterState); - writer.Write(TargetTimeVeryLowBatt); - writer.Write(TargetTimeLowBatt); - writer.Write(TestModeTime); - writer.Write(EmptyPipeThreshold); - writer.Write(PCBNumber[0]); - writer.Write(PCBNumber[1]); - writer.Write(PCBNumber[2]); - writer.Write(PCBNumber[3]); - writer.Write(PCBNumber[4]); - writer.Write(TestModeConfig); - writer.Write(RadioAddress); - writer.Write(TempCalibration); - writer.Write(AlarmMask); - writer.Write(ConfigCheckSum); + if (writer == null) + throw new ArgumentNullException(nameof(writer)); + + // ---- Marker ---- + writer.Write((byte)0x11); + + // ---- Version ---- + if (!string.IsNullOrEmpty(Version)) + { + // Convert string to bytes (UTF8 is standard) + byte[] versionBytes = Encoding.UTF8.GetBytes(Version); + // 1) write length + writer.Write(versionBytes.Length); + // 2) write string bytes + writer.Write(versionBytes); + //writer.Write(Version); + } + else + { + writer.Write(0);//Length + } + + // ---- StatusMode ---- + writer.Write((byte)StatusMode); + + // ---- PCB Number ---- + if (!string.IsNullOrEmpty(PCBNumberString)) + { + byte[] PCBNumberStringBytes = Encoding.UTF8.GetBytes(PCBNumberString); + // 1) write length + writer.Write(PCBNumberStringBytes.Length); + // 2) write string bytes + writer.Write(PCBNumberStringBytes); + } + else + { + writer.Write(0); //Length + } + + // ---- Unit ---- + if (!string.IsNullOrEmpty(Unit)) + { + // Convert string to bytes (UTF8 is standard) + byte[] unitBytes = Encoding.UTF8.GetBytes(Unit); + // 1) write length + writer.Write(unitBytes.Length); + // 2) write string bytes + writer.Write(unitBytes); + //writer.Write(Version); + } + else + { + writer.Write(0); //Length + } + } public virtual void ReadBinary(BinaryReader reader) { - Version = reader.ReadByte(); - MeterState = (MeterState)reader.ReadByte(); - TargetTimeVeryLowBatt = reader.ReadUInt32(); - TargetTimeLowBatt = reader.ReadUInt32(); - TestModeTime = reader.ReadUInt32(); - EmptyPipeThreshold = reader.ReadUInt16(); - PCBNumber[0] = reader.ReadByte(); - PCBNumber[1] = reader.ReadByte(); - PCBNumber[2] = reader.ReadByte(); - PCBNumber[3] = reader.ReadByte(); - PCBNumber[4] = reader.ReadByte(); - TestModeConfig = reader.ReadByte(); - RadioAddress = reader.ReadUInt32(); - TempCalibration = reader.ReadUInt16(); - AlarmMask = reader.ReadUInt16(); - ConfigCheckSum = reader.ReadUInt16(); + if (reader == null) + throw new ArgumentNullException(nameof(reader)); + + // ---- Marker ---- + byte marker = reader.ReadByte(); + if (marker != 0x11) + throw new InvalidDataException($"Invalid config marker: 0x{marker:X2}"); + + // ---- Version ---- + int versionLength = reader.ReadInt32(); + if (versionLength < 0) + throw new InvalidDataException("Invalid Version length."); + + byte[] versionBytes = reader.ReadBytes(versionLength); + if (versionBytes.Length != versionLength) + throw new EndOfStreamException("Unexpected end of stream while reading Version."); + + Version = versionLength > 0 + ? Encoding.UTF8.GetString(versionBytes) + : string.Empty; + + // ---- StatusMode ---- + StatusMode = (ProtocolStatuses)reader.ReadByte(); + + // ---- PCB Number ---- + int pcbLength = reader.ReadInt32(); + if (pcbLength < 0) + throw new InvalidDataException("Invalid PCB number length."); + + byte[] pcbBytes = reader.ReadBytes(pcbLength); + if (pcbBytes.Length != pcbLength) + throw new EndOfStreamException("Unexpected end of stream while reading PCB number."); + + PCBNumberString = pcbLength > 0 + ? Encoding.UTF8.GetString(pcbBytes) + : string.Empty; + + // ---- Unit ---- + int unitLength = reader.ReadInt32(); + if (unitLength < 0) + throw new InvalidDataException("Invalid Unit length."); + + byte[] unitBytes = reader.ReadBytes(unitLength); + if (unitBytes.Length != unitLength) + throw new EndOfStreamException("Unexpected end of stream while reading Unit."); + + Unit = unitLength > 0 + ? Encoding.UTF8.GetString(unitBytes) + : string.Empty; } } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/FlowDirectionDetection.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/FlowDirectionDetection.cs index 37745792e..2e23e3f6d 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/FlowDirectionDetection.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/FlowDirectionDetection.cs @@ -11,40 +11,35 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { private static readonly ILog log = LogManager.GetLogger(typeof(IperlHead)); - const int FIFO_SIZE = 64; /// 8 sec. @ 8Hz - const double MAX_OPTO_DROPOUT = 4.5; /// sec. - + const int FIFO_SIZE = 64; // 8 sec @ 8Hz + const double MAX_OPTO_DROPOUT = 4.5; // sec - Int64[] volumeRawFifo; /// Volume FIFO buffer - Int64[] timestampFifo; /// Timestamp FIFO buffer + private readonly double[] volumeRawFifo; + private readonly double[] timestampFifo; // centered timestamps - int fifoCount; /// Number of valid FIFO items - int fifoIx; /// Index of the next FIFO item - DateTime lastFifoWriteTime; /// Time of the last write to FIFO + private int fifoCount; + private int fifoIx; + private DateTime lastFifoWriteTime; - /// - /// Sums for linear regression calculation - /// - decimal sumXX; - decimal sumX; - decimal sumXY; - decimal sumY; - decimal N; + // regression sums (double is ideal here) + private double sumXX; + private double sumX; + private double sumXY; + private double sumY; - double minSlope; /// max. slope of the regressed line, always positive or 0 - double maxSlope; /// min. slope of the regressed line, always negative or 0 + private double minSlope; + private double maxSlope; + + // timestamp centering for numerical stability + private double firstTimestamp = double.NaN; public FlowDirectionDetection() { - volumeRawFifo = new Int64[FIFO_SIZE]; - timestampFifo = new Int64[FIFO_SIZE]; + volumeRawFifo = new double[FIFO_SIZE]; + timestampFifo = new double[FIFO_SIZE]; ClearFifo(); } - - /// - /// Clear FIFO data - /// public void ClearFifo() { fifoCount = 0; @@ -55,94 +50,93 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead sumX = 0; sumXY = 0; sumY = 0; - N = 0; minSlope = 0; maxSlope = 0; + firstTimestamp = double.NaN; } - /// - /// Write data to FIFO + /// Add sample to rolling FIFO and update regression sums /// - /// Volume - /// Time stamp - public void WriteToFifo(Int64 volumeRaw, Int64 timestamp) + public void WriteToFifo(double volumeRaw, double timestamp) { - /// - /// Update sums for linear regression calculation - /// + // establish time origin (CRITICAL for double precision) + if (double.IsNaN(firstTimestamp)) + firstTimestamp = timestamp; + + double x = timestamp - firstTimestamp; // centered time + double y = volumeRaw; + + // remove oldest sample if buffer full if (fifoCount == FIFO_SIZE) { - /// Buffer is already full, the oldest item will be re-written - sumXX -= timestampFifo[fifoIx] * timestampFifo[fifoIx]; - sumX -= timestampFifo[fifoIx]; - sumXY -= timestampFifo[fifoIx] * volumeRawFifo[fifoIx]; - sumY -= volumeRawFifo[fifoIx]; - N--; - } - sumXX += timestamp * timestamp; - sumX += timestamp; - sumXY += timestamp * volumeRaw; - sumY += volumeRaw; - N++; + double oldX = timestampFifo[fifoIx]; + double oldY = volumeRawFifo[fifoIx]; + + sumXX -= oldX * oldX; + sumX -= oldX; + sumXY -= oldX * oldY; + sumY -= oldY; + } + else + { + fifoCount++; + } + + // add new sample + sumXX += x * x; + sumX += x; + sumXY += x * y; + sumY += y; + + // store sample + timestampFifo[fifoIx] = x; + volumeRawFifo[fifoIx] = y; - /// - /// Save new values to FIFO - /// - volumeRawFifo[fifoIx] = volumeRaw; - timestampFifo[fifoIx] = timestamp; fifoIx = (fifoIx + 1) % FIFO_SIZE; - fifoCount = Math.Min(fifoCount + 1, FIFO_SIZE); lastFifoWriteTime = DateTime.Now; } - - /// - /// Determine whether there are enough recent FIFO data - /// - /// true when data valid public bool AreFifoDataValid() { - return (DateTime.Now.Subtract(lastFifoWriteTime).TotalSeconds <= MAX_OPTO_DROPOUT) && (fifoCount == FIFO_SIZE); + return (DateTime.Now.Subtract(lastFifoWriteTime).TotalSeconds <= MAX_OPTO_DROPOUT) + && (fifoCount == FIFO_SIZE); } - - /// - /// Verify whether the flow direction is correct - /// - /// OptoHeadState.OptoAndDirOK, OptoHeadState.OptoNok or OptoHeadState.DirNok public OptoHeadState CheckFlowDirection(Counting counting, string iPerlHeadName) { - if (!AreFifoDataValid()) return OptoHeadState.OptoNok; + if (!AreFifoDataValid()) + return OptoHeadState.OptoNok; try { - decimal numer = N * sumXY - sumX * sumY; - decimal denom = N * sumXX - sumX * sumX; + double N = fifoCount; - if (denom == 0) return OptoHeadState.DirNok; + double numer = N * sumXY - sumX * sumY; + double denom = N * sumXX - sumX * sumX; + + if (Math.Abs(denom) < 1e-12) + return OptoHeadState.DirNok; + + double slope = numer / denom; - /// Calculate the slope of the regressed line, determine min. and max. - double slope = (double)(numer / denom); if (slope > maxSlope) maxSlope = slope; if (slope < minSlope) minSlope = slope; - if ( counting == Counting.Arbitrary || + if (counting == Counting.Arbitrary || (counting == Counting.Positive && maxSlope > Math.Abs(2 * minSlope)) || (counting == Counting.Negative && minSlope < -Math.Abs(2 * maxSlope))) { return OptoHeadState.OptoAndDirOK; } - else - { - return OptoHeadState.DirNok; - } + + return OptoHeadState.DirNok; } - catch (Exception) + catch (Exception ex) { - log.ErrorFormat("{0} : CheckFlowDirection() failed", iPerlHeadName); - return OptoHeadState.DirNok; /// ??? + log.ErrorFormat("{0} : CheckFlowDirection() failed: {1}", iPerlHeadName, ex); + return OptoHeadState.DirNok; } } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs index 2df3887c2..b4502c2ab 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs @@ -6,28 +6,36 @@ using System.IO; using System.IO.Ports; using log4net; using Common; -using Common.Iperl; using Config.Entities; using TBF.Rig.Generic; using TBF.Rig.GenericDevices; using Sensus.iPerl.NfcHandler; using NHibernate; -using Renci.SshNet; using System.Linq; -using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.Linq; // This line is correct and does not need to be changed. -using System.Windows; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using TBF.Rig.TestMethods.iPerlCommunication.communication; // This line is correct and does not need to be changed. +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.utils; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger; +using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils; +using OptoTelegramFlags = TBF.Rig.TestMethods.iPerlCommunication.common.OptoTelegramFlags; +using OptoTelegramRaw = TBF.Rig.TestMethods.iPerlCommunication.common.OptoTelegramRaw; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common; + + namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { /// /// This component = instance of this class is a placeholder for a combined main watermeter /// - public class IperlHead : ComponentBase, IDevice,IRegReaderDatastream, ISessionDataMngmnt, IOperation, ISmartReader + public class IperlHead : ComponentBase, IDevice,IRegReaderDatastream, ISessionDataMngmnt, IOperation, IRegReaderSmart { private static readonly ILog log = LogManager.GetLogger(typeof(IperlHead)); + private static readonly ILog logStream = LogManager.GetLogger("StreamData"); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } #if TURA_SPECIAL @@ -38,63 +46,49 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead public const string OptoDataDirectory = "C:\\TBF\\ProcessData"; public const int StartOptoDataCount = OptoDataBufferSize / 2; public const int EndOptoDataCount = OptoDataBufferSize - StartOptoDataCount; - public const int StartEndFilterSamplesCount2 = 20; /// StartEndFilterSamplesCount = 2 * StartEndFilterSamplesCount2 + 1 + public const int StartEndFilterSamplesCount2 = 2; //20 /// StartEndFilterSamplesCount = 2 * StartEndFilterSamplesCount2 + 1 public const int FeatureVectorSize = 9; + private OptoHeadTest _optoHeadTest; + + public OptoHeadTest OptoHeadTest + { + get + { + if (_optoHeadTest == null) + _optoHeadTest = new OptoHeadTest(this); + return _optoHeadTest; + } + set { _optoHeadTest = value; } + } + readonly IperlHeadCfg iperlHeadCfg; - public int RfidComPortNr { get { return iperlHeadCfg.RfidComPortNr; } } - public bool CommFailed { get; set; } - public bool Disabled { get; set; } public int OptoComPortNr { get { return iperlHeadCfg.OptoComPortNr; } } public int MuxBoardNrOrGroup14 { get { return iperlHeadCfg.MuxBoardNr; } } public int Group { get { return iperlHeadCfg.Group; } } public iPerlHead.MeterType MeterType { get { return iperlHeadCfg.MeterType; } } - public string CommInterface { get { return iperlHeadCfg.CommunicationInterface.ToDescription(); } } + public CommunicationInterface CommInterface { get { return iperlHeadCfg.CommunicationInterface; } } - - static int? ExtractPreferredNumber(string input) - { - if (string.IsNullOrEmpty(input)) - return null; - - // Match all sequences of digits - var matches = Regex.Matches(input, @"\d+"); - if (matches.Count == 0) - return null; - - // Prefer the last one if there are multiple - string selected = matches[matches.Count - 1].Value; // last element - return int.Parse(selected); - } - - /// - /// this is a hack to get the position from the name - /// name must consist only with digit describing order of the meter - /// public int Position { get { - //BUMI this is a hack to get the position from the name - // but it is not working for all cases !!!!! - // - what stupid prediction (what index should be used?? see: 'S4iPerl1' or ...) - - int? extractPreferredNumber = ExtractPreferredNumber(Name); - if (extractPreferredNumber.HasValue) - return extractPreferredNumber.Value; - return 0; + int firstDigitPos = Name.IndexOfAny(new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }); + int position; + return (firstDigitPos < 0) ? 0 : (int.TryParse(Name.Substring(firstDigitPos), out position) ? position : 0); } } public RegisterReaderType RegisterReaderType { get { return RegisterReaderType.DataStream; } } public double PulsesPerLtr { - get { return 1000.0; } - set {PulsesPerLtr = value; } + get { return 1000.0; } + set { } } public double LtrsPerPulse { get { return 1 / PulsesPerLtr; } } public string QuantityUnits { get; set; } + public double CalibTarget { get { return iperlHeadCfg.ProcParams.CalibTarget; } } public ushort FactorLimitLo { get { return (ushort)iperlHeadCfg.ProcParams.FactorLimitLo; } } public ushort FactorLimitHi { get { return (ushort)iperlHeadCfg.ProcParams.FactorLimitHi; } } @@ -118,7 +112,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead simulatedPcbNr = value; } } - + + public bool Disabled; + public bool CommFailed; public int ResultCode; @@ -132,8 +128,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// /// Passed to OptoTelegramRaw.UpdateFromString(...) /// - Int64 volumeRawExtLast; - Int64 timestampExtLast; + double volumeRawExtLast; + double timestampExtLast; FlowDirectionDetection flowDirectionDetection; @@ -190,13 +186,23 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// public int WMPulses { get { return wmPulses; } } public int WMRefPulses { get { return wmRefPulses; } } - public double BeginWMState { get { return beginWMState; } set { beginWMState = value; }} - public double EndWMState { get { return endWMState; } set { endWMState = value;} } - public double WMVolume { get { return wmVolume; } } - public double WMTestTime { get { return wmTestTime; } } + public double BeginWMState { get { return ResolveNaNDouble(beginWMState); } } + public double EndWMState { get { return ResolveNaNDouble(endWMState); } } + public double WMVolume { get { return ResolveNaNDouble(wmVolume); } } + public double WMTestTime { get { return ResolveNaNDouble(wmTestTime); } } string simulatedPcbNr = null; + double ResolveNaNDouble(double d) + { + if (Double.IsNaN(d)) + { + return 0.0; + } + else + return d; + } + int wmPulses; int wmRefPulses; double beginWMState; @@ -269,7 +275,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead const double C = B * 60.0; /// Raw units per hour, 480 double D = C / A; /// ml correction per hour double F = D / (nominalTestFlowLph * 10.0); /// Error corrected with 8 Raw Units per minute [%] - double G = F / B; /// Error corrected with 1 Raw Unit per minute [%] + double G = F / B; /// Error corrected with 1 Raw Units per minute [%] /// Do not change the factor for an invalid measurement (q2adjResult.VolumeMeter == 0) double q2CorrectionFactor = (Math.Abs(currentQ2Result.VolumeMeter) <= float.Epsilon) ? Convert.ToDouble(currentFactor) : @@ -389,7 +395,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// /// Timestamp from the opto telegram /// - private Int64 lastTimestamp; + private double lastTimestamp; private double timestampSec; private double timestampSec0; @@ -412,14 +418,14 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// /// Volume of water from the opto telegram /// - private Int64 lastVolumeRaw; /// Last read raw volume + private double lastVolumeRaw; /// Last read raw volume private double volumeLtr; private double volumeLtr0; /// Test start volume for metrology in liters public double VolumeLtrStart { - get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); } + get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), 0); } } /// Test end volume for metrology in liters public double VolumeLtrEnd @@ -473,7 +479,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// Check whether head is connected, working try { - OpenOptoSerialPort($"COM{iperlHeadCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, Handshake.None); + OpenOptoSerialPort($"COM{iperlHeadCfg.OptoComPortNr}", 38400, Parity.None, 8, StopBits.One, Handshake.None); CloseOptoSerialPort(); log.FatalFormat($"{Name} initialized: {this}"); } @@ -618,10 +624,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { ResultCode = 0; - volumeLtr = 0; - volumeLtr0 = 0; - timestampSec = 0; - timestampSec0 = 0; + volumeLtr = Double.NaN; + volumeLtr0 = Double.NaN; + timestampSec = Double.NaN; + timestampSec0 = Double.NaN; extraDataPath = null; @@ -887,34 +893,63 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead endWMState = volumeLtr; wmVolume = Math.Abs(endWMState - beginWMState); wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5); + log.Debug("wmPulses = " + wmPulses + "wmVolume = " + wmVolume + "PulsesPerLtr = " + PulsesPerLtr + ""); wmRefPulses = StateMachine.ControlBoardMain.RefPulses; wmTestTime = timestampSec - timestampSec0; } - private void OpenOptoSerialPort(string comPort, int baudRate, Parity parity, int dataBits, StopBits stopBit, Handshake handshake) + private void OpenOptoSerialPort( + string comPort, + int baudRate, + Parity parity, + int dataBits, + StopBits stopBit, + Handshake handshake, + int openTimeoutMs = 3000) { if (DebugLevel == DebugMode.FailureDuringOperation) DebugLevel = DebugMode.Normal; - if (DebugLevel == DebugMode.Normal) - { - /// Open serial port: 9600 Bd, 8 data bits, 1 stop bit, no parity - try - { - CloseOptoSerialPort(); - optoSerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBit); - optoSerialPort.Handshake = handshake; - optoSerialPort.Open(); - log.FatalFormat($"{Name} OptoPort opened: {this}"); - } - catch (Exception ex) - { - log.FatalFormat($"{Name} OptoPort - error opening port: {this}" + Environment.NewLine + ex.Message); - throw ex; - } - } - else + if (DebugLevel != DebugMode.Normal) { optoSerialPort = null; log.FatalFormat($"{Name} OproPort simulated: {this}"); + return; + } + + try + { + CloseOptoSerialPort(); + + var port = new SerialPort(comPort, baudRate, parity, dataBits, stopBit) + { + Handshake = handshake, + NewLine = "\r\n", + Encoding = Encoding.ASCII + }; + + port.ReadTimeout = 5000; + port.WriteTimeout = 5000; + port.DtrEnable = true; + port.RtsEnable = true; + + // Run Open() on separate task + var openTask = Task.Run(() => port.Open()); + + if (!openTask.Wait(openTimeoutMs)) + { + port.Dispose(); + throw new TimeoutException( + $"Opening serial port {comPort} timed out after {openTimeoutMs} ms."); + } + + optoSerialPort = port; + + log.FatalFormat($"{Name} OptoPort opened: {this}"); + } + catch (Exception ex) + { + log.FatalFormat($"{Name} OptoPort - error opening port: {this}" + + Environment.NewLine + ex.Message); + throw; // NEVER use "throw ex;" (destroys stack trace) } } @@ -937,7 +972,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { try { - OpenOptoSerialPort($"COM{iperlHeadCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, Handshake.None); + OpenOptoSerialPort($"COM{iperlHeadCfg.OptoComPortNr}", 38400, Parity.None, 8, StopBits.One, Handshake.None); } catch (Exception) { @@ -961,18 +996,6 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead dataStreamState = DataStreamState.ProcessAndSave; } - public void SetCommunicationInterface(string commInterface) - { - CommunicationInterface com = (CommunicationInterface)Enum.Parse(typeof(CommunicationInterface), commInterface); - SetCommunicationInterface(com); - } - - public void SetCommunicationInterface(RegisterReaders.CommonRR.CommunicationInterface commInterface) - { - CommunicationInterface com = (CommunicationInterface)Enum.Parse(typeof(CommunicationInterface), commInterface.ToDescription()); - SetCommunicationInterface(com); - } - /// /// Returns true when processing and saving datastream data is in progress /// @@ -981,11 +1004,6 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead return dataStreamState == DataStreamState.ProcessAndSave; } - void ISmartReader.SetRfidInterface() - { - SetRfidInterface(); - } - /// /// Stop processing and saving datastream data /// @@ -1001,121 +1019,95 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead bool synchronized; bool synchronized2; string partOfTelegram; - private RegisterReaders.CommonRR.CommunicationInterface _commInterface; - private string _commInterface1; + + DiagnosticLedParser parser = new DiagnosticLedParser(DiagnosticLedState.State4); /// /// Reads opto-datastream via serial port. Invoked from RunDeviceBefore() /// - /// Telegram description: - /// AAAAAA[tab]BBBB[tab]CCCC[tab]DDDDDD[tab]EEEE[tab]FFFFFFFF[tab]GG[cr][lf] (42 bytes) - /// Example: - /// FFFFFE 51EA 0000 65324E 0087 F6319DFF 86 - /// FFDD3A 51F9 0000 65324E 0088 F631A60B 45 - /// ... - /// - /// OptoState.Read or OptoState.Flush - void ReadOptoData(DataStreamState optoState) - { + /// Telegram description: + /// AAAAAA[tab]BBBB[tab]CCCC[tab]DDDDDD[tab]EEEE[tab]FFFFFFFF[tab]GG[cr][lf] (42 bytes) + /// Example: + /// FFFFFE 51EA 0000 65324E 0087 F6319DFF 86 + /// FFDD3A 51F9 0000 65324E 0088 F631A60B 45 + /// ... + /// + /// OptoState.Read or OptoState.Flush + void ReadOptoData(DataStreamState optoState) + { if (optoSerialPort is null) return; + lock (this) { - int nrBytes = optoSerialPort.BytesToRead; - if (nrBytes > 0) + try { - char[] buffer = new char[nrBytes]; - optoSerialPort.Read(buffer, 0, nrBytes); - string received = new string(buffer); - - string allRcvd = partOfTelegram + received; - - while (true) + int nrBytes = optoSerialPort.BytesToRead; + if (nrBytes > 0) { - int pos = allRcvd.IndexOf("\r\n"); + // This will now wait max 3 seconds (ReadTimeout) + string line = optoSerialPort.ReadLine(); - if (pos < 0) + byte[] bytes = optoSerialPort.Encoding.GetBytes(line); + log.Debug("ComPort: " + OptoComPortNr + " OPTHO RX ← " + HexFormatter.ToSerialHex(bytes)); + + if (optoState == DataStreamState.ProcessAndSave) { - /// No CR+LF found, wait for more characters in the next invocation - partOfTelegram = allRcvd; - return; + DiagnosticLedState4Data data = + (DiagnosticLedState4Data)parser.ParseLine(line, false); + + int bufferIx = BufferIdx(optoDataCount); + + if (synchronized) + { + optoData[bufferIx].Counter = optoDataCount; + optoData[bufferIx].SetFlags(OptoTelegramFlags.SyncError); + } + + if (data != null) + { + log.Debug($"OPTHO {OptoComPortNr} Parsed optho data:" + data); + logStream.Debug($"ID: {OptoComPortNr} " + data); + + optoData[bufferIx].UpdateFromSmart( + data, + optoDataCount, + Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), + ref volumeRawExtLast, + ref timestampExtLast); + + flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); + + OptoTelegramReceived( + optoDataCount, + true, + volumeRawExtLast, + timestampExtLast); + } + + optoDataCount++; } else { - /// CR+LF found - if (optoState == DataStreamState.ProcessAndSave) - { - int bufferIx = BufferIdx(optoDataCount); + // Flush mode + DiagnosticLedState4Data data = + (DiagnosticLedState4Data)parser.ParseLine(line, false); - if (pos < OptoTelegramRaw.Length - 2) - { - /// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop - allRcvd = allRcvd.Substring(pos + 2); - if (synchronized) - { - optoData[bufferIx].Counter = optoDataCount; - optoData[bufferIx].SetFlags(OptoTelegramFlags.SyncError); - } - synchronized = true; - } - else if (optoData[bufferIx].UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), - optoDataCount, - Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), - ref volumeRawExtLast, ref timestampExtLast)) - { - /// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) && the telegram is OK - flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); - OptoTelegramReceived(optoDataCount, synchronized2, volumeRawExtLast, timestampExtLast); - synchronized2 = synchronized; - allRcvd = allRcvd.Substring(pos + 2); - } - else - { - /// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) but the telgram was not OK - optoData[bufferIx].Counter = optoDataCount; - optoDataCount++; - allRcvd = allRcvd.Substring(pos + 2); - } - - optoDataCount++; - } - else /// optoState == OptoState.Flush - { - if (pos < OptoTelegramRaw.Length - 2) - { - /// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop - allRcvd = allRcvd.Substring(pos + 2); - synchronized = true; - } - // CR+LF found and (pos >= OptoTelegram.Length - 2) - else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), - 0, - Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), - ref volumeRawExtLast, ref timestampExtLast)) - { - flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); - synchronized2 = synchronized; - allRcvd = allRcvd.Substring(pos + 2); - } - else - { - allRcvd = allRcvd.Substring(pos + 2); - } - } + flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); } } - - //OnOptoReceived(this, new OptoReceivedEventArgs(s)); } - else + catch (TimeoutException) { - //OnOptoReceived(this, new OptoReceivedEventArgs(".")); + // ✅ No data received within 3 seconds + log.Debug($"OPTHO {OptoComPortNr} ReadLine timeout (3s) - continuing."); + + // Just continue without parsing + } + catch (Exception ex) + { + log.Error($"OPTHO {OptoComPortNr} Read error: {ex.Message}"); } } - } - - void ISmartReader.ResetNfcInterface(bool? nfc_on) - { - ResetNfcInterface(nfc_on); } public string ReadOptoData() @@ -1124,48 +1116,114 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead string received = "."; lock (this) { - int nrBytes = optoSerialPort.BytesToRead; - if (nrBytes > 0) + try { - char[] buffer = new char[nrBytes]; - optoSerialPort.Read(buffer, 0, nrBytes); - received = new string(buffer); + string line = optoSerialPort.ReadLine(); // string + byte[] bytes = optoSerialPort.Encoding.GetBytes(line); + received = HexFormatter.ToSerialHex(bytes); + log.Debug("RX ← " + received); + } + catch (TimeoutException) + { + // ✅ No data received within 3 seconds + log.Debug($"ReadOptoData() OPTHO {OptoComPortNr} ReadLine timeout (3s) - continuing."); + + // Just continue without parsing + } + catch (Exception ex) + { + log.Error($"ReadOptoData() OPTHO {OptoComPortNr} Read error: {ex.Message}"); } } return received; } - - void ISmartReader.SetNfcInterface() + + public async Task ReadOptoDataWithTimeoutAsync(int timeoutMs = 5000) { - SetNfcInterface(); + if (optoSerialPort == null) + return string.Empty; + + var readTask = Task.Run(() => + { + lock (this) + { + if (optoSerialPort== null) return string.Empty; + try + { + string line = optoSerialPort.ReadLine(); + byte[] bytes = optoSerialPort.Encoding.GetBytes(line); + string received = HexFormatter.ToSerialHex(bytes); + + log.Debug("RX ← " + received); + return line; + } + catch (TimeoutException) + { + // ✅ No data received within 3 seconds + log.Debug($"ReadOptoData() OPTHO {OptoComPortNr} ReadLine timeout (3s) - continuing."); + + // Just continue without parsing + } + catch (Exception ex) + { + log.Error($"ReadOptoData() OPTHO {OptoComPortNr} Read error: {ex.Message}"); + } + + return string.Empty; + } + }); + + var completedTask = await Task.WhenAny(readTask, Task.Delay(timeoutMs)); + + if (completedTask == readTask) + { + return await readTask; // completed successfully + } + + log.Debug("ReadOptoData timeout after " + timeoutMs + " ms"); + return string.Empty; // timeout case + } + + public string ReadOptoDataWithTimeout(int timeoutMs = 5000) + { + try + { + return ReadOptoDataWithTimeoutAsync(timeoutMs) + .GetAwaiter() + .GetResult(); + } + catch + { + return string.Empty; + } } - void OptoTelegramReceived(int currentIx, bool async, Int64 volumeRawExt, Int64 timestampRawExt) + void OptoTelegramReceived(int currentIx, bool async, double volumeRawExt, double timestampRawExt) { currentTelegramIx = currentIx; lastVolumeRaw = volumeRawExt; lastTimestamp = timestampRawExt; - if (volumeLtr == 0 && volumeLtr0 == 0) + if (Double.IsNaN(volumeLtr) && Double.IsNaN(volumeLtr0)) { - volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0; + volumeLtr = lastVolumeRaw; volumeLtr0 = volumeLtr; } else { - volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0; + volumeLtr = lastVolumeRaw; } - if (timestampSec == 0 && timestampSec0 == 0) + if (Double.IsNaN(timestampSec)&& Double.IsNaN(timestampSec0)) { - timestampSec = (double)lastTimestamp / 8192.0; + timestampSec = lastTimestamp; timestampSec0 = timestampSec; } else { - timestampSec = (double)lastTimestamp / 8192.0; + timestampSec = lastTimestamp; } } @@ -1270,25 +1328,55 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// Filtered volume double VolumeFromSamples(OptoTelegramRaw[] optoData, int optoDataCount, int unwrappedIx, double scalingFactor, int samplesCount2 = 0) { + log.Debug("-- Get VolumeFromSamples() --"); + if (samplesCount2 == 0) + { + if (unwrappedIx >= optoDataCount) + { + log.Debug( + $"-- FAILED VolumeFromSamples() - unwrappedIx {unwrappedIx} >= optoDataCount{optoDataCount}--"); + return 0; + } + + int wrappedIx = BufferIdx(unwrappedIx); + + if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && + optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && + optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd) + { + log.Debug($"-- Get VolumeFromSamples() - Quit because:{optoData[wrappedIx].Flags}--"); + return 0; + } + + log.Debug($"Valid data VolumeRawExt: {optoData[wrappedIx].VolumeRawExt}"); + return optoData[wrappedIx].VolumeRawExt; + } + + + //TODO BUMI - do result as average from data - usually 5 samples + if (samplesCount2 < 0) samplesCount2 = 0; if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0; - - Int64 sum = 0; + + + double sum = 0; for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++) { int wrappedIx = BufferIdx(i); - + if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd) { return 0; } - + sum += optoData[wrappedIx].VolumeRawExt; } - - return 0.0000625 * scalingFactor * sum / (double)(2 * samplesCount2 + 1); + + return sum / (double)(2 * samplesCount2 + 1); + //return 0.0000625 * scalingFactor * sum / (double)(2 * samplesCount2 + 1); + } /// @@ -1299,25 +1387,45 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead /// Filtered time double TimeFromSamples(OptoTelegramRaw[] optoData, int optoDataCount, int unwrappedIx, int samplesCount2 = 0) { - if (samplesCount2 < 0) samplesCount2 = 0; - if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0; - - Int64 sum = 0; - for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++) + log.Debug("-- Get TimeFromSamples() --"); + if (unwrappedIx >= optoDataCount) { - int wrappedIx = BufferIdx(i); - - if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && - optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && - optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd) - { - return 0; - } - - sum += optoData[wrappedIx].TimestampExt; + log.Debug( + $"-- FAILED TimeFromSamples() - unwrappedIx {unwrappedIx} >= optoDataCount{optoDataCount}--"); + return 0; } + + int wrappedIx = BufferIdx(unwrappedIx); - return sum / (double)(8192 * (2 * samplesCount2 + 1)); + if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && + optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && + optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd) + { + log.Debug($"-- Get TimeFromSamples() - Quit because:{optoData[wrappedIx].Flags}--"); + return 0; + } + log.Debug($"Valid data TimestampExt: {optoData[wrappedIx].TimestampExt}"); + return optoData[wrappedIx].TimestampExt; + + // if (samplesCount2 < 0) samplesCount2 = 0; + // if ((unwrappedIx - samplesCount2) < 0 || (unwrappedIx + samplesCount2) >= optoDataCount) return 0; + // + // Int64 sum = 0; + // for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++) + // { + // int wrappedIx = BufferIdx(i); + // + // if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && + // optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && + // optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestEnd) + // { + // return 0; + // } + // + // sum += optoData[wrappedIx].TimestampExt; + // } + // + // return sum / (double)(8192 * (2 * samplesCount2 + 1)); } /// @@ -1536,5 +1644,204 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { return this; } + + + public async Task DataEntry_ReadSerialNumber() + { + log.Debug("called DataEntry_ReadSerialNumber()"); + if (!string.IsNullOrEmpty(SerialNr)) return SerialNr; + + //need to find serial number + SerialNr = await DataEntry_ReadSerialNumberAsync(); + + return SerialNr; + } + + public Task DataEntry_ReadBeginVolume() + { + log.Debug("called DataEntry_ReadBeginVolumer()"); + + Task readedVolume = DataEntry_BeginVolumeAsync(); + + return readedVolume; + } + + public Task DataEntry_ReadEndVolume() + { + log.Debug("called DataEntry_ReadBeginVolumer()"); + + Task readedVolume = DataEntry_EndVolumeAsync(); + + return readedVolume; + } + + + public async Task DataEntry_EndVolumeAsync() + { + + if (optoSerialPort == null || !optoSerialPort.IsOpen) + { + StartDataStreamProcessing(); + if (optoSerialPort == null || !optoSerialPort.IsOpen) + { + log.Error($"optoSerialPort COM: {this.OptoComPortNr} is not open - DataEntry_EndVolumeAsync()"); + return Double.NaN; + } + } + + return await Task.Run(() => + { + log.Debug($"Try get End Volume! COM: {this.OptoComPortNr}"); + volumeLtr = Double.NaN; + + int counter = 0; + while (Double.IsNaN(volumeLtr) && counter < 2) + { + counter++; + try + { + string readOptoDataWithTimeout = ReadOptoDataWithTimeout(2000); + if (!string.IsNullOrEmpty(readOptoDataWithTimeout)) + { + try + { + DiagnosticLedState4Data data = + (DiagnosticLedState4Data)parser.ParseLine(readOptoDataWithTimeout, false); + volumeLtr = data.RawVolume; + break; + } + catch (Exception ex) + { + log.Warn($"Parsing DiagnosticLedState4Data: {ex.Message}"); + } + } + } + catch (Exception ex) + { + break; + } + } + + + log.Debug($"Try get End Volume! COM: {this.OptoComPortNr}, Volume: {volumeLtr}"); + if (optoSerialPort != null && optoSerialPort.IsOpen) CloseOptoSerialPort(); + + if (!Double.IsNaN(volumeLtr)) + { + endWMState = volumeLtr; + if (!Double.IsNaN(beginWMState) && !Double.IsNaN(endWMState)) + { + //Solve roll over + if (endWMState < beginWMState) + { + log.Debug($"Solve roll over! endWMState: {endWMState} < beginWMState: {beginWMState}"); + const double VOL_RANGE_LITERS = 16777216.0 * 0.00025; // 4,194.304 l + endWMState += VOL_RANGE_LITERS; + volumeLtr = endWMState; + ReadPulses(); + log.Debug($"Solve roll over! Upgraded endWMState: {endWMState}, beginWMState: {beginWMState}"); + } + } + return endWMState; + } + //} + + log.Warn("Default NaN value returned! Data Opto stream reading failed!"); + return Double.NaN; + }).ConfigureAwait(false); + } + + + public async Task DataEntry_BeginVolumeAsync() + { + if (ConfigStruct == null) + { + log.Debug("ConfigStruct is null - created new in ReadSerialNr()"); + ConfigStruct = new ConfigStruct(); + } + + return await Task.Run(() => + { + + log.Debug($"Try get Start Volume! COM: {this.OptoComPortNr}"); + + Start(); + + volumeLtr0 = Double.NaN; + int counter = 0; + while (Double.IsNaN(volumeLtr0) && counter < 10) + { + counter++; + try + { + string readOptoDataWithTimeout = ReadOptoDataWithTimeout(5000); + if (!string.IsNullOrEmpty(readOptoDataWithTimeout)) + { + try + { + DiagnosticLedState4Data data = + (DiagnosticLedState4Data)parser.ParseLine(readOptoDataWithTimeout, false); + volumeLtr0 = data.RawVolume; + break; + } + catch (Exception ex) + { + log.Warn($"Parsing DiagnosticLedState4Data: {ex.Message}"); + } + } + } + catch (Exception ex) + { + break; + } + } + + log.Debug($"Try get Start Volume! COM: {this.OptoComPortNr}, Volume: {volumeLtr0}"); + if (optoSerialPort != null && optoSerialPort.IsOpen) CloseOptoSerialPort(); + + if (!Double.IsNaN(volumeLtr0)) + { + beginWMState = volumeLtr0; + ReadPulses(); + return beginWMState; + } + //} + + log.Warn("Default NaN value returned! Data Opto stream reading failed!"); + return Double.NaN; + }).ConfigureAwait(false); + } + + public async Task DataEntry_ReadSerialNumberAsync() + { + if (!string.IsNullOrEmpty(SerialNr)) + return SerialNr; + + if (ConfigStruct == null) + { + log.Debug("ConfigStruct is null - created new in ReadSerialNr()"); + ConfigStruct = new ConfigStruct(); + } + + if (CommFailed || ConfigStruct == null) + return CommErr.CommFailed.ToString(); + + return await Task.Run(() => + { + + + + log.Debug($"Try get ReadSerialNr! COM: {this.RfidComPortNr}"); + if (OptoHeadTest.ReadSerialNr()) + { + SerialNr = this.ConfigStruct.PCBNumberString; + log.Debug("ReadSerialNr successful"); + } + + //optoHeadTest.CloseConnection(); + + return SerialNr; + }); + } } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHeadTestCtrl.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHeadTestCtrl.cs index c89ca5c09..f65c32ade 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHeadTestCtrl.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/IperlHeadTestCtrl.cs @@ -3,7 +3,7 @@ using System.Threading; using System.Web.UI.WebControls; using System.Windows.Forms; using TBF.Rig.Sequences; -using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication; +using TBF.Rig.TestMethods.iPerlCommunication.communication; namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { @@ -22,7 +22,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead InitializeComponent(); if (config == null) return; - SmartCommunicationForm.TestMethodCfg = new TestMethodCfg_IPerl(null); // default values for iPerlCommunication + iPerlCommunicationForm.cfg = new TestMethodCfg(null); // default values for iPerlCommunication foreach(var head in ProcessData.IperlHeads) { @@ -78,14 +78,16 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead using (Tools.LogChecker logChecker = new Tools.LogChecker("RfidData", log4net.Core.Level.Debug)) { ListItem rfidListItem = new ListItem(); - rfidListItem.Attributes.Add("style", "font-weight:bold"); + rfidListItem.Attributes.Add("style", "font-volume:bold"); + //rfidListItem.Attributes.Add("style", "font-weight:bold"); + bool isTestModeSuccessful = false; switch (rfidCommandComboBox.SelectedValue) { case "ReadPCB": - rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(iPerlHead)}"; + rfidListItem.Text = $"PCB: {iPerlHead.OptoHeadTest.ReadRequest_PCB()}"; break; case "SetTestMode": - rfidListItem.Text = OpticalHeadTest.SetTestMode(iPerlHead); + rfidListItem.Text = iPerlHead.OptoHeadTest.SetTestMode(ref isTestModeSuccessful); optoListBox.Items.Clear(); stopWorkerThread = false; optoThread = new Thread(OptoWorker); @@ -96,7 +98,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead } break; case "SetActiveMode": - rfidListItem.Text = OpticalHeadTest.SetActiveMode(iPerlHead); + + rfidListItem.Text = iPerlHead.OptoHeadTest.SetActiveMode(ref isTestModeSuccessful); stopWorkerThread = true; iPerlHead.StopDataStreamProcessing(); // close opto port break; diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/NfcServices.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/NfcServices.cs index d0df2c37c..9f50e64b9 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/NfcServices.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/NfcServices.cs @@ -1,4 +1,4 @@ -using log4net; +using log4net; using Sensus.iPerl.NfcHandler; using Sensus.iPerl.RfidCom.Exceptions; using System; @@ -12,9 +12,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead internal class NfcServices { protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); - internal static int ReadRequest(TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead, MCI_Protocol.StructName structName, int offset, int length, out byte[] buffer) + internal static int ReadRequest(TestMethodCfg cfg, IperlHead iperlHead, MCI_Protocol.StructName structName, int offset, int length, out byte[] buffer) { - for (int i = 0; i < cfgIPerl.MaxCommRetries; i++) + for (int i = 0; i < cfg.MaxCommRetries; i++) { NfcDataHandler _nfcDataHandler = new NfcDataHandler(); @@ -26,9 +26,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead try { rfidDataLogger.Info($"NFC COM{iperlHead.RfidComPortNr} ReadRequest : {structName}, {offset}, {length}"); - OpenConnection(_nfcDataHandler, cfgIPerl, iperlHead); + OpenConnection(_nfcDataHandler, cfg, iperlHead); - buffer = MciRead(_nfcDataHandler, cfgIPerl, structName, (ushort)offset, length); + buffer = MciRead(_nfcDataHandler, cfg, structName, (ushort)offset, length); _nfcDataHandler.RFProtocolOFF(); // turn off rf antenna due to possible interference CloseComPort(_nfcDataHandler); @@ -44,7 +44,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead } catch (RfidValidationException) { - Thread.Sleep(cfgIPerl.WaitTimeAfterFailure); + Thread.Sleep(cfg.WaitTimeAfterFailure); } catch (Exception ex) { @@ -57,7 +57,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead return 3; } - internal static int WriteRequest(TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead, MCI_Protocol.StructName structName, int offset, int length, byte[] buffer) + internal static int WriteRequest(TestMethodCfg cfg, IperlHead iperlHead, MCI_Protocol.StructName structName, int offset, int length, byte[] buffer) { NfcDataHandler _nfcDataHandler = new NfcDataHandler(); MessageEventHandlers(_nfcDataHandler); @@ -68,9 +68,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead try { rfidDataLogger.Info($"NFC COM{iperlHead.RfidComPortNr} WriteRequest : {structName}, {offset}, {length}, {ByteArrayToHexString(buffer)}"); - OpenConnection(_nfcDataHandler, cfgIPerl, iperlHead); + OpenConnection(_nfcDataHandler, cfg, iperlHead); - MciWrite(_nfcDataHandler, cfgIPerl, structName, (ushort)offset, length, buffer); + MciWrite(_nfcDataHandler, cfg, structName, (ushort)offset, length, buffer); _nfcDataHandler.RFProtocolOFF(); // turn off rf antenna due to possible interference CloseComPort(_nfcDataHandler); @@ -83,14 +83,14 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead } } - private static void OpenConnection(NfcDataHandler nfcDataHandler, TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead) + private static void OpenConnection(NfcDataHandler nfcDataHandler, TestMethodCfg cfg, IperlHead iperlHead) { string comPort = $"COM{iperlHead.RfidComPortNr}"; int retryCount = 0 ; Open: nfcDataHandler.Close(); Thread.Sleep(100); - if (nfcDataHandler.OpenConnection(comPort, cfgIPerl.BaudRate, cfgIPerl.DataBits, cfgIPerl.ParityBit, cfgIPerl.StopBits)) + if (nfcDataHandler.OpenConnection(comPort, cfg.BaudRate, cfg.DataBits, cfg.ParityBit, cfg.StopBits)) { rfidDataLogger.Info($"NFC COM{iperlHead.RfidComPortNr} Port Open"); @@ -100,7 +100,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead if (!nfcDataHandler.ConnectDevice()) { rfidDataLogger.Error($"NFC COM{iperlHead.RfidComPortNr} Error connect device."); - for (int i = 0; i < cfgIPerl.MaxCommRetries; i++) + for (int i = 0; i < cfg.MaxCommRetries; i++) { if (nfcDataHandler.Echo()) break; } @@ -110,7 +110,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { retryCount++; rfidDataLogger.Error($"NFC COM{iperlHead.RfidComPortNr} Error connect reader. Reconnect comport {retryCount}"); - if (retryCount < cfgIPerl.MaxCommRetries) + if (retryCount < cfg.MaxCommRetries) { nfcDataHandler.Close(); iperlHead.ResetNfcInterface(); // reset NFC head via optoport - switch to RFID and back to NFC interface @@ -127,7 +127,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead nfcDataHandler.Close(); } - private static byte[] MciRead(NfcDataHandler nfcDataHandler, TestMethodCfg_IPerl cfgIPerl, StructName structName, ushort offset, int length) + private static byte[] MciRead(NfcDataHandler nfcDataHandler, TestMethodCfg cfg, StructName structName, ushort offset, int length) { bool isReadValues = false; int retryCount = 0; @@ -153,14 +153,14 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { rfidDataLogger.Info($"MCI Error: Unidentified"); retryCount++; - if (retryCount < cfgIPerl.MaxCommRetries) + if (retryCount < cfg.MaxCommRetries) goto Read; } else { rfidDataLogger.Info("Last error message: " + nfcDataHandler.LastErrorMessage); retryCount++; - if (retryCount < cfgIPerl.MaxCommRetries) + if (retryCount < cfg.MaxCommRetries) goto Read; } } @@ -168,13 +168,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { rfidDataLogger.Error("MciRead Last error message: " + ex.Message); retryCount++; - if (retryCount < cfgIPerl.MaxCommRetries) + if (retryCount < cfg.MaxCommRetries) goto Read; } return new byte[length]; } - private static void MciWrite(NfcDataHandler nfcDataHandler, TestMethodCfg_IPerl cfgIPerl, MCI_Protocol.StructName structName, ushort offset, int length, byte[] payload) + private static void MciWrite(NfcDataHandler nfcDataHandler, TestMethodCfg cfg, MCI_Protocol.StructName structName, ushort offset, int length, byte[] payload) { int retryCount = 0; Write: @@ -199,7 +199,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { rfidDataLogger.Error("MciWrite error message: " + ex.Message); retryCount++; - if (retryCount < cfgIPerl.MaxCommRetries) + if (retryCount < cfg.MaxCommRetries) goto Write; } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ProcParams.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ProcParams.cs index 0fab699f5..edb20f64d 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ProcParams.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/ProcParams.cs @@ -149,16 +149,16 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead return pars; } - public override bool UpdateFromDbEntity(ComponentProcedure dbEntity) - { - if (dbEntity == null) return false; - try - { - ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams; + public override bool UpdateFromDbEntity(ComponentProcedure dbEntity) + { + if (dbEntity == null) return false; + try + { + ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams; - procedureParamsEntity = dbEntity; - componentName = dbEntity.CmpntName; - procedure = dbEntity.Procedure; + procedureParamsEntity = dbEntity; + componentName = dbEntity.CmpntName; + procedure = dbEntity.Procedure; if (tmp != null) { @@ -181,7 +181,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead } } - public ProcParams() + + public ProcParams() { } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/RfidServices.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/RfidServices.cs index f2af71a25..0a0bedf1e 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/RfidServices.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/RfidServices.cs @@ -1,29 +1,28 @@ -using Sensus.iPerl.RfidCom.Exceptions; +using Sensus.iPerl.RfidCom.Exceptions; using Sensus.iPerl.RfidCom.Helper; using Sensus.iPerl.RfidCom; using System; using System.Text.RegularExpressions; using System.Threading; using log4net; -using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication; namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { internal class RfidServices { protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); - private static readonly ILog log = LogManager.GetLogger(typeof(SmartCommunicationForm)); + private static readonly ILog log = LogManager.GetLogger(typeof(iPerlCommunicationForm)); - internal static int ReadRequest(TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead, MessageID messageID, int offset, int length, out byte[] buffer) + internal static int ReadRequest(TestMethodCfg cfg, IperlHead iperlHead, MessageID messageID, int offset, int length, out byte[] buffer) { - for (int i = 0; i < cfgIPerl.MaxCommRetries; i++) + for (int i = 0; i < cfg.MaxCommRetries; i++) { - rfidDataLogger.Error($"{iperlHead.CommInterface} Start {i} reading: COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},{offset}, {length}... timeout {cfgIPerl.CommTimeout})"); + rfidDataLogger.Error($"{iperlHead.CommInterface} Start {i} reading: COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},{offset}, {length}... timeout {cfg.CommTimeout})"); using (RfidLogic writer = new RfidLogic($"COM{iperlHead.RfidComPortNr}")) { try { - byte[] response = writer.ReadRequest((byte)messageID, offset, length, cfgIPerl.CommTimeout); + byte[] response = writer.ReadRequest((byte)messageID, offset, length, cfg.CommTimeout); string hexString = RfidHelper.ConvertByteArrayToHexString(response); string swapHexString = RfidHelper.SwapHexcode(hexString); string decString = RfidHelper.HexLiteral2Unsigned(RfidHelper.SwapHexcode(hexString)).ToString(); @@ -57,42 +56,42 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead if (/*RfidHelper.IsPassThrough(messageID)*/ messageID == MessageID.ASICRegisterReadTest || messageID == MessageID.RadioPassthrough) { rfidDataLogger.Info($"COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},...) {(i > 0 ? "<- Error: Invalid Pass-Through data." : "<- Info: Wait for Pass-Through data.")}"); - Thread.Sleep(cfgIPerl.PassThroughWaitTime); + Thread.Sleep(cfg.PassThroughWaitTime); } else { - Thread.Sleep(cfgIPerl.WaitTimeAfterFailure); + Thread.Sleep(cfg.WaitTimeAfterFailure); } } catch (RfidValidationException) { - Thread.Sleep(cfgIPerl.WaitTimeAfterFailure); + Thread.Sleep(cfg.WaitTimeAfterFailure); } catch (Exception ex) { rfidDataLogger.Error($"COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},...) {ex.Message}"); - Thread.Sleep(cfgIPerl.WaitTimeAfterFailure); + Thread.Sleep(cfg.WaitTimeAfterFailure); } } } - rfidDataLogger.Error($"{iperlHead.CommInterface} reading failed after {cfgIPerl.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},...)"); - log.Error($"{iperlHead.CommInterface} reading failed after {cfgIPerl.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},...)"); + rfidDataLogger.Error($"{iperlHead.CommInterface} reading failed after {cfg.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},...)"); + log.Error($"{iperlHead.CommInterface} reading failed after {cfg.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: ReadRequestPort ({messageID},...)"); buffer = new byte[length]; return 3; } - internal static int WriteRequest(TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead, MessageID messageID, int offset, int length, byte[] buffer) + internal static int WriteRequest(TestMethodCfg cfg, IperlHead iperlHead, MessageID messageID, int offset, int length, byte[] buffer) { RfidLogic writer = new RfidLogic($"COM{iperlHead.RfidComPortNr}"); string payload = RfidHelper.ConvertByteArrayToHexString(buffer); - for (var i = 0; i < cfgIPerl.MaxCommRetries; i++) + for (var i = 0; i < cfg.MaxCommRetries; i++) { - rfidDataLogger.Error($"{iperlHead.CommInterface} Start {i} writting: COM{iperlHead.RfidComPortNr}: WriteRequest ({messageID},{offset}, {length}, {payload}... timeout {cfgIPerl.CommTimeout})"); + rfidDataLogger.Error($"{iperlHead.CommInterface} Start {i} writting: COM{iperlHead.RfidComPortNr}: WriteRequest ({messageID},{offset}, {length}, {payload}... timeout {cfg.CommTimeout})"); try { if (writer.ClosePort()) writer.OpenPort(); - writer.WriteRequest((byte)messageID, offset, length, buffer, cfgIPerl.CommTimeout, false); + writer.WriteRequest((byte)messageID, offset, length, buffer, cfg.CommTimeout, false); writer.ClosePort(); rfidDataLogger.InfoFormat($"{iperlHead.Name}({iperlHead.SerialNr},COM{iperlHead.RfidComPortNr}): WriteRequestPort({messageID}, {offset}, {length}, {payload})"); return 0; @@ -106,7 +105,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead else { rfidDataLogger.Error($"COM{iperlHead.RfidComPortNr}: Error: {ex.Message}"); - Thread.Sleep(cfgIPerl.WaitTimeAfterFailure); + Thread.Sleep(cfg.WaitTimeAfterFailure); if (i > 1) { rfidDataLogger.Error($"COM{iperlHead.RfidComPortNr}: Reopen the com port."); @@ -116,8 +115,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead } } writer.ClosePort(); - rfidDataLogger.Error($"RFID writing failed after {cfgIPerl.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: WriteRequestPort ({messageID},...) {System.Text.Encoding.UTF8.GetString(buffer)}"); - log.Error($"RFID writing failed after {cfgIPerl.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: WriteRequestPort ({messageID},...) {System.Text.Encoding.UTF8.GetString(buffer)}"); + rfidDataLogger.Error($"RFID writing failed after {cfg.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: WriteRequestPort ({messageID},...) {System.Text.Encoding.UTF8.GetString(buffer)}"); + log.Error($"RFID writing failed after {cfg.MaxCommRetries} retries: COM{iperlHead.RfidComPortNr}: WriteRequestPort ({messageID},...) {System.Text.Encoding.UTF8.GetString(buffer)}"); return 2; } } diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/SimulationServices.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/SimulationServices.cs index 7ccf4f6f5..0f90ae570 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/SimulationServices.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlHead/SimulationServices.cs @@ -1,5 +1,8 @@ using System; +using System.IO; using System.Linq; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { @@ -7,11 +10,34 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead { const int Q2CorrFactorsAddr = 0x1878; - internal static int ReadRequest(TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead, MessageID messageID, int offset, int length, out byte[] buffer) + internal static int ReadRequest(TestMethodCfg cfg, IperlHead iperlHead, MessageID messageID, int offset, int length, out byte[] buffer) { - byte[] configurationBuffer = new byte[ConfigStruct.Length] { 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + + string pcbStr = iperlHead.RfidComPortNr.ToString().PadRight(10,'0') + iperlHead.Position.ToString("D2"); + long decVal = Convert.ToInt64(pcbStr); + string nHexStr = decVal.ToString("X4"); + + ConfigStruct configStruct = new ConfigStruct(); + configStruct.PCBNumberString = nHexStr; + configStruct.StatusMode = ProtocolStatuses.Active; + configStruct.OpthoStatusMode = DiagnosticLedState.State4; + configStruct.Version = "Good Version: 123456"; + + byte[] configurationBuffer; + + using (var ms = new MemoryStream()) + using (var writer = new BinaryWriter(ms)) + { + configStruct.WriteBinary(writer); + writer.Flush(); + configurationBuffer = ms.ToArray(); // ← this is the binary output + } + byte[] calibrationBuffer = new byte[CalibrationStructV4.Length] { 3, 0, 150, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 150, 10 }; buffer = new byte[length]; + + return 0;//switch off if (messageID == MessageID.Configuration) { @@ -34,7 +60,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead return iperlHead.Name.Equals("iPerl13") ? 2 : 0; /// Simulates an error on position 13 } - internal static int WriteRequest(TestMethodCfg_IPerl cfgIPerl, IperlHead iperlHead, MessageID messageID, int offset, int length, byte[] buffer) + internal static int WriteRequest(TestMethodCfg cfg, IperlHead iperlHead, MessageID messageID, int offset, int length, byte[] buffer) { return 0; } diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlASICCorrections.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlASICCorrections.cs index 888564eda..75ac506dd 100644 --- a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlASICCorrections.cs +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlASICCorrections.cs @@ -252,10 +252,10 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations string resultStr = string.Empty; - WorkerActivity(currentActivity, ihead, wm, currentTest, - wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep); - ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity, - currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID); + // WorkerActivity(currentActivity, ihead, wm, currentTest, + // wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep); + // ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity, + // currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID); break; } @@ -524,10 +524,10 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations public static int ReadRequestPort(ITestMethodCfg cfgMethod, ISmartReader smartHead, MessageID messageID, MCI_Protocol.StructName structName, int offset, int length, out byte[] buffer) { - TestMethodCfg_IPerl cfg = cfgMethod as TestMethodCfg_IPerl; + TestMethodCfg cfg = cfgMethod as TestMethodCfg; if (cfg == null) { - if (smartHead.Cfg is TestMethodCfg_IPerl cfg2) cfg = cfg2; + if (smartHead.Cfg is TestMethodCfg cfg2) cfg = cfg2; } Thread.Sleep(cfg == null ? 250 : Math.Max(250, cfg.DelayBetweenRetries)); diff --git a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlCorrections.cs b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlCorrections.cs index ea6c6a307..d14df3d0b 100644 --- a/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlCorrections.cs +++ b/TBF/Rig/Uni/SharedDialogs/SmartMetersCommunication/implementations/IPerlCorrections.cs @@ -252,10 +252,10 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations string resultStr = string.Empty; - WorkerActivity(currentActivity, ihead, wm, currentTest, - wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep); - ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity, - currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID); + // WorkerActivity(currentActivity, ihead, wm, currentTest, + // wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep); + // ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity, + // currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID); break; } @@ -524,10 +524,10 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations public static int ReadRequestPort(ITestMethodCfg cfgMethod, ISmartReader smartHead, MessageID messageID, MCI_Protocol.StructName structName, int offset, int length, out byte[] buffer) { - TestMethodCfg_IPerl cfg = cfgMethod as TestMethodCfg_IPerl; + TestMethodCfg cfg = cfgMethod as TestMethodCfg; if (cfg == null) { - if (smartHead.Cfg is TestMethodCfg_IPerl cfg2) cfg = cfg2; + if (smartHead.Cfg is TestMethodCfg cfg2) cfg = cfg2; } Thread.Sleep(cfg == null ? 250 : Math.Max(250, cfg.DelayBetweenRetries)); diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index d84662498..f70b0bb3c 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -663,6 +663,7 @@ + @@ -688,6 +689,7 @@ + @@ -1263,50 +1265,17 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + - - UserControl - - - IPerlUniCfgCtrl.cs - - - UserControl - - - IperlASICUniHeadTestCtrl.cs - + + @@ -1607,10 +1576,54 @@ Component - - Form - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1640,7 +1653,7 @@ - + UserControl @@ -3362,12 +3375,8 @@ RRCfgCtrl.cs - - IPerlUniCfgCtrl.cs - - - IperlASICUniHeadTestCtrl.cs - + + IPerlUniCfgCtrl.cs @@ -3482,7 +3491,7 @@ GrabImageCfgCtrl.cs - + diff --git a/TBF/UI/MainWnd.cs b/TBF/UI/MainWnd.cs index 569eecb23..8bb041a6f 100644 --- a/TBF/UI/MainWnd.cs +++ b/TBF/UI/MainWnd.cs @@ -20,6 +20,7 @@ using TBF.UI.Shared; using AppDiagnostic; using SharedComponents; using System.Diagnostics; +using TBF.Rig.TestMethods.iPerlCommunication; using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication; namespace TBF.UI @@ -1198,7 +1199,7 @@ namespace TBF.UI private void optoHeadsToolStripMenuItem_Click(object sender, EventArgs e) { - new SmartCommunicationForm(true).ShowDialog(); + new iPerlCommunicationForm(true).ShowDialog(); } private void statusStrip1_DoubleClick(object sender, EventArgs e) diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadBaudRateDetectionTests.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadBaudRateDetectionTests.cs deleted file mode 100644 index 4cae1d19b..000000000 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadBaudRateDetectionTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.IO.Ports; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.hexLogger; - -namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4 -{ - [TestClass] - public class TouchReadBaudRateDetectionTests - { - private const string ComPort = "COM3"; // COM PORT OF THE ASIC - private const int ReadTimeoutMs = 1500; - - private static readonly int[] StandardBaudRates = - { - 300, 600, 7812, 1200, 18432, 2400, 4800, - 9600, 10400, 15625, 19200, 31250, 36864, - 38400, 50000, 57600, 62500, 76800, 115200 - }; - - [TestMethod] - [TestCategory("Hardware")] - [TestCategory("Serial")] - public void Detect_BaudRate_By_ViewFactoryId() - { - byte[] request = new TouchReadFrameBuilder() - .RequestResponse(true) - .AddCommand(TouchReadCommand.ViewFactoryId) - .BuildBytes(); - - var parser = new TouchReadFrameParser(); - - foreach (int baud in StandardBaudRates) - { - Console.WriteLine($"--- Testing baud rate: {baud} ---"); - - try - { - using (var port = new SerialPort(ComPort, baud, Parity.None, 8, StopBits.One)) - { - port.ReadTimeout = ReadTimeoutMs; - port.WriteTimeout = 500; - port.Open(); - - port.DiscardInBuffer(); - port.DiscardOutBuffer(); - - Console.WriteLine("TX → " + HexFormatter.ToSerialHex(request)); - port.Write(request, 0, request.Length); - - byte[] response = ReadFullFrame(port); - - Console.WriteLine("RX ← " + HexFormatter.ToSerialHex(response)); - - TouchReadResponse decoded = parser.Parse(response); - - if (decoded.IsOk) - { - string factoryId = decoded.GetAsciiPayload(); - - Console.WriteLine(); - Console.WriteLine("VALID RESPONSE"); - Console.WriteLine("Baud rate : " + baud); - Console.WriteLine("Factory ID : " + factoryId); - Console.WriteLine(); - - Assert.IsFalse(string.IsNullOrEmpty(factoryId), - "Factory ID is empty"); - - return; // SUCCESS → stop scanning - } - } - } - catch (TimeoutException) - { - Console.WriteLine("Timeout"); - } - catch (Exception ex) - { - Console.WriteLine("Error: " + ex.Message); - } - } - - Assert.Fail("No valid baud rate detected."); - } - - private static byte[] ReadFullFrame(SerialPort port) - { - byte start = (byte)port.ReadByte(); - if (start != 0x0D) - throw new InvalidOperationException("Invalid START byte"); - - byte length = (byte)port.ReadByte(); - - int remaining = length; - byte[] buffer = new byte[2 + remaining]; - - buffer[0] = start; - buffer[1] = length; - - int offset = 2; - while (remaining > 0) - { - int read = port.Read(buffer, offset, remaining); - offset += read; - remaining -= read; - } - - return buffer; - } - } -} diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameBuilderTest.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameBuilderTest.cs deleted file mode 100644 index 3f9f4a284..000000000 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadFrameBuilderTest.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using JetBrains.Annotations; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.hexLogger; - -namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4 -{ - [TestClass] - [TestSubject(typeof(TouchReadFrameBuilder))] - public class TouchReadFrameBuilderTest - { - - [TestMethod] - public void Encode_ViewFactoryId_Command() - { - byte[] frame = new TouchReadFrameBuilder() - .RequestResponse(true) - .AddCommand(TouchReadCommand.ViewFactoryId) - .BuildBytes(); - - byte[] expected = - { - 0x0D, // START - 0x04, // LEN - 0x08, // CONTROL (RF) - 0x01, // COMMAND - 0x00, // CHECKSUM HI - 0x1A // CHECKSUM LO - }; - - CollectionAssert.AreEqual(expected, frame); - - string log = TouchReadLogger.DescribeTx(frame); - Console.WriteLine(log); - Console.WriteLine(@"Raw: < {0} >", HexFormatter.ToSerialHex(frame)); - } - - [TestMethod] - public void Encode_ViewProgrammableId_Command() - { - byte[] frame = new TouchReadFrameBuilder() - .RequestResponse(true) - .AddCommand(TouchReadCommand.ViewProgrammableId) - .BuildBytes(); - - byte[] expected = - { - 0x0D, // START - 0x04, // LEN - 0x08, // CONTROL (RF) - 0x03, // COMMAND - 0x00, // CHECKSUM HI - 0x1C // CHECKSUM LO - }; - - CollectionAssert.AreEqual(expected, frame); - - string log = TouchReadLogger.DescribeTx(frame); - Console.WriteLine(log); - Console.WriteLine(@"Raw: <{0}>", HexFormatter.ToSerialHex(frame)); - } - - [TestMethod] - public void Encode_SetState_Idle() - { - // Arrange - byte[] frame = new TouchReadFrameBuilder() - .RequestResponse(true) - .AddCommand(TouchReadCommand.SetState) - .AddPayload(new byte[] { 0x01 }) // Idle - .BuildBytes(); - - byte[] expected = - { - 0x0D, // START - 0x05, // LEN - 0x08, // CONTROL (RF) - 0x1A, // COMMAND (Set State) - 0x01, // PAYLOAD (Idle) - 0x00, // CHECKSUM HI - 0x35 // CHECKSUM LO - }; - - // Assert - CollectionAssert.AreEqual(expected, frame, - $"Encoded frame mismatch.\nExpected: {HexFormatter.ToSerialHex(expected)}\nActual: {HexFormatter.ToSerialHex(frame)}"); - } - - [TestMethod] - [ExpectedException(typeof(FormatException))] - public void Decode_InvalidStart_Throws() - { - byte[] response = - { - 0x00, // invalid START - 0x04, - 0x00, - 0x01, - 0x00, - 0x12 - }; - - var parser = new TouchReadFrameParser(); - - parser.Parse(response); - } - } -} \ No newline at end of file diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadSerialIntegrationTests.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadSerialIntegrationTests.cs deleted file mode 100644 index 554652324..000000000 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/TouchReadSerialIntegrationTests.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.IO.Ports; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.hexLogger; - -namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4 -{ - [TestClass] - public class TouchReadSerialIntegrationTests - { - private const string ComPort = "COM3"; // CHANGE THIS - private const int BaudRate = 9600;//38400;//115200;//9600; // VERIFY FROM METER DOC - private const int ReadTimeoutMs = 2000; - - [TestMethod] - [TestCategory("Hardware")] - [TestCategory("Serial")] - public void Serial_ViewFactoryId_ReadSerialNumber() - { - // -------- Arrange -------- - byte[] request = new TouchReadFrameBuilder() - .RequestResponse(true) - .AddCommand(TouchReadCommand.ViewFactoryId) - .BuildBytes(); - - var parser = new TouchReadFrameParser(); - - using (var port = new SerialPort(ComPort, BaudRate, Parity.None, 8, StopBits.One)) - { - port.ReadTimeout = ReadTimeoutMs; - port.WriteTimeout = 500; - port.Open(); - - // Flush buffers - port.DiscardInBuffer(); - port.DiscardOutBuffer(); - - // -------- Act -------- - port.Write(request, 0, request.Length); - - Console.WriteLine("TX → " + HexFormatter.ToSerialHex(request)); - - byte[] response = ReadFullFrame(port); - - Console.WriteLine("RX ← " + HexFormatter.ToSerialHex(response)); - - TouchReadResponse decoded = parser.Parse(response); - - // -------- Assert -------- - Assert.AreEqual(0x01, decoded.Status, "Meter returned error status"); - - string serialNumber = decoded.GetAsciiPayload(); - - Assert.IsFalse(string.IsNullOrEmpty(serialNumber), - "Factory ID (serial number) is empty"); - - Console.WriteLine("Meter Factory ID: " + serialNumber); - } - } - - /// - /// Reads a full TouchRead frame from the serial port. - /// Blocks until complete frame or timeout. - /// - private static byte[] ReadFullFrame(SerialPort port) - { - // Read START + LEN first - byte start = (byte)port.ReadByte(); - if (start != 0x0D) - throw new InvalidOperationException("Invalid START byte from meter"); - - byte length = (byte)port.ReadByte(); - - // LEN counts from CONTROL to CHECKSUM - int remaining = length; - - byte[] buffer = new byte[2 + remaining]; - buffer[0] = start; - buffer[1] = length; - - int offset = 2; - while (remaining > 0) - { - int read = port.Read(buffer, offset, remaining); - offset += read; - remaining -= read; - } - - return buffer; - } - - - [TestMethod] - [TestCategory("Hardware")] - public void Serial_RawSniff() - { - using (var port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One)) - { - port.ReadTimeout = 500; - port.Open(); - - Console.WriteLine("Listening for 5 seconds..."); - DateTime end = DateTime.Now.AddSeconds(5); - - while (DateTime.Now < end) - { - try - { - int b = port.ReadByte(); - Console.Write($"{b:X2} "); - } - catch (TimeoutException) - { - } - } - - Console.WriteLine("\nDone."); - } - } - - } -} \ No newline at end of file diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/DiagnosticLedParserTest.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/DiagnosticLedParserTest.cs deleted file mode 100644 index 89a70f117..000000000 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/diagnosticLed/DiagnosticLedParserTest.cs +++ /dev/null @@ -1,189 +0,0 @@ -using JetBrains.Annotations; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.parserer; - -namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed -{ - [TestClass] - [TestSubject(typeof(DiagnosticLedParser))] - public class DiagnosticLedParserTest - { - private static string WithChecksum(string bodyWithoutChecksum) - { - byte sum = 0; - foreach (char c in bodyWithoutChecksum) - sum += (byte)c; - - return bodyWithoutChecksum + sum.ToString("X2") + "\r\n"; - } - - [TestMethod] - public void Parse_DiagnosticLed_State1() - { - string body = - "FFFF9C\t" + // signed 24-bit ADC = -100 - "2020\t" + // field strength - "FFFA\t" + // raw flow (-6) - "0050FC\t" + // raw volume - "0054\t"; // capacitor mV - - string line = WithChecksum(body); - - var parser = new DiagnosticLedParser(DiagnosticLedState.State1); - var data = (DiagnosticLedState1Data)parser.ParseLine(line); - - Assert.AreEqual(-100, data.Adc24); - Assert.AreEqual((ushort)0x2020, data.FieldStrength); - Assert.AreEqual((short)-6, data.RawFlow); - Assert.AreEqual((uint)0x0050FC, data.RawVolume); - Assert.AreEqual((ushort)0x0054, data.CapacitorMv); - } - - - [TestMethod] - public void Parse_DiagnosticLed_State2() - { - string line = - "00004F\t029A\t0000\tFFD3B1\t005C\t3B9AC9B1\t02\t01\t0D\r\n"; - - var parser = new DiagnosticLedParser(DiagnosticLedState.State2); - var data = (DiagnosticLedState2Data)parser.ParseLine(line); - - Assert.AreEqual(79, data.Adc24); - Assert.AreEqual((ushort)666, data.FieldStrength); - Assert.AreEqual((short)0, data.RawFlow); - Assert.AreEqual(0xFFD3B1u, data.RawVolume); - Assert.AreEqual((ushort)92, data.CapacitorMv); - Assert.AreEqual(0x3B9AC9B1u, data.LcdVolume); - Assert.AreEqual((byte)0x02, data.MeterState); - Assert.IsTrue(data.IsLowFlowCutoff); - } - - - [TestMethod] - public void Parse_DiagnosticLed_State3() - { - string body = - "FFCC09\t2020\tFFFA\t0050FC\t0054\t0B01\t048000\tA7\t"; - - string line = WithChecksum(body); - - var parser = new DiagnosticLedParser(DiagnosticLedState.State3); - var data = (DiagnosticLedState3Data)parser.ParseLine(line); - - Assert.AreEqual(-13303, data.Adc24); - Assert.AreEqual((ushort)0x2020, data.FieldStrength); - Assert.AreEqual((short)-6, data.RawFlow); - Assert.AreEqual((uint)0x0050FC, data.RawVolume); - Assert.AreEqual((ushort)0x0054, data.CapacitorMv); - Assert.AreEqual((ushort)0x0B01, data.FieldCalibration); - Assert.AreEqual((uint)0x048000, data.AsicTimestamp); - Assert.AreEqual((byte)0xA7, data.FieldDriveTimeUs); - } - - - [TestMethod] - public void Parse_DiagnosticLed_State4() - { - string body = - "000ABC\t2020\tFFFA\t0050FC\t0054\t0B01\t048000\tA7\t" + - "00001234\t00F0\t00F1\t0100\t0200\t03\t"; - - string line = WithChecksum(body); - - var parser = new DiagnosticLedParser(DiagnosticLedState.State4); - var data = (DiagnosticLedState4Data)parser.ParseLine(line); - - Assert.AreEqual(2748, data.Adc24); - Assert.AreEqual((ushort)0x2020, data.FieldStrength); - Assert.AreEqual((short)-6, data.RawFlow); - Assert.AreEqual((uint)0x0050FC, data.RawVolume); - Assert.AreEqual((ushort)0x0054, data.CapacitorMv); - - Assert.AreEqual((ushort)0x0B01, data.FieldCalibration); - Assert.AreEqual((uint)0x048000, data.AsicTimestamp); - Assert.AreEqual((byte)0xA7, data.FieldDriveTimeUs); - - Assert.AreEqual(0x00001234, data.MeanFlowRate); - Assert.AreEqual((ushort)0x00F0, data.Field1Measurement); - Assert.AreEqual((ushort)0x00F1, data.Field2Measurement); - Assert.AreEqual((ushort)0x0100, data.IntegratorCalibrationPositive); - Assert.AreEqual((ushort)0x0200, data.IntegratorCalibrationNegative); - Assert.AreEqual((byte)0x03, data.AsicState); - } - - [TestMethod] - public void Parse_DiagnosticLed_State5() - { - string body = - "FFCC09\t2020\tFFFA\t0050FC\t0054\t0B01\t048000\tA7\t" + - "00001234\t00F0\t00F1\t0100\t0200\t03\tFFEC\t"; - - string line = WithChecksum(body); - - var parser = new DiagnosticLedParser(DiagnosticLedState.State5); - var data = (DiagnosticLedState5Data)parser.ParseLine(line); - - Assert.AreEqual((short)-20, data.WaterImpedance); - Assert.AreEqual((byte)0x03, data.AsicState); - } - - [TestMethod] - public void Parse_DiagnosticLed_State6() - { - string body = - "FFCC09\t2020\tFFFA\t0050FC\t0054\t0B01\t048000\tA7\t" + - "00001234\t00F0\t00F1\t0100\t0200\t03\tFFEC\t0010\t" + - "02\t" + // pp spike detection - "02\t" + // ll pipe status - "00000099\t" + // LCD volume - "01\t"; // ASIC state1 - - - string line = WithChecksum(body); - - var parser = new DiagnosticLedParser(DiagnosticLedState.State6); - var data = (DiagnosticLedState6Data)parser.ParseLine(line); - - Assert.AreEqual((short)-20, data.WaterImpedance); - Assert.AreEqual((short)0x0010, data.ElectrodeDeltaMv); - Assert.AreEqual((byte)0x02, data.SpikeDetection); - Assert.AreEqual((byte)0x02, data.PipeStatus); - Assert.AreEqual((uint)0x99, data.LcdVolume); - Assert.AreEqual((byte)0x01, data.AsicState1); - } - - [TestMethod] - public void Parse_DiagnosticLed_State7() - { - string body = - "FFCC09\t2020\tFFFA\t0050FC\t0054\t0B01\t048000\tA7\t" + - "00001234\t00F0\t00F1\t0100\t0200\t03\tFFEC\t0010\t" + - "02\t" + // pp spike detection - "02\t" + // ll pipe status - "00000099\t" + // LCD volume - "01\t" + // ASIC state1 - "FFAA10\t" + // raw ADC before offset - "000123\t" + // detrended ADC - "FFEE\t" + // imaginary water impedance - "0011\t" + // electrode voltage noise - "03\t"; // ADC offset learning status - - string line = WithChecksum(body); - - var parser = new DiagnosticLedParser(DiagnosticLedState.State7); - var data = (DiagnosticLedState7Data)parser.ParseLine(line); - - Assert.AreEqual(-22000, data.RawAdcBeforeOffset); - Assert.AreEqual(0x000123, data.DetrendedAdc); - Assert.AreEqual((short)-18, data.ImaginaryWaterImpedance); - Assert.AreEqual((ushort)0x0011, data.ElectrodeVoltageNoise); - Assert.AreEqual((byte)0x03, data.AdcOffsetLearningStatus); - } - - - - - } -} \ No newline at end of file diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ShortVariableLedParserTest.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ShortVariableLedParserTest.cs deleted file mode 100644 index b113ec2b6..000000000 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/ShortVariableLedParserTest.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using JetBrains.Annotations; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.led; - -namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.led -{ - [TestClass] - [TestSubject(typeof(ShortVariableLedParser))] - public class ShortVariableLedParserTest - { - - [TestMethod] - public void Parse_ValidShortVariableMessage() - { - // Arrange - string raw = ";12345678,00012345.67;"; - var message = new TouchReadLedMessage(raw); - var parser = new ShortVariableLedParser(); - - // Act - TouchReadLedData data = parser.Parse(message); - - // Assert - Assert.IsNotNull(data); - Assert.AreEqual(raw, data.Raw); - Assert.AreEqual("12345678", data.MeterId); - Assert.AreEqual(12345.67m, data.Reading); - } - - [TestMethod] - [ExpectedException(typeof(FormatException))] - public void Parse_InvalidDecimal_Throws() - { - // Arrange - string raw = ";12345678,ABCDEF;"; - var message = new TouchReadLedMessage(raw); - var parser = new ShortVariableLedParser(); - - // Act - parser.Parse(message); - } - } -} \ No newline at end of file diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedMessageTest.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedMessageTest.cs deleted file mode 100644 index 5eb084082..000000000 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/led/TouchReadLedMessageTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using JetBrains.Annotations; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.led; - -namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.led -{ - [TestClass] - [TestSubject(typeof(TouchReadLedMessage))] - public class TouchReadLedMessageTest - { - - [TestMethod] - public void Parse_LedMessage_Basic() - { - string raw = ";12345678,00012345.67;"; - - var msg = new TouchReadLedMessage(raw); - - Assert.AreEqual(2, msg.Fields.Length); - Assert.AreEqual("12345678", msg.Fields[0]); - Assert.AreEqual("00012345.67", msg.Fields[1]); - } - - [TestMethod] - public void TouchReadLedData_Parse_Extended() - { - string raw = ";12345678,ABC123,00012345.67,m3;"; - - var msg = new TouchReadLedMessage(raw); - - var data = new TouchReadLedData(raw) - { - MeterId = msg.Fields[0], - CustomerId = msg.Fields[1], - Reading = TouchReadLedData.ParseDecimal(msg.Fields[2]), - Units = msg.Fields[3] - }; - - Assert.AreEqual("12345678", data.MeterId); - Assert.AreEqual("ABC123", data.CustomerId); - Assert.AreEqual(12345.67m, data.Reading); - Assert.AreEqual("m3", data.Units); - } - } -} \ No newline at end of file diff --git a/TBFTests/TBFTests.csproj b/TBFTests/TBFTests.csproj index 0226c233e..cd6a043f3 100644 --- a/TBFTests/TBFTests.csproj +++ b/TBFTests/TBFTests.csproj @@ -103,12 +103,6 @@ - - - - - - diff --git a/packages/Antlr3.Runtime.3.5.1/.signature.p7s b/packages/Antlr3.Runtime.3.5.1/.signature.p7s deleted file mode 100644 index 186744ebd..000000000 Binary files a/packages/Antlr3.Runtime.3.5.1/.signature.p7s and /dev/null differ diff --git a/packages/Antlr3.Runtime.3.5.1/Antlr3.Runtime.3.5.1.nupkg b/packages/Antlr3.Runtime.3.5.1/Antlr3.Runtime.3.5.1.nupkg deleted file mode 100644 index b37b2f63c..000000000 Binary files a/packages/Antlr3.Runtime.3.5.1/Antlr3.Runtime.3.5.1.nupkg and /dev/null differ diff --git a/packages/Antlr3.Runtime.3.5.1/lib/net20/Antlr3.Runtime.dll b/packages/Antlr3.Runtime.3.5.1/lib/net20/Antlr3.Runtime.dll deleted file mode 100644 index 2bf359a63..000000000 Binary files a/packages/Antlr3.Runtime.3.5.1/lib/net20/Antlr3.Runtime.dll and /dev/null differ diff --git a/packages/Antlr3.Runtime.3.5.1/lib/net20/Antlr3.Runtime.xml b/packages/Antlr3.Runtime.3.5.1/lib/net20/Antlr3.Runtime.xml deleted file mode 100644 index 565e15d57..000000000 --- a/packages/Antlr3.Runtime.3.5.1/lib/net20/Antlr3.Runtime.xml +++ /dev/null @@ -1,3249 +0,0 @@ - - - - Antlr3.Runtime - - - - - This is a char buffer stream that is loaded from a file - all at once when you construct the object. This looks very - much like an ANTLReader or ANTLRInputStream, but it's a special case - since we know the exact size of the object to load. We can avoid lots - of data copying. - - - - - A kind of ReaderStream that pulls from an InputStream. - Useful for reading from stdin and specifying file encodings etc... - - - - - Vacuum all input from a Reader and then treat it like a StringStream. - Manage the buffer manually to avoid unnecessary data copying. - - - - If you need encoding, use ANTLRInputStream. - - - - - A pretty quick CharStream that pulls all data from an array - directly. Every method call counts in the lexer. Java's - strings aren't very good so I'm avoiding. - - - - The data being scanned - - - How many characters are actually in the buffer - - - 0..n-1 index into string of next char - - - line number 1..n within the input - - - The index of the character relative to the beginning of the line 0..n-1 - - - tracks how deep mark() calls are nested - - - - A list of CharStreamState objects that tracks the stream state - values line, charPositionInLine, and p that can change as you - move through the input stream. Indexed from 1..markDepth. - A null is kept @ index 0. Create upon first call to mark(). - - - - Track the last mark() call result value for use in rewind(). - - - What is name or source of this char stream? - - - Copy data in string to a local char array - - - This is the preferred constructor as no data is copied - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the index of char to - be returned from LA(1). - - - - - Reset the stream so that it's in the same state it was - when the object was created *except* the data array is not - touched. - - - - - consume() ahead until p==index; can't just set p=index as we must - update line and charPositionInLine. - - - - - A generic recognizer that can handle recognizers generated from - lexer, parser, and tree grammars. This is all the parsing - support code essentially; most of it is error recovery stuff and - backtracking. - - - - - State of a lexer, parser, or tree parser are collected into a state - object so the state can be shared. This sharing is needed to - have one grammar import others and share same error variables - and other state variables. It's a kind of explicit multiple - inheritance via delegation of methods and shared state. - - - - reset the parser's state; subclasses must rewinds the input stream - - - - Match current input symbol against ttype. Attempt - single token insertion or deletion error recovery. If - that fails, throw MismatchedTokenException. - - - - To turn off single token insertion or deletion error - recovery, override recoverFromMismatchedToken() and have it - throw an exception. See TreeParser.recoverFromMismatchedToken(). - This way any error in a rule will cause an exception and - immediate exit from rule. Rule would recover by resynchronizing - to the set of symbols that can follow rule ref. - - - - Match the wildcard: in a symbol - - - Report a recognition problem. - - - This method sets errorRecovery to indicate the parser is recovering - not parsing. Once in recovery mode, no errors are generated. - To get out of recovery mode, the parser must successfully match - a token (after a resync). So it will go: - - 1. error occurs - 2. enter recovery mode, report error - 3. consume until token found in resynch set - 4. try to resume parsing - 5. next match() will reset errorRecovery mode - - If you override, make sure to update syntaxErrors if you care about that. - - - - What error message should be generated for the various exception types? - - - Not very object-oriented code, but I like having all error message - generation within one method rather than spread among all of the - exception classes. This also makes it much easier for the exception - handling because the exception classes do not have to have pointers back - to this object to access utility routines and so on. Also, changing - the message for an exception type would be difficult because you - would have to subclassing exception, but then somehow get ANTLR - to make those kinds of exception objects instead of the default. - This looks weird, but trust me--it makes the most sense in terms - of flexibility. - - For grammar debugging, you will want to override this to add - more information such as the stack frame with - getRuleInvocationStack(e, this.getClass().getName()) and, - for no viable alts, the decision description and state etc... - - Override this to change the message generated for one or more - exception types. - - - - - Get number of recognition errors (lexer, parser, tree parser). Each - recognizer tracks its own number. So parser and lexer each have - separate count. Does not count the spurious errors found between - an error and next valid token match - - - - - - What is the error header, normally line/character position information? - - - - How should a token be displayed in an error message? The default - is to display just the text, but during development you might - want to have a lot of information spit out. Override in that case - to use t.ToString() (which, for CommonToken, dumps everything about - the token). This is better than forcing you to override a method in - your token objects because you don't have to go modify your lexer - so that it creates a new Java type. - - - - Override this method to change where error messages go - - - - Recover from an error found on the input stream. This is - for NoViableAlt and mismatched symbol exceptions. If you enable - single token insertion and deletion, this will usually not - handle mismatched symbol exceptions but there could be a mismatched - token that the match() routine could not recover from. - - - - - A hook to listen in on the token consumption during error recovery. - The DebugParser subclasses this to fire events to the listenter. - - - - - Compute the context-sensitive FOLLOW set for current rule. - This is set of token types that can follow a specific rule - reference given a specific call chain. You get the set of - viable tokens that can possibly come next (lookahead depth 1) - given the current call chain. Contrast this with the - definition of plain FOLLOW for rule r: - - - FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)} - - where x in T* and alpha, beta in V*; T is set of terminals and - V is the set of terminals and nonterminals. In other words, - FOLLOW(r) is the set of all tokens that can possibly follow - references to r in *any* sentential form (context). At - runtime, however, we know precisely which context applies as - we have the call chain. We may compute the exact (rather - than covering superset) set of following tokens. - - For example, consider grammar: - - stat : ID '=' expr ';' // FOLLOW(stat)=={EOF} - | "return" expr '.' - ; - expr : atom ('+' atom)* ; // FOLLOW(expr)=={';','.',')'} - atom : INT // FOLLOW(atom)=={'+',')',';','.'} - | '(' expr ')' - ; - - The FOLLOW sets are all inclusive whereas context-sensitive - FOLLOW sets are precisely what could follow a rule reference. - For input input "i=(3);", here is the derivation: - - stat => ID '=' expr ';' - => ID '=' atom ('+' atom)* ';' - => ID '=' '(' expr ')' ('+' atom)* ';' - => ID '=' '(' atom ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ';' - - At the "3" token, you'd have a call chain of - - stat -> expr -> atom -> expr -> atom - - What can follow that specific nested ref to atom? Exactly ')' - as you can see by looking at the derivation of this specific - input. Contrast this with the FOLLOW(atom)={'+',')',';','.'}. - - You want the exact viable token set when recovering from a - token mismatch. Upon token mismatch, if LA(1) is member of - the viable next token set, then you know there is most likely - a missing token in the input stream. "Insert" one by just not - throwing an exception. - - - Attempt to recover from a single missing or extra token. - - EXTRA TOKEN - - LA(1) is not what we are looking for. If LA(2) has the right token, - however, then assume LA(1) is some extra spurious token. Delete it - and LA(2) as if we were doing a normal match(), which advances the - input. - - MISSING TOKEN - - If current token is consistent with what could come after - ttype then it is ok to "insert" the missing token, else throw - exception For example, Input "i=(3;" is clearly missing the - ')'. When the parser returns from the nested call to expr, it - will have call chain: - - stat -> expr -> atom - - and it will be trying to match the ')' at this point in the - derivation: - - => ID '=' '(' INT ')' ('+' atom)* ';' - ^ - match() will see that ';' doesn't match ')' and report a - mismatched token error. To recover, it sees that LA(1)==';' - is in the set of tokens that can follow the ')' token - reference in rule atom. It can assume that you forgot the ')'. - - - Not currently used - - - - Match needs to return the current input symbol, which gets put - into the label for the associated token ref; e.g., x=ID. Token - and tree parsers need to return different objects. Rather than test - for input stream type or change the IntStream interface, I use - a simple method to ask the recognizer to tell me what the current - input symbol is. - - - This is ignored for lexers. - - - Conjure up a missing token during error recovery. - - - The recognizer attempts to recover from single missing - symbols. But, actions might refer to that missing symbol. - For example, x=ID {f($x);}. The action clearly assumes - that there has been an identifier matched previously and that - $x points at that token. If that token is missing, but - the next token in the stream is what we want we assume that - this token is missing and we keep going. Because we - have to return some token to replace the missing token, - we have to conjure one up. This method gives the user control - over the tokens returned for missing tokens. Mostly, - you will want to create something special for identifier - tokens. For literals such as '{' and ',', the default - action in the parser or tree parser works. It simply creates - a CommonToken of the appropriate type. The text will be the token. - If you change what tokens must be created by the lexer, - override this method to create the appropriate tokens. - - - - Consume tokens until one matches the given token set - - - Push a rule's follow set using our own hardcoded stack - - - - Return of the rules in your parser instance - leading up to a call to this method. You could override if - you want more details such as the file/line info of where - in the parser java code a rule is invoked. - - - - This is very useful for error messages and for context-sensitive - error recovery. - - - - - A more general version of GetRuleInvocationStack where you can - pass in the StackTrace of, for example, a RecognitionException - to get it's rule stack trace. - - - - Return whether or not a backtracking attempt failed. - - - - Used to print out token names like ID during debugging and - error reporting. The generated parsers implement a method - that overrides this to point to their String[] tokenNames. - - - - - For debugging and other purposes, might want the grammar name. - Have ANTLR generate an implementation for this method. - - - - - A convenience method for use most often with template rewrites. - Convert a list of to a list of . - - - - - Given a rule number and a start token index number, return - MEMO_RULE_UNKNOWN if the rule has not parsed input starting from - start index. If this rule has parsed input starting from the - start index before, then return where the rule stopped parsing. - It returns the index of the last token matched by the rule. - - - - For now we use a hashtable and just the slow Object-based one. - Later, we can make a special one for ints and also one that - tosses out data after we commit past input position i. - - - - - Has this rule already parsed input at the current index in the - input stream? Return the stop token index or MEMO_RULE_UNKNOWN. - If we attempted but failed to parse properly before, return - MEMO_RULE_FAILED. - - - - This method has a side-effect: if we have seen this input for - this rule and successfully parsed before, then seek ahead to - 1 past the stop token matched for this rule last time. - - - - - Record whether or not this rule parsed the input at this position - successfully. Use a standard java hashtable for now. - - - - return how many rule/input-index pairs there are in total. - TODO: this includes synpreds. :( - - - - A stripped-down version of org.antlr.misc.BitSet that is just - good enough to handle runtime requirements such as FOLLOW sets - for automatic error recovery. - - - - - We will often need to do a mod operator (i mod nbits). Its - turns out that, for powers of two, this mod operation is - same as (i & (nbits-1)). Since mod is slow, we use a - precomputed mod mask to do the mod instead. - - - - The actual data bits - - - Construct a bitset of size one word (64 bits) - - - Construction from a static array of longs - - - Construction from a list of integers - - - Construct a bitset given the size - The size of the bitset in bits - - - return this | a in a new set - - - or this element into this set (grow as necessary to accommodate) - - - Grows the set to a larger number of bits. - element that must fit in set - - - Sets the size of a set. - how many words the new set should be - - - return how much space is being used by the bits array not how many actually have member bits on. - - - Is this contained within a? - - - Buffer all input tokens but do on-demand fetching of new tokens from - lexer. Useful when the parser or lexer has to set context/mode info before - proper lexing of future tokens. The ST template parser needs this, - for example, because it has to constantly flip back and forth between - inside/output templates. E.g., <names:{hi, <it>}> has to parse names - as part of an expression but "hi, <it>" as a nested template. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - (UnbufferedTokenStream is the same way.) - - This is not a subclass of UnbufferedTokenStream because I don't want - to confuse small moving window of tokens it uses for the full buffer. - - - Record every single token pulled from the source so we can reproduce - chunks of it later. The buffer in LookaheadStream overlaps sometimes - as its moving window moves through the input. This list captures - everything so we can access complete input text. - - - Track the last mark() call result value for use in rewind(). - - - The index into the tokens list of the current token (next token - to consume). tokens[p] should be LT(1). p=-1 indicates need - to initialize with first token. The ctor doesn't get a token. - First call to LT(1) or whatever gets the first token and sets p=0; - - - - How deep have we gone? - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - Walk past any token not on the channel the parser is listening to. - - - Make sure index i in tokens has a token. - - - add n elements to buffer - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - When walking ahead with cyclic DFA or for syntactic predicates, - we need to record the state of the input stream (char index, - line, etc...) so that we can rewind the state after scanning ahead. - - - This is the complete state of a stream. - - - Index into the char stream of next lookahead char - - - What line number is the scanner at before processing buffer[p]? - - - What char position 0..n-1 in line is scanner before processing buffer[p]? - - - - A Token object like we'd use in ANTLR 2.x; has an actual string created - and associated with this object. These objects are needed for imaginary - tree nodes that have payload objects. We need to create a Token object - that has a string; the tree node will point at this token. CommonToken - has indexes into a char stream and hence cannot be used to introduce - new strings. - - - - What token number is this from 0..n-1 tokens - - - - We need to be able to change the text once in a while. If - this is non-null, then getText should return this. Note that - start/stop are not affected by changing this. - - - - What token number is this from 0..n-1 tokens; < 0 implies invalid index - - - The char position into the input buffer where this token starts - - - The char position into the input buffer where this token stops - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - Reset this token stream by setting its token source. - - - Always leave p on an on-channel token. - - - Given a starting index, return the index of the first on-channel - token. - - - All debugging events that a recognizer can trigger. - - - I did not create a separate AST debugging interface as it would create - lots of extra classes and DebugParser has a dbg var defined, which makes - it hard to change to ASTDebugEventListener. I looked hard at this issue - and it is easier to understand as one monolithic event interface for all - possible events. Hopefully, adding ST debugging stuff won't be bad. Leave - for future. 4/26/2006. - - - - - The parser has just entered a rule. No decision has been made about - which alt is predicted. This is fired AFTER init actions have been - executed. Attributes are defined and available etc... - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - - Because rules can have lots of alternatives, it is very useful to - know which alt you are entering. This is 1..n for n alts. - - - - - This is the last thing executed before leaving a rule. It is - executed even if an exception is thrown. This is triggered after - error reporting and recovery have occurred (unless the exception is - not caught in this rule). This implies an "exitAlt" event. - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - Track entry into any (...) subrule other EBNF construct - - - - Every decision, fixed k or arbitrary, has an enter/exit event - so that a GUI can easily track what LT/consume events are - associated with prediction. You will see a single enter/exit - subrule but multiple enter/exit decision events, one for each - loop iteration. - - - - - An input token was consumed; matched by any kind of element. - Trigger after the token was matched by things like match(), matchAny(). - - - - - An off-channel input token was consumed. - Trigger after the token was matched by things like match(), matchAny(). - (unless of course the hidden token is first stuff in the input stream). - - - - - Somebody (anybody) looked ahead. Note that this actually gets - triggered by both LA and LT calls. The debugger will want to know - which Token object was examined. Like consumeToken, this indicates - what token was seen at that depth. A remote debugger cannot look - ahead into a file it doesn't have so LT events must pass the token - even if the info is redundant. - - - - - The parser is going to look arbitrarily ahead; mark this location, - the token stream's marker is sent in case you need it. - - - - - After an arbitrairly long lookahead as with a cyclic DFA (or with - any backtrack), this informs the debugger that stream should be - rewound to the position associated with marker. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. - - - - - To watch a parser move through the grammar, the parser needs to - inform the debugger what line/charPos it is passing in the grammar. - For now, this does not know how to switch from one grammar to the - other and back for island grammars etc... - - - - This should also allow breakpoints because the debugger can stop - the parser whenever it hits this line/pos. - - - - - A recognition exception occurred such as NoViableAltException. I made - this a generic event so that I can alter the exception hierachy later - without having to alter all the debug objects. - - - - Upon error, the stack of enter rule/subrule must be properly unwound. - If no viable alt occurs it is within an enter/exit decision, which - also must be rewound. Even the rewind for each mark must be unwount. - In the Java target this is pretty easy using try/finally, if a bit - ugly in the generated code. The rewind is generated in DFA.predict() - actually so no code needs to be generated for that. For languages - w/o this "finally" feature (C++?), the target implementor will have - to build an event stack or something. - - Across a socket for remote debugging, only the RecognitionException - data fields are transmitted. The token object or whatever that - caused the problem was the last object referenced by LT. The - immediately preceding LT event should hold the unexpected Token or - char. - - Here is a sample event trace for grammar: - - b : C ({;}A|B) // {;} is there to prevent A|B becoming a set - | D - ; - - The sequence for this rule (with no viable alt in the subrule) for - input 'c c' (there are 3 tokens) is: - - commence - LT(1) - enterRule b - location 7 1 - enter decision 3 - LT(1) - exit decision 3 - enterAlt1 - location 7 5 - LT(1) - consumeToken [c/<4>,1:0] - location 7 7 - enterSubRule 2 - enter decision 2 - LT(1) - LT(1) - recognitionException NoViableAltException 2 1 2 - exit decision 2 - exitSubRule 2 - beginResync - LT(1) - consumeToken [c/<4>,1:1] - LT(1) - endResync - LT(-1) - exitRule b - terminate - - - - - Indicates the recognizer is about to consume tokens to resynchronize - the parser. Any consume events from here until the recovered event - are not part of the parse--they are dead tokens. - - - - - Indicates that the recognizer has finished consuming tokens in order - to resychronize. There may be multiple beginResync/endResync pairs - before the recognizer comes out of errorRecovery mode (in which - multiple errors are suppressed). This will be useful - in a gui where you want to probably grey out tokens that are consumed - but not matched to anything in grammar. Anything between - a beginResync/endResync pair was tossed out by the parser. - - - - A semantic predicate was evaluate with this result and action text - - - - Announce that parsing has begun. Not technically useful except for - sending events over a socket. A GUI for example will launch a thread - to connect and communicate with a remote parser. The thread will want - to notify the GUI when a connection is made. ANTLR parsers - trigger this upon entry to the first rule (the ruleLevel is used to - figure this out). - - - - - Parsing is over; successfully or not. Mostly useful for telling - remote debugging listeners that it's time to quit. When the rule - invocation level goes to zero at the end of a rule, we are done - parsing. - - - - - Input for a tree parser is an AST, but we know nothing for sure - about a node except its type and text (obtained from the adaptor). - This is the analog of the consumeToken method. Again, the ID is - the hashCode usually of the node so it only works if hashCode is - not implemented. If the type is UP or DOWN, then - the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - - - The tree parser lookedahead. If the type is UP or DOWN, - then the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - A nil was created (even nil nodes have a unique ID... - they are not "null" per se). As of 4/28/2006, this - seems to be uniquely triggered when starting a new subtree - such as when entering a subrule in automatic mode and when - building a tree in rewrite mode. - - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - - Upon syntax error, recognizers bracket the error with an error node - if they are building ASTs. - - - - - - Announce a new node built from token elements such as type etc... - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID, type, text are - set. - - - - Announce a new node built from an existing token. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only node.ID and token.tokenIndex - are set. - - - - Make a node the new root of an existing root. See - - - Note: the newRootID parameter is possibly different - than the TreeAdaptor.becomeRoot() newRoot parameter. - In our case, it will always be the result of calling - TreeAdaptor.becomeRoot() and not root_n or whatever. - - The listener should assume that this event occurs - only when the current subrule (or rule) subtree is - being reset to newRootID. - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Make childID a child of rootID. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Set the token start/stop token index for a subtree root or node. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - A DFA implemented as a set of transition tables. - - - Any state that has a semantic predicate edge is special; those states - are generated with if-then-else structures in a specialStateTransition() - which is generated by cyclicDFA template. - - There are at most 32767 states (16-bit signed short). - Could get away with byte sometimes but would have to generate different - types and the simulation code too. For a point of reference, the Java - lexer's Tokens rule DFA has 326 states roughly. - - - - Which recognizer encloses this DFA? Needed to check backtracking - - - - From the input stream, predict what alternative will succeed - using this DFA (representing the covering regular approximation - to the underlying CFL). Return an alternative number 1..n. Throw - an exception upon error. - - - - A hook for debugging interface - - - - Given a String that has a run-length-encoding of some unsigned shorts - like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid - static short[] which generates so much init code that the class won't - compile. :( - - - - Hideous duplication of code, but I need different typed arrays out :( - - - The recognizer did not match anything for a (..)+ loop. - - - - A semantic predicate failed during validation. Validation of predicates - occurs when normally parsing the alternative just like matching a token. - Disambiguating predicate evaluation occurs when we hoist a predicate into - a prediction decision. - - - - AST rules have trees - - - Has a value potentially if output=AST; - - - AST rules have trees - - - Has a value potentially if output=AST; - - - A source of characters for an ANTLR lexer - - - - For infinite streams, you don't need this; primarily I'm providing - a useful interface for action code. Just make sure actions don't - use this on streams that don't support it. - - - - - Get the ith character of lookahead. This is the same usually as - LA(i). This will be used for labels in the generated - lexer code. I'd prefer to return a char here type-wise, but it's - probably better to be 32-bit clean and be consistent with LA. - - - - ANTLR tracks the line information automatically - Because this stream can rewind, we need to be able to reset the line - - - The index of the character relative to the beginning of the line 0..n-1 - - - - A simple stream of integers used when all I care about is the char - or token type sequence (such as interpretation). - - - - - Get int at current input pointer + i ahead where i=1 is next int. - Negative indexes are allowed. LA(-1) is previous token (token - just matched). LA(-i) where i is before first token should - yield -1, invalid char / EOF. - - - - - Tell the stream to start buffering if it hasn't already. Return - current input position, Index, or some other marker so that - when passed to rewind() you get back to the same spot. - rewind(mark()) should not affect the input cursor. The Lexer - track line/col info as well as input index so its markers are - not pure input indexes. Same for tree node streams. - - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the symbol about to be - read not the most recently read symbol. - - - - - Reset the stream so that next call to index would return marker. - The marker will usually be Index but it doesn't have to be. It's - just a marker to indicate what state the stream was in. This is - essentially calling release() and seek(). If there are markers - created after this marker argument, this routine must unroll them - like a stack. Assume the state the stream was in when this marker - was created. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. It is - like invoking rewind(last marker) but it should not "pop" - the marker off. It's like seek(last marker's input position). - - - - - You may want to commit to a backtrack but don't want to force the - stream to keep bookkeeping objects around for a marker that is - no longer necessary. This will have the same behavior as - rewind() except it releases resources without the backward seek. - This must throw away resources for all markers back to the marker - argument. So if you're nested 5 levels of mark(), and then release(2) - you have to release resources for depths 2..5. - - - - - Set the input cursor to the position indicated by index. This is - normally used to seek ahead in the input stream. No buffering is - required to do this unless you know your stream will use seek to - move backwards such as when backtracking. - - - - This is different from rewind in its multi-directional - requirement and in that its argument is strictly an input cursor (index). - - For char streams, seeking forward must update the stream state such - as line number. For seeking backwards, you will be presumably - backtracking using the mark/rewind mechanism that restores state and - so this method does not need to update state when seeking backwards. - - Currently, this method is only used for efficient backtracking using - memoization, but in the future it may be used for incremental parsing. - - The index is 0..n-1. A seek to position i means that LA(1) will - return the ith symbol. So, seeking to 0 means LA(1) will return the - first element in the stream. - - - - - Only makes sense for streams that buffer everything up probably, but - might be useful to display the entire stream or for testing. This - value includes a single EOF. - - - - - Where are you getting symbols from? Normally, implementations will - pass the buck all the way to the lexer who can ask its input stream - for the file name or whatever. - - - - - Rules can have start/stop info. - - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - - Rules can have start/stop info. - - The element type of the input stream. - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - Get the text of the token - - - The line number on which this token was matched; line=1..n - - - The index of the first character relative to the beginning of the line 0..n-1 - - - - An index from 0..n-1 of the token object in the input stream. - This must be valid in order to use the ANTLRWorks debugger. - - - - - From what character stream was this token created? You don't have to - implement but it's nice to know where a Token comes from if you have - include files etc... on the input. - - - - - A source of tokens must provide a sequence of tokens via nextToken() - and also must reveal it's source of characters; CommonToken's text is - computed from a CharStream; it only store indices into the char stream. - - - - Errors from the lexer are never passed to the parser. Either you want - to keep going or you do not upon token recognition error. If you do not - want to continue lexing then you do not want to continue parsing. Just - throw an exception not under RecognitionException and Java will naturally - toss you all the way out of the recognizers. If you want to continue - lexing then you should not throw an exception to the parser--it has already - requested a token. Keep lexing until you get a valid one. Just report - errors and keep going, looking for a valid token. - - - - - Return a Token object from your input stream (usually a CharStream). - Do not fail/return upon lexing error; keep chewing on the characters - until you get a good one; errors are not passed through to the parser. - - - - - Where are you getting tokens from? normally the implication will simply - ask lexers input stream. - - - - A stream of tokens accessing tokens from a TokenSource - - - Get Token at current input pointer + i ahead where i=1 is next Token. - i<0 indicates tokens in the past. So -1 is previous token and -2 is - two tokens ago. LT(0) is undefined. For i>=n, return Token.EOFToken. - Return null for LT(0) and any index that results in an absolute address - that is negative. - - - - How far ahead has the stream been asked to look? The return - value is a valid index from 0..n-1. - - - - - Get a token at an absolute index i; 0..n-1. This is really only - needed for profiling and debugging and token stream rewriting. - If you don't want to buffer up tokens, then this method makes no - sense for you. Naturally you can't use the rewrite stream feature. - I believe DebugTokenStream can easily be altered to not use - this method, removing the dependency. - - - - - Where is this stream pulling tokens from? This is not the name, but - the object that provides Token objects. - - - - - Return the text of all tokens from start to stop, inclusive. - If the stream does not buffer all the tokens then it can just - return "" or null; Users should not access $ruleLabel.text in - an action of course in that case. - - - - - Because the user is not required to use a token with an index stored - in it, we must provide a means for two token objects themselves to - indicate the start/end location. Most often this will just delegate - to the other toString(int,int). This is also parallel with - the TreeNodeStream.toString(Object,Object). - - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - - Record every single token pulled from the source so we can reproduce - chunks of it later. - - - - Map from token type to channel to override some Tokens' channel numbers - - - Set of token types; discard any tokens with this type - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - By default, track all incoming tokens - - - Track the last mark() call result value for use in rewind(). - - - - The index into the tokens list of the current token (next token - to consume). p==-1 indicates that the tokens list is empty - - - - - How deep have we gone? - - - - Reset this token stream by setting its token source. - - - - Load all tokens from the token source and put in tokens. - This is done upon first LT request because you might want to - set some token type / channel overrides before filling buffer. - - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - - - Walk past any token not on the channel the parser is listening to. - - - - Given a starting index, return the index of the first on-channel token. - - - - A simple filter mechanism whereby you can tell this token stream - to force all tokens of type ttype to be on channel. For example, - when interpreting, we cannot exec actions so we need to tell - the stream to force all WS and NEWLINE to be a different, ignored - channel. - - - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - - Get the ith token from the current position 1..n where k=1 is the - first symbol of lookahead. - - - - Look backwards k tokens on-channel tokens - - - - Return absolute token i; ignore which channel the tokens are on; - that is, count all tokens not just on-channel tokens. - - - - - A lexer is recognizer that draws input symbols from a character stream. - lexer grammars result in a subclass of this object. A Lexer object - uses simplified match() and error recovery mechanisms in the interest - of speed. - - - - Where is the lexer drawing characters from? - - - - Gets or sets the text matched so far for the current token or any text override. - - - Setting this value replaces any previously set value, and overrides the original text. - - - - Return a token from this source; i.e., match a token on the char stream. - - - Returns the EOF token (default), if you need - to return a custom token instead override this method. - - - - Instruct the lexer to skip creating a token for current lexer rule - and look for another token. nextToken() knows to keep looking when - a lexer rule finishes with token set to SKIP_TOKEN. Recall that - if token==null at end of any token rule, it creates one for you - and emits it. - - - - This is the lexer entry point that sets instance var 'token' - - - - Currently does not support multiple emits per nextToken invocation - for efficiency reasons. Subclass and override this method and - nextToken (to push tokens into a list and pull from that list rather - than a single variable as this implementation does). - - - - - The standard method called to automatically emit a token at the - outermost lexical rule. The token object should point into the - char buffer start..stop. If there is a text override in 'text', - use that to set the token's text. Override this method to emit - custom Token objects. - - - - If you are building trees, then you should also override - Parser or TreeParser.getMissingSymbol(). - - - - What is the index of the current character of lookahead? - - - - Lexers can normally match any char in it's vocabulary after matching - a token, so do the easy thing and just kill a character and hope - it all works out. You can instead use the rule invocation stack - to do sophisticated error recovery if you are in a fragment rule. - - - - A queue that can dequeue and get(i) in O(1) and grow arbitrarily large. - A linked list is fast at dequeue but slow at get(i). An array is - the reverse. This is O(1) for both operations. - - List grows until you dequeue last element at end of buffer. Then - it resets to start filling at 0 again. If adds/removes are balanced, the - buffer will not grow too large. - - No iterator stuff as that's not how we'll use it. - - - dynamically-sized buffer of elements - - - index of next element to fill - - - - How deep have we gone? - - - - - Return element {@code i} elements ahead of current element. {@code i==0} - gets current element. This is not an absolute index into {@link #data} - since {@code p} defines the start of the real list. - - - - Get and remove first element in queue - - - Return string of current buffer contents; non-destructive - - - - A lookahead queue that knows how to mark/release locations in the buffer for - backtracking purposes. Any markers force the {@link FastQueue} superclass to - keep all elements until no more markers; then can reset to avoid growing a - huge buffer. - - - - Absolute token index. It's the index of the symbol about to be - read via {@code LT(1)}. Goes from 0 to numtokens. - - - This is the {@code LT(-1)} element for the first element in {@link #data}. - - - Track object returned by nextElement upon end of stream; - Return it later when they ask for LT passed end of input. - - - Track the last mark() call result value for use in rewind(). - - - tracks how deep mark() calls are nested - - - - Implement nextElement to supply a stream of elements to this - lookahead buffer. Return EOF upon end of the stream we're pulling from. - - - - - Get and remove first element in queue; override - {@link FastQueue#remove()}; it's the same, just checks for backtracking. - - - - Make sure we have at least one element to remove, even if EOF - - - - Make sure we have 'need' elements from current position p. Last valid - p index is data.size()-1. p+need-1 is the data index 'need' elements - ahead. If we need 1 element, (p+1-1)==p must be < data.size(). - - - - add n elements to buffer - - - Size of entire stream is unknown; we only know buffer size from FastQueue - - - - Seek to a 0-indexed absolute token index. Normally used to seek backwards - in the buffer. Does not force loading of nodes. - - - To preserve backward compatibility, this method allows seeking past the - end of the currently buffered data. In this case, the input pointer will - be moved but the data will only actually be loaded upon the next call to - {@link #consume} or {@link #LT} for {@code k>0}. - - - - A mismatched char or Token or tree node - - - - We were expecting a token but it's not found. The current token - is actually what we wanted next. Used for tree node errors too. - - - - - A parser for TokenStreams. "parser grammars" result in a subclass - of this. - - - - Gets or sets the token stream; resets the parser upon a set. - - - - Rules that return more than a single value must return an object - containing all the values. Besides the properties defined in - RuleLabelScope.predefinedRulePropertiesScope there may be user-defined - return values. This class simply defines the minimum properties that - are always defined and methods to access the others that might be - available depending on output option such as template and tree. - - - - Note text is not an actual property of the return value, it is computed - from start and stop using the input stream's toString() method. I - could add a ctor to this so that we can pass in and store the input - stream, but I'm not sure we want to do that. It would seem to be undefined - to get the .text property anyway if the rule matches tokens from multiple - input streams. - - I do not use getters for fields of objects that are used simply to - group values such as this aggregate. The getters/setters are there to - satisfy the superclass interface. - - - - The root of the ANTLR exception hierarchy. - - - To avoid English-only error messages and to generally make things - as flexible as possible, these exceptions are not created with strings, - but rather the information necessary to generate an error. Then - the various reporting methods in Parser and Lexer can be overridden - to generate a localized error message. For example, MismatchedToken - exceptions are built with the expected token type. - So, don't expect getMessage() to return anything. - - Note that as of Java 1.4, you can access the stack trace, which means - that you can compute the complete trace of rules from the start symbol. - This gives you considerable context information with which to generate - useful error messages. - - ANTLR generates code that throws exceptions upon recognition error and - also generates code to catch these exceptions in each rule. If you - want to quit upon first error, you can turn off the automatic error - handling mechanism using rulecatch action, but you still need to - override methods mismatch and recoverFromMismatchSet. - - In general, the recognition exceptions can track where in a grammar a - problem occurred and/or what was the expected input. While the parser - knows its state (such as current input symbol and line info) that - state can change before the exception is reported so current token index - is computed and stored at exception time. From this info, you can - perhaps print an entire line of input not just a single token, for example. - Better to just say the recognizer had a problem and then let the parser - figure out a fancy report. - - - - What input stream did the error occur in? - - - - What was the lookahead index when this exception was thrown? - - - - What is index of token/char were we looking at when the error occurred? - - - - The current Token when an error occurred. Since not all streams - can retrieve the ith Token, we have to track the Token object. - For parsers. Even when it's a tree parser, token might be set. - - - - - If this is a tree parser exception, node is set to the node with - the problem. - - - - The current char when an error occurred. For lexers. - - - - Track the line (1-based) at which the error occurred in case this is - generated from a lexer. We need to track this since the - unexpected char doesn't carry the line info. - - - - - The 0-based index into the line where the error occurred. - - - - - If you are parsing a tree node stream, you will encounter som - imaginary nodes w/o line/col info. We now search backwards looking - for most recent token with line/col info, but notify getErrorHeader() - that info is approximate. - - - - Used for remote debugger deserialization - - - Return the token type or char of the unexpected input element - - - - The set of fields needed by an abstract recognizer to recognize input - and recover from errors etc... As a separate state object, it can be - shared among multiple grammars; e.g., when one grammar imports another. - - - - These fields are publically visible but the actual state pointer per - parser is protected. - - - - - Track the set of token types that can follow any rule invocation. - Stack grows upwards. When it hits the max, it grows 2x in size - and keeps going. - - - - - This is true when we see an error and before having successfully - matched a token. Prevents generation of more than one error message - per error. - - - - - The index into the input stream where the last error occurred. - This is used to prevent infinite loops where an error is found - but no token is consumed during recovery...another error is found, - ad naseum. This is a failsafe mechanism to guarantee that at least - one token/tree node is consumed for two errors. - - - - - In lieu of a return value, this indicates that a rule or token - has failed to match. Reset to false upon valid token match. - - - - Did the recognizer encounter a syntax error? Track how many. - - - - If 0, no backtracking is going on. Safe to exec actions etc... - If >0 then it's the level of backtracking. - - - - - An array[size num rules] of dictionaries that tracks - the stop token index for each rule. ruleMemo[ruleIndex] is - the memoization table for ruleIndex. For key ruleStartIndex, you - get back the stop token for associated rule or MEMO_RULE_FAILED. - - - This is only used if rule memoization is on (which it is by default). - - - - The goal of all lexer rules/methods is to create a token object. - This is an instance variable as multiple rules may collaborate to - create a single token. nextToken will return this object after - matching lexer rule(s). If you subclass to allow multiple token - emissions, then set this to the last token to be matched or - something nonnull so that the auto token emit mechanism will not - emit another token. - - - - - What character index in the stream did the current token start at? - Needed, for example, to get the text for current token. Set at - the start of nextToken. - - - - The line on which the first character of the token resides - - - The character position of first character within the line - - - The channel number for the current token - - - The token type for the current token - - - - You can set the text for the current token to override what is in - the input char buffer. Use setText() or can set this instance var. - - - - - All tokens go to the parser (unless skip() is called in that rule) - on a particular "channel". The parser tunes to a particular channel - so that whitespace etc... can go to the parser on a "hidden" channel. - - - - - Anything on different channel than DEFAULT_CHANNEL is not parsed - by parser. - - - - Useful for dumping out the input stream after doing some - augmentation or other manipulations. - - You can insert stuff, replace, and delete chunks. Note that the - operations are done lazily--only if you convert the buffer to a - String. This is very efficient because you are not moving data around - all the time. As the buffer of tokens is converted to strings, the - toString() method(s) check to see if there is an operation at the - current index. If so, the operation is done and then normal String - rendering continues on the buffer. This is like having multiple Turing - machine instruction streams (programs) operating on a single input tape. :) - - Since the operations are done lazily at toString-time, operations do not - screw up the token index values. That is, an insert operation at token - index i does not change the index values for tokens i+1..n-1. - - Because operations never actually alter the buffer, you may always get - the original token stream back without undoing anything. Since - the instructions are queued up, you can easily simulate transactions and - roll back any changes if there is an error just by removing instructions. - For example, - - CharStream input = new ANTLRFileStream("input"); - TLexer lex = new TLexer(input); - TokenRewriteStream tokens = new TokenRewriteStream(lex); - T parser = new T(tokens); - parser.startRule(); - - Then in the rules, you can execute - Token t,u; - ... - input.insertAfter(t, "text to put after t");} - input.insertAfter(u, "text after u");} - System.out.println(tokens.toString()); - - Actually, you have to cast the 'input' to a TokenRewriteStream. :( - - You can also have multiple "instruction streams" and get multiple - rewrites from a single pass over the input. Just name the instruction - streams and use that name again when printing the buffer. This could be - useful for generating a C file and also its header file--all from the - same buffer: - - tokens.insertAfter("pass1", t, "text to put after t");} - tokens.insertAfter("pass2", u, "text after u");} - System.out.println(tokens.toString("pass1")); - System.out.println(tokens.toString("pass2")); - - If you don't use named rewrite streams, a "default" stream is used as - the first example shows. - - - What index into rewrites List are we? - - - Token buffer index. - - - - Execute the rewrite operation by possibly adding to the buffer. - Return the index of the next token to operate on. - - - - - I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp - instructions. - - - - - You may have multiple, named streams of rewrite operations. - I'm calling these things "programs." - Maps String (name) -> rewrite (List) - - - - Map String (program name) -> Integer index - - - - Rollback the instruction stream for a program so that - the indicated instruction (via instructionIndex) is no - longer in the stream. UNTESTED! - - - - Reset the program so that no instructions exist - - - We need to combine operations and report invalid operations (like - overlapping replaces that are not completed nested). Inserts to - same index need to be combined etc... Here are the cases: - - I.i.u I.j.v leave alone, nonoverlapping - I.i.u I.i.v combine: Iivu - - R.i-j.u R.x-y.v | i-j in x-y delete first R - R.i-j.u R.i-j.v delete first R - R.i-j.u R.x-y.v | x-y in i-j ERROR - R.i-j.u R.x-y.v | boundaries overlap ERROR - - Delete special case of replace (text==null): - D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) - - I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before - we're not deleting i) - I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping - R.x-y.v I.i.u | i in x-y ERROR - R.x-y.v I.x.u R.x-y.uv (combine, delete I) - R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping - - I.i.u = insert u before op @ index i - R.x-y.u = replace x-y indexed tokens with u - - First we need to examine replaces. For any replace op: - - 1. wipe out any insertions before op within that range. - 2. Drop any replace op before that is contained completely within - that range. - 3. Throw exception upon boundary overlap with any previous replace. - - Then we can deal with inserts: - - 1. for any inserts to same index, combine even if not adjacent. - 2. for any prior replace with same left boundary, combine this - insert with replace and delete this replace. - 3. throw exception if index in same range as previous replace - - Don't actually delete; make op null in list. Easier to walk list. - Later we can throw as we add to index -> op map. - - Note that I.2 R.2-2 will wipe out I.2 even though, technically, the - inserted stuff would be before the replace range. But, if you - add tokens in front of a method body '{' and then delete the method - body, I think the stuff before the '{' you added should disappear too. - - Return a map from token index to operation. - - - Get all operations before an index of a particular kind - - - - In an action, a lexer rule can set token to this SKIP_TOKEN and ANTLR - will avoid creating a token for this symbol and try to fetch another. - - - - imaginary tree navigation type; traverse "get child" link - - - imaginary tree navigation type; finish with a child list - - - - A generic tree implementation with no payload. You must subclass to - actually have any user data. ANTLR v3 uses a list of children approach - instead of the child-sibling approach in v2. A flat tree (a list) is - an empty node whose children represent the list. An empty, but - non-null node is called "nil". - - - - - Create a new node from an existing node does nothing for BaseTree - as there are no fields other than the children list, which cannot - be copied as the children are not considered part of this node. - - - - - Get the children internal List; note that if you directly mess with - the list, do so at your own risk. - - - - BaseTree doesn't track parent pointers. - - - BaseTree doesn't track child indexes. - - - Add t as child of this node. - - - Warning: if t has no children, but child does - and child isNil then this routine moves children to t via - t.children = child.children; i.e., without copying the array. - - - - Add all elements of kids list as children of this node - - - Insert child t at child position i (0..n-1) by shifting children - i+1..n-1 to the right one position. Set parent / indexes properly - but does NOT collapse nil-rooted t's that come in here like addChild. - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - Override in a subclass to change the impl of children list - - - Set the parent and child index values for all child of t - - - Walk upwards looking for ancestor with this token type. - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - Print out a whole tree not just a node - - - Override to say how a node (not a tree) should look as text - - - A TreeAdaptor that works with any Tree implementation. - - - - System.identityHashCode() is not always unique; we have to - track ourselves. That's ok, it's only for debugging, though it's - expensive: we have to create a hashtable with all tree nodes in it. - - - - - Create tree node that holds the start and stop tokens associated - with an error. - - - - If you specify your own kind of tree nodes, you will likely have to - override this method. CommonTree returns Token.INVALID_TOKEN_TYPE - if no token payload but you might have to set token type for diff - node type. - - You don't have to subclass CommonErrorNode; you will likely need to - subclass your own tree node class to avoid class cast exception. - - - - - This is generic in the sense that it will work with any kind of - tree (not just ITree interface). It invokes the adaptor routines - not the tree node routines to do the construction. - - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - Transform ^(nil x) to x and nil to null - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Duplicate a node. This is part of the factory; - override if you want another kind of node to be built. - - - - I could use reflection to prevent having to override this - but reflection is slow. - - - - - Track start/stop token for subtree root created for a rule. - Only works with Tree nodes. For rules that match nothing, - seems like this will yield start=i and stop=i-1 in a nil node. - Might be useful info so I'll not force to be i..i. - - - - A buffered stream of tree nodes. Nodes can be from a tree of ANY kind. - - This node stream sucks all nodes out of the tree specified in - the constructor during construction and makes pointers into - the tree using an array of Object pointers. The stream necessarily - includes pointers to DOWN and UP and EOF nodes. - - This stream knows how to mark/release for backtracking. - - This stream is most suitable for tree interpreters that need to - jump around a lot or for tree parsers requiring speed (at cost of memory). - There is some duplicated functionality here with UnBufferedTreeNodeStream - but just in bookkeeping, not tree walking etc... - - TARGET DEVELOPERS: - - This is the old CommonTreeNodeStream that buffered up entire node stream. - No need to implement really as new CommonTreeNodeStream is much better - and covers what we need. - - @see CommonTreeNodeStream - - - The complete mapping from stream index to tree node. - This buffer includes pointers to DOWN, UP, and EOF nodes. - It is built upon ctor invocation. The elements are type - Object as we don't what the trees look like. - - Load upon first need of the buffer so we can set token types - of interest for reverseIndexing. Slows us down a wee bit to - do all of the if p==-1 testing everywhere though. - - - Pull nodes from which tree? - - - IF this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - Reuse same DOWN, UP navigation nodes unless this is true - - - The index into the nodes list of the current node (next node - to consume). If -1, nodes array not filled yet. - - - Track the last mark() call result value for use in rewind(). - - - Stack of indexes used for push/pop calls - - - Walk tree with depth-first-search and fill nodes buffer. - Don't do DOWN, UP nodes if its a list (t is isNil). - - - What is the stream index for node? 0..n-1 - Return -1 if node not found. - - - As we flatten the tree, we use UP, DOWN nodes to represent - the tree structure. When debugging we need unique nodes - so instantiate new ones when uniqueNavigationNodes is true. - - - Look backwards k nodes - - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - - Used for testing, just return the token type stream - - - Debugging - - - A node representing erroneous token range in token stream - - - - A tree node that is wrapper for a Token object. After 3.0 release - while building tree rewrite stuff, it became clear that computing - parent and child index is very difficult and cumbersome. Better to - spend the space in every tree node. If you don't want these extra - fields, it's easy to cut them out in your own BaseTree subclass. - - - - A single token is the payload - - - - What token indexes bracket all tokens associated with this node - and below? - - - - Who is the parent node of this node; if null, implies node is root - - - What index is this node in the child list? Range: 0..n-1 - - - - For every node in this subtree, make sure it's start/stop token's - are set. Walk depth first, visit bottom up. Only updates nodes - with at least one token index < 0. - - - - - A TreeAdaptor that works with any Tree implementation. It provides - really just factory methods; all the work is done by BaseTreeAdaptor. - If you would like to have different tokens created than ClassicToken - objects, you need to override this and then set the parser tree adaptor to - use your subclass. - - - - To get your parser to build nodes of a different type, override - create(Token), errorNode(), and to be safe, YourTreeClass.dupNode(). - dupNode is called to duplicate nodes during rewrite operations. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - What is the Token associated with this node? If - you are not using CommonTree, then you must - override this in your own adaptor. - - - - Pull nodes from which tree? - - - If this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - The tree iterator we are using - - - Stack of indexes used for push/pop calls - - - Tree (nil A B C) trees like flat A B C streams - - - Tracks tree depth. Level=0 means we're at root node level. - - - Tracks the last node before the start of {@link #data} which contains - position information to provide information for error reporting. This is - tracked in addition to {@link #prevElement} which may or may not contain - position information. - - @see #hasPositionInformation - @see RecognitionException#extractInformationFromTreeNodeStream - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - Returns an element containing position information. If {@code allowApproximateLocation} is {@code false}, then - this method will return the {@code LT(1)} element if it contains position information, and otherwise return {@code null}. - If {@code allowApproximateLocation} is {@code true}, then this method will return the last known element containing position information. - - @see #hasPositionInformation - - - For debugging; destructive: moves tree iterator to end. - - - A utility class to generate DOT diagrams (graphviz) from - arbitrary trees. You can pass in your own templates and - can pass in any kind of tree or use Tree interface method. - I wanted this separator so that you don't have to include - ST just to use the org.antlr.runtime.tree.* package. - This is a set of non-static methods so you can subclass - to override. For example, here is an invocation: - - CharStream input = new ANTLRInputStream(System.in); - TLexer lex = new TLexer(input); - CommonTokenStream tokens = new CommonTokenStream(lex); - TParser parser = new TParser(tokens); - TParser.e_return r = parser.e(); - Tree t = (Tree)r.tree; - System.out.println(t.toStringTree()); - DOTTreeGenerator gen = new DOTTreeGenerator(); - StringTemplate st = gen.toDOT(t); - System.out.println(st); - - - Track node to number mapping so we can get proper node name back - - - Track node number so we can get unique node names - - - Generate DOT (graphviz) for a whole tree not just a node. - For example, 3+4*5 should generate: - - digraph { - node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier", - width=.4, height=.2]; - edge [arrowsize=.7] - "+"->3 - "+"->"*" - "*"->4 - "*"->5 - } - - Takes a Tree interface object. - - - - @author Sam Harwell - - - Returns an element containing concrete information about the current - position in the stream. - - @param allowApproximateLocation if {@code false}, this method returns - {@code null} if an element containing exact information about the current - position is not available - - - Determines if the specified {@code element} contains concrete position - information. - - @param element the element to check - @return {@code true} if {@code element} contains concrete position - information, otherwise {@code false} - - - - What does a tree look like? ANTLR has a number of support classes - such as CommonTreeNodeStream that work on these kinds of trees. You - don't have to make your trees implement this interface, but if you do, - you'll be able to use more support code. - - - - NOTE: When constructing trees, ANTLR can build any kind of tree; it can - even use Token objects as trees if you add a child list to your tokens. - - This is a tree node without any payload; just navigation and factory stuff. - - - - Is there is a node above with token type ttype? - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - This node is what child index? 0..n-1 - - - Set the parent and child index values for all children - - - - Add t as a child to this node. If t is null, do nothing. If t - is nil, add all children of t to this' children. - - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - - Indicates the node is a nil node but may still have children, meaning - the tree is a flat list. - - - - - What is the smallest token index (indexing from 0) for this node - and its children? - - - - - What is the largest token index (indexing from 0) for this node - and its children? - - - - Return a token type; needed for tree parsing - - - In case we don't have a token payload, what is the line for errors? - - - - How to create and navigate trees. Rather than have a separate factory - and adaptor, I've merged them. Makes sense to encapsulate. - - - - This takes the place of the tree construction code generated in the - generated code in 2.x and the ASTFactory. - - I do not need to know the type of a tree at all so they are all - generic Objects. This may increase the amount of typecasting needed. :( - - - - - Create a tree node from Token object; for CommonTree type trees, - then the token just becomes the payload. This is the most - common create call. - - - - Override if you want another kind of node to be built. - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel]. - - - - This should invoke createToken(Token). - - - - - Same as create(tokenType,fromToken) except set the text too. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel, "IMAG"]. - - - - This should invoke createToken(Token). - - - - - Same as create(fromToken) except set the text too. - This is invoked when the text terminal option is set, as in - IMAG<text='IMAG'>. - - - - This should invoke createToken(Token). - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG["IMAG"]. - - - - This should invoke createToken(int,String). - - - - Duplicate a single tree node. - Override if you want another kind of node to be built. - - - Duplicate tree recursively, using dupNode() for each node - - - - Return a nil node (an empty but non-null node) that can hold - a list of element as the children. If you want a flat tree (a list) - use "t=adaptor.nil(); t.addChild(x); t.addChild(y);" - - - - - Return a tree node representing an error. This node records the - tokens consumed during error recovery. The start token indicates the - input symbol at which the error was detected. The stop token indicates - the last symbol consumed during recovery. - - - - You must specify the input stream so that the erroneous text can - be packaged up in the error node. The exception could be useful - to some applications; default implementation stores ptr to it in - the CommonErrorNode. - - This only makes sense during token parsing, not tree parsing. - Tree parsing should happen only when parsing and tree construction - succeed. - - - - Is tree considered a nil node used to make lists of child nodes? - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. Do nothing if t or child is null. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - - Given the root of the subtree created for this rule, post process - it to do any simplifications or whatever you want. A required - behavior is to convert ^(nil singleSubtree) to singleSubtree - as the setting of start/stop indexes relies on a single non-nil root - for non-flat trees. - - - - Flat trees such as for lists like "idlist : ID+ ;" are left alone - unless there is only one ID. For a list, the start/stop indexes - are set in the nil node. - - This method is executed after all rule tree construction and right - before setTokenBoundaries(). - - - - For identifying trees. - - - How to identify nodes so we can say "add node to a prior node"? - Even becomeRoot is an issue. Use System.identityHashCode(node) - usually. - - - - - Create a node for newRoot make it the root of oldRoot. - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - Return node created for newRoot. - - - - Be advised: when debugging ASTs, the DebugTreeAdaptor manually - calls create(Token child) and then plain becomeRoot(node, node) - because it needs to trap calls to create, but it can't since it delegates - to not inherits from the TreeAdaptor. - - - - For tree parsing, I need to know the token type of a node - - - Node constructors can set the type of a node - - - Node constructors can set the text of a node - - - - Return the token object from which this node was created. - Currently used only for printing an error message. - The error display routine in BaseRecognizer needs to - display where the input the error occurred. If your - tree of limitation does not store information that can - lead you to the token, you can create a token filled with - the appropriate information and pass that back. See - BaseRecognizer.getErrorMessage(). - - - - - Where are the bounds in the input token stream for this node and - all children? Each rule that creates AST nodes will call this - method right before returning. Flat trees (i.e., lists) will - still usually have a nil root node just to hold the children list. - That node would contain the start/stop indexes then. - - - - Get the token start index for this subtree; return -1 if no such index - - - Get the token stop index for this subtree; return -1 if no such index - - - Get a child 0..n-1 node - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - Remove ith child and shift children down from right. - - - How many children? If 0, then this is a leaf node - - - - Who is the parent node of this node; if null, implies node is root. - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - What index is this node in the child list? Range: 0..n-1 - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - Replace from start to stop child index of parent with t, which might - be a list. Number of children may be different after this call. - - - - If parent is null, don't do anything; must be at root of overall tree. - Can't replace whatever points to the parent externally. Do nothing. - - - - A stream of tree nodes, accessing nodes from a tree of some kind - - - - Get a tree node at an absolute index i; 0..n-1. - If you don't want to buffer up nodes, then this method makes no - sense for you. - - - - - Get tree node at current input pointer + ahead where - ==1 is next node. <0 indicates nodes in the past. So - {@code LT(-1)} is previous node, but implementations are not required to - provide results for < -1. {@code LT(0)} is undefined. For - <=n, return . Return for {@code LT(0)} - and any index that results in an absolute address that is negative. - - - - This is analogous to , but this returns a tree node - instead of a . Makes code generation identical for both - parser and tree grammars. - - - - - Where is this stream pulling nodes from? This is not the name, but - the object that provides node objects. - - - - - If the tree associated with this stream was created from a - {@link TokenStream}, you can specify it here. Used to do rule - {@code $text} attribute in tree parser. Optional unless you use tree - parser rule {@code $text} attribute or {@code output=template} and - {@code rewrite=true} options. - - - - - What adaptor can tell me how to interpret/navigate nodes and - trees. E.g., get text of a node. - - - - - As we flatten the tree, we use {@link Token#UP}, {@link Token#DOWN} nodes - to represent the tree structure. When debugging we need unique nodes so - we have to instantiate new ones. When doing normal tree parsing, it's - slow and a waste of memory to create unique navigation nodes. Default - should be {@code false}. - - - - - Return the text of all nodes from {@code start} to {@code stop}, - inclusive. If the stream does not buffer all the nodes then it can still - walk recursively from start until stop. You can always return - {@code null} or {@code ""} too, but users should not access - {@code $ruleLabel.text} in an action of course in that case. - - - - - Replace children of {@code parent} from index {@code startChildIndex} to - {@code stopChildIndex} with {@code t}, which might be a list. Number of - children may be different after this call. The stream is notified because - it is walking the tree and might need to know you are monkeying with the - underlying tree. Also, it might be able to modify the node stream to - avoid restreaming for future phases. - - - - If {@code parent} is {@code null}, don't do anything; must be at root of - overall tree. Can't replace whatever points to the parent externally. Do - nothing. - - - - - How to execute code for node t when a visitor visits node t. Execute - pre() before visiting children and execute post() after visiting children. - - - - - Execute an action before visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. Children of returned value will be - visited if using TreeVisitor.visit(). - - - - - Execute an action after visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. - - - - - A record of the rules used to match a token sequence. The tokens - end up as the leaves of this tree and rule nodes are the interior nodes. - This really adds no functionality, it is just an alias for CommonTree - that is more meaningful (specific) and holds a String to display for a node. - - - - - Emit a token and all hidden nodes before. EOF node holds all - hidden tokens after last real token. - - - - - Print out the leaves of this tree, which means printing original - input back out. - - - - - Base class for all exceptions thrown during AST rewrite construction. - This signifies a case where the cardinality of two or more elements - in a subrule are different: (ID INT)+ where |ID|!=|INT| - - - - No elements within a (...)+ in a rewrite rule - - - Ref to ID or expr but no tokens in ID stream or subtrees in expr stream - - - - A generic list of elements tracked in an alternative to be used in - a -> rewrite rule. We need to subclass to fill in the next() method, - which returns either an AST node wrapped around a token payload or - an existing subtree. - - - - Once you start next()ing, do not try to add more elements. It will - break the cursor tracking I believe. - - TODO: add mechanism to detect/puke on modification after reading from stream - - - - - - - - Cursor 0..n-1. If singleElement!=null, cursor is 0 until you next(), - which bumps it to 1 meaning no more elements. - - - - Track single elements w/o creating a list. Upon 2nd add, alloc list - - - The list of tokens or subtrees we are tracking - - - Once a node / subtree has been used in a stream, it must be dup'd - from then on. Streams are reset after subrules so that the streams - can be reused in future subrules. So, reset must set a dirty bit. - If dirty, then next() always returns a dup. - - - The element or stream description; usually has name of the token or - rule reference that this list tracks. Can include rulename too, but - the exception would track that info. - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Reset the condition of this stream so that it appears we have - not consumed any of its elements. Elements themselves are untouched. - Once we reset the stream, any future use will need duplicates. Set - the dirty bit. - - - - - Return the next element in the stream. If out of elements, throw - an exception unless size()==1. If size is 1, then return elements[0]. - Return a duplicate node/subtree if stream is out of elements and - size==1. If we've already used the element, dup (dirty bit set). - - - - - Do the work of getting the next element, making sure that it's - a tree node or subtree. Deal with the optimization of single- - element list versus list of size > 1. Throw an exception - if the stream is empty or we're out of elements and size>1. - protected so you can override in a subclass if necessary. - - - - - When constructing trees, sometimes we need to dup a token or AST - subtree. Dup'ing a token means just creating another AST node - around it. For trees, you must call the adaptor.dupTree() unless - the element is for a tree root; then it must be a node dup. - - - - - Ensure stream emits trees; tokens must be converted to AST nodes. - AST nodes can be passed through unmolested. - - - - - Queues up nodes matched on left side of -> in a tree parser. This is - the analog of RewriteRuleTokenStream for normal parsers. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Treat next element as a single node even if it's a subtree. - This is used instead of next() when the result has to be a - tree root node. Also prevents us from duplicating recently-added - children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration - must dup the type node, but ID has been added. - - - - Referencing a rule result twice is ok; dup entire tree as - we can't be adding trees as root; e.g., expr expr. - - Hideous code duplication here with super.next(). Can't think of - a proper way to refactor. This needs to always call dup node - and super.next() doesn't know which to call: dup node or dup tree. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Get next token from stream and make a node for it - - - - Don't convert to a tree unless they explicitly call nextTree. - This way we can do hetero tree nodes in rewrite. - - - - Return a node stream from a doubly-linked tree whose nodes - know what child index they are. No remove() is supported. - - Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure. - - - If we emit UP/DOWN nodes, we need to spit out multiple nodes per - next() call. - - - - A parser for a stream of tree nodes. "tree grammars" result in a subclass - of this. All the error reporting and recovery is shared with Parser via - the BaseRecognizer superclass. - - - - Set the input stream - - - - Match '.' in tree parser has special meaning. Skip node or - entire tree if node has children. If children, scan until - corresponding UP node. - - - - - We have DOWN/UP nodes in the stream that have no line info; override. - plus we want to alter the exception type. Don't try to recover - from tree parser errors inline... - - - - - Prefix error message with the grammar name because message is - always intended for the programmer because the parser built - the input tree not the user. - - - - - Tree parsers parse nodes they usually have a token object as - payload. Set the exception token and do the default behavior. - - - - The tree pattern to lex like "(A B C)" - - - Index into input string - - - Current char - - - How long is the pattern in char? - - - Set when token type is ID or ARG (name mimics Java's StreamTokenizer) - - - Override this if you need transformation tracing to go somewhere - other than stdout or if you're not using ITree-derived trees. - - - - This is identical to the ParserRuleReturnScope except that - the start property is a tree nodes not Token object - when you are parsing trees. - - - - Gets the first node or root node of tree matched for this rule. - - - Do a depth first walk of a tree, applying pre() and post() actions as we go. - - - - Visit every node in tree t and trigger an action for each node - before/after having visited all of its children. Bottom up walk. - Execute both actions even if t has no children. Ignore return - results from transforming children since they will have altered - the child list of this node (their parent). Return result of - applying post action to this node. - - - - - Build and navigate trees with this object. Must know about the names - of tokens so you have to pass in a map or array of token names (from which - this class can build the map). I.e., Token DECL means nothing unless the - class can translate it to a token type. - - - - In order to create nodes and navigate, this class needs a TreeAdaptor. - - This class can build a token type -> node index for repeated use or for - iterating over the various nodes with a particular type. - - This class works in conjunction with the TreeAdaptor rather than moving - all this functionality into the adaptor. An adaptor helps build and - navigate trees using methods. This class helps you do it with string - patterns like "(A B C)". You can create a tree from that pattern or - match subtrees against it. - - - - - When using %label:TOKENNAME in a tree for parse(), we must - track the label. - - - - This adaptor creates TreePattern objects for use during scan() - - - - Compute a Map<String, Integer> that is an inverted index of - tokenNames (which maps int token types to names). - - - - Using the map of token names to token types, return the type. - - - - Walk the entire tree and make a node name to nodes mapping. - For now, use recursion but later nonrecursive version may be - more efficient. Returns Map<Integer, List> where the List is - of your AST node type. The Integer is the token type of the node. - - - - TODO: save this index so that find and visit are faster - - - - Do the work for index - - - Return a List of tree nodes with token type ttype - - - Return a List of subtrees matching pattern. - - - - Visit every ttype node in t, invoking the visitor. This is a quicker - version of the general visit(t, pattern) method. The labels arg - of the visitor action method is never set (it's null) since using - a token type rather than a pattern doesn't let us set a label. - - - - Do the recursive work for visit - - - - For all subtrees that match the pattern, execute the visit action. - The implementation uses the root node of the pattern in combination - with visit(t, ttype, visitor) so nil-rooted patterns are not allowed. - Patterns with wildcard roots are also not allowed. - - - - - Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels - on the various nodes and '.' (dot) as the node/subtree wildcard, - return true if the pattern matches and fill the labels Map with - the labels pointing at the appropriate nodes. Return false if - the pattern is malformed or the tree does not match. - - - - If a node specifies a text arg in pattern, then that must match - for that node in t. - - TODO: what's a better way to indicate bad pattern? Exceptions are a hassle - - - - - Do the work for parse. Check to see if the t2 pattern fits the - structure and token types in t1. Check text if the pattern has - text arguments on nodes. Fill labels map with pointers to nodes - in tree matched against nodes in pattern with labels. - - - - - Create a tree or node from the indicated tree pattern that closely - follows ANTLR tree grammar tree element syntax: - - (root child1 ... child2). - - - - You can also just pass in a node: ID - - Any node can have a text argument: ID[foo] - (notice there are no quotes around foo--it's clear it's a string). - - nil is a special name meaning "give me a nil node". Useful for - making lists: (nil A B C) is a list of A B C. - - - - - Compare t1 and t2; return true if token types/text, structure match exactly. - The trees are examined in their entirety so that (A B) does not match - (A B C) nor (A (B C)). - - - - TODO: allow them to pass in a comparator - TODO: have a version that is nonstatic so it can use instance adaptor - - I cannot rely on the tree node's equals() implementation as I make - no constraints at all on the node types nor interface etc... - - - - - Compare type, structure, and text of two trees, assuming adaptor in - this instance of a TreeWizard. - - - - A token stream that pulls tokens from the code source on-demand and - without tracking a complete buffer of the tokens. This stream buffers - the minimum number of tokens possible. It's the same as - OnDemandTokenStream except that OnDemandTokenStream buffers all tokens. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - - You can only look backwards 1 token: LT(-1). - - Use this when you need to read from a socket or other infinite stream. - - @see BufferedTokenStream - @see CommonTokenStream - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - An extra token while parsing a TokenStream - - - diff --git a/packages/Antlr3.Runtime.3.5.1/lib/net40-client/Antlr3.Runtime.dll b/packages/Antlr3.Runtime.3.5.1/lib/net40-client/Antlr3.Runtime.dll deleted file mode 100644 index 55c8fbd6a..000000000 Binary files a/packages/Antlr3.Runtime.3.5.1/lib/net40-client/Antlr3.Runtime.dll and /dev/null differ diff --git a/packages/Antlr3.Runtime.3.5.1/lib/net40-client/Antlr3.Runtime.xml b/packages/Antlr3.Runtime.3.5.1/lib/net40-client/Antlr3.Runtime.xml deleted file mode 100644 index 565e15d57..000000000 --- a/packages/Antlr3.Runtime.3.5.1/lib/net40-client/Antlr3.Runtime.xml +++ /dev/null @@ -1,3249 +0,0 @@ - - - - Antlr3.Runtime - - - - - This is a char buffer stream that is loaded from a file - all at once when you construct the object. This looks very - much like an ANTLReader or ANTLRInputStream, but it's a special case - since we know the exact size of the object to load. We can avoid lots - of data copying. - - - - - A kind of ReaderStream that pulls from an InputStream. - Useful for reading from stdin and specifying file encodings etc... - - - - - Vacuum all input from a Reader and then treat it like a StringStream. - Manage the buffer manually to avoid unnecessary data copying. - - - - If you need encoding, use ANTLRInputStream. - - - - - A pretty quick CharStream that pulls all data from an array - directly. Every method call counts in the lexer. Java's - strings aren't very good so I'm avoiding. - - - - The data being scanned - - - How many characters are actually in the buffer - - - 0..n-1 index into string of next char - - - line number 1..n within the input - - - The index of the character relative to the beginning of the line 0..n-1 - - - tracks how deep mark() calls are nested - - - - A list of CharStreamState objects that tracks the stream state - values line, charPositionInLine, and p that can change as you - move through the input stream. Indexed from 1..markDepth. - A null is kept @ index 0. Create upon first call to mark(). - - - - Track the last mark() call result value for use in rewind(). - - - What is name or source of this char stream? - - - Copy data in string to a local char array - - - This is the preferred constructor as no data is copied - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the index of char to - be returned from LA(1). - - - - - Reset the stream so that it's in the same state it was - when the object was created *except* the data array is not - touched. - - - - - consume() ahead until p==index; can't just set p=index as we must - update line and charPositionInLine. - - - - - A generic recognizer that can handle recognizers generated from - lexer, parser, and tree grammars. This is all the parsing - support code essentially; most of it is error recovery stuff and - backtracking. - - - - - State of a lexer, parser, or tree parser are collected into a state - object so the state can be shared. This sharing is needed to - have one grammar import others and share same error variables - and other state variables. It's a kind of explicit multiple - inheritance via delegation of methods and shared state. - - - - reset the parser's state; subclasses must rewinds the input stream - - - - Match current input symbol against ttype. Attempt - single token insertion or deletion error recovery. If - that fails, throw MismatchedTokenException. - - - - To turn off single token insertion or deletion error - recovery, override recoverFromMismatchedToken() and have it - throw an exception. See TreeParser.recoverFromMismatchedToken(). - This way any error in a rule will cause an exception and - immediate exit from rule. Rule would recover by resynchronizing - to the set of symbols that can follow rule ref. - - - - Match the wildcard: in a symbol - - - Report a recognition problem. - - - This method sets errorRecovery to indicate the parser is recovering - not parsing. Once in recovery mode, no errors are generated. - To get out of recovery mode, the parser must successfully match - a token (after a resync). So it will go: - - 1. error occurs - 2. enter recovery mode, report error - 3. consume until token found in resynch set - 4. try to resume parsing - 5. next match() will reset errorRecovery mode - - If you override, make sure to update syntaxErrors if you care about that. - - - - What error message should be generated for the various exception types? - - - Not very object-oriented code, but I like having all error message - generation within one method rather than spread among all of the - exception classes. This also makes it much easier for the exception - handling because the exception classes do not have to have pointers back - to this object to access utility routines and so on. Also, changing - the message for an exception type would be difficult because you - would have to subclassing exception, but then somehow get ANTLR - to make those kinds of exception objects instead of the default. - This looks weird, but trust me--it makes the most sense in terms - of flexibility. - - For grammar debugging, you will want to override this to add - more information such as the stack frame with - getRuleInvocationStack(e, this.getClass().getName()) and, - for no viable alts, the decision description and state etc... - - Override this to change the message generated for one or more - exception types. - - - - - Get number of recognition errors (lexer, parser, tree parser). Each - recognizer tracks its own number. So parser and lexer each have - separate count. Does not count the spurious errors found between - an error and next valid token match - - - - - - What is the error header, normally line/character position information? - - - - How should a token be displayed in an error message? The default - is to display just the text, but during development you might - want to have a lot of information spit out. Override in that case - to use t.ToString() (which, for CommonToken, dumps everything about - the token). This is better than forcing you to override a method in - your token objects because you don't have to go modify your lexer - so that it creates a new Java type. - - - - Override this method to change where error messages go - - - - Recover from an error found on the input stream. This is - for NoViableAlt and mismatched symbol exceptions. If you enable - single token insertion and deletion, this will usually not - handle mismatched symbol exceptions but there could be a mismatched - token that the match() routine could not recover from. - - - - - A hook to listen in on the token consumption during error recovery. - The DebugParser subclasses this to fire events to the listenter. - - - - - Compute the context-sensitive FOLLOW set for current rule. - This is set of token types that can follow a specific rule - reference given a specific call chain. You get the set of - viable tokens that can possibly come next (lookahead depth 1) - given the current call chain. Contrast this with the - definition of plain FOLLOW for rule r: - - - FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)} - - where x in T* and alpha, beta in V*; T is set of terminals and - V is the set of terminals and nonterminals. In other words, - FOLLOW(r) is the set of all tokens that can possibly follow - references to r in *any* sentential form (context). At - runtime, however, we know precisely which context applies as - we have the call chain. We may compute the exact (rather - than covering superset) set of following tokens. - - For example, consider grammar: - - stat : ID '=' expr ';' // FOLLOW(stat)=={EOF} - | "return" expr '.' - ; - expr : atom ('+' atom)* ; // FOLLOW(expr)=={';','.',')'} - atom : INT // FOLLOW(atom)=={'+',')',';','.'} - | '(' expr ')' - ; - - The FOLLOW sets are all inclusive whereas context-sensitive - FOLLOW sets are precisely what could follow a rule reference. - For input input "i=(3);", here is the derivation: - - stat => ID '=' expr ';' - => ID '=' atom ('+' atom)* ';' - => ID '=' '(' expr ')' ('+' atom)* ';' - => ID '=' '(' atom ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ';' - - At the "3" token, you'd have a call chain of - - stat -> expr -> atom -> expr -> atom - - What can follow that specific nested ref to atom? Exactly ')' - as you can see by looking at the derivation of this specific - input. Contrast this with the FOLLOW(atom)={'+',')',';','.'}. - - You want the exact viable token set when recovering from a - token mismatch. Upon token mismatch, if LA(1) is member of - the viable next token set, then you know there is most likely - a missing token in the input stream. "Insert" one by just not - throwing an exception. - - - Attempt to recover from a single missing or extra token. - - EXTRA TOKEN - - LA(1) is not what we are looking for. If LA(2) has the right token, - however, then assume LA(1) is some extra spurious token. Delete it - and LA(2) as if we were doing a normal match(), which advances the - input. - - MISSING TOKEN - - If current token is consistent with what could come after - ttype then it is ok to "insert" the missing token, else throw - exception For example, Input "i=(3;" is clearly missing the - ')'. When the parser returns from the nested call to expr, it - will have call chain: - - stat -> expr -> atom - - and it will be trying to match the ')' at this point in the - derivation: - - => ID '=' '(' INT ')' ('+' atom)* ';' - ^ - match() will see that ';' doesn't match ')' and report a - mismatched token error. To recover, it sees that LA(1)==';' - is in the set of tokens that can follow the ')' token - reference in rule atom. It can assume that you forgot the ')'. - - - Not currently used - - - - Match needs to return the current input symbol, which gets put - into the label for the associated token ref; e.g., x=ID. Token - and tree parsers need to return different objects. Rather than test - for input stream type or change the IntStream interface, I use - a simple method to ask the recognizer to tell me what the current - input symbol is. - - - This is ignored for lexers. - - - Conjure up a missing token during error recovery. - - - The recognizer attempts to recover from single missing - symbols. But, actions might refer to that missing symbol. - For example, x=ID {f($x);}. The action clearly assumes - that there has been an identifier matched previously and that - $x points at that token. If that token is missing, but - the next token in the stream is what we want we assume that - this token is missing and we keep going. Because we - have to return some token to replace the missing token, - we have to conjure one up. This method gives the user control - over the tokens returned for missing tokens. Mostly, - you will want to create something special for identifier - tokens. For literals such as '{' and ',', the default - action in the parser or tree parser works. It simply creates - a CommonToken of the appropriate type. The text will be the token. - If you change what tokens must be created by the lexer, - override this method to create the appropriate tokens. - - - - Consume tokens until one matches the given token set - - - Push a rule's follow set using our own hardcoded stack - - - - Return of the rules in your parser instance - leading up to a call to this method. You could override if - you want more details such as the file/line info of where - in the parser java code a rule is invoked. - - - - This is very useful for error messages and for context-sensitive - error recovery. - - - - - A more general version of GetRuleInvocationStack where you can - pass in the StackTrace of, for example, a RecognitionException - to get it's rule stack trace. - - - - Return whether or not a backtracking attempt failed. - - - - Used to print out token names like ID during debugging and - error reporting. The generated parsers implement a method - that overrides this to point to their String[] tokenNames. - - - - - For debugging and other purposes, might want the grammar name. - Have ANTLR generate an implementation for this method. - - - - - A convenience method for use most often with template rewrites. - Convert a list of to a list of . - - - - - Given a rule number and a start token index number, return - MEMO_RULE_UNKNOWN if the rule has not parsed input starting from - start index. If this rule has parsed input starting from the - start index before, then return where the rule stopped parsing. - It returns the index of the last token matched by the rule. - - - - For now we use a hashtable and just the slow Object-based one. - Later, we can make a special one for ints and also one that - tosses out data after we commit past input position i. - - - - - Has this rule already parsed input at the current index in the - input stream? Return the stop token index or MEMO_RULE_UNKNOWN. - If we attempted but failed to parse properly before, return - MEMO_RULE_FAILED. - - - - This method has a side-effect: if we have seen this input for - this rule and successfully parsed before, then seek ahead to - 1 past the stop token matched for this rule last time. - - - - - Record whether or not this rule parsed the input at this position - successfully. Use a standard java hashtable for now. - - - - return how many rule/input-index pairs there are in total. - TODO: this includes synpreds. :( - - - - A stripped-down version of org.antlr.misc.BitSet that is just - good enough to handle runtime requirements such as FOLLOW sets - for automatic error recovery. - - - - - We will often need to do a mod operator (i mod nbits). Its - turns out that, for powers of two, this mod operation is - same as (i & (nbits-1)). Since mod is slow, we use a - precomputed mod mask to do the mod instead. - - - - The actual data bits - - - Construct a bitset of size one word (64 bits) - - - Construction from a static array of longs - - - Construction from a list of integers - - - Construct a bitset given the size - The size of the bitset in bits - - - return this | a in a new set - - - or this element into this set (grow as necessary to accommodate) - - - Grows the set to a larger number of bits. - element that must fit in set - - - Sets the size of a set. - how many words the new set should be - - - return how much space is being used by the bits array not how many actually have member bits on. - - - Is this contained within a? - - - Buffer all input tokens but do on-demand fetching of new tokens from - lexer. Useful when the parser or lexer has to set context/mode info before - proper lexing of future tokens. The ST template parser needs this, - for example, because it has to constantly flip back and forth between - inside/output templates. E.g., <names:{hi, <it>}> has to parse names - as part of an expression but "hi, <it>" as a nested template. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - (UnbufferedTokenStream is the same way.) - - This is not a subclass of UnbufferedTokenStream because I don't want - to confuse small moving window of tokens it uses for the full buffer. - - - Record every single token pulled from the source so we can reproduce - chunks of it later. The buffer in LookaheadStream overlaps sometimes - as its moving window moves through the input. This list captures - everything so we can access complete input text. - - - Track the last mark() call result value for use in rewind(). - - - The index into the tokens list of the current token (next token - to consume). tokens[p] should be LT(1). p=-1 indicates need - to initialize with first token. The ctor doesn't get a token. - First call to LT(1) or whatever gets the first token and sets p=0; - - - - How deep have we gone? - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - Walk past any token not on the channel the parser is listening to. - - - Make sure index i in tokens has a token. - - - add n elements to buffer - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - When walking ahead with cyclic DFA or for syntactic predicates, - we need to record the state of the input stream (char index, - line, etc...) so that we can rewind the state after scanning ahead. - - - This is the complete state of a stream. - - - Index into the char stream of next lookahead char - - - What line number is the scanner at before processing buffer[p]? - - - What char position 0..n-1 in line is scanner before processing buffer[p]? - - - - A Token object like we'd use in ANTLR 2.x; has an actual string created - and associated with this object. These objects are needed for imaginary - tree nodes that have payload objects. We need to create a Token object - that has a string; the tree node will point at this token. CommonToken - has indexes into a char stream and hence cannot be used to introduce - new strings. - - - - What token number is this from 0..n-1 tokens - - - - We need to be able to change the text once in a while. If - this is non-null, then getText should return this. Note that - start/stop are not affected by changing this. - - - - What token number is this from 0..n-1 tokens; < 0 implies invalid index - - - The char position into the input buffer where this token starts - - - The char position into the input buffer where this token stops - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - Reset this token stream by setting its token source. - - - Always leave p on an on-channel token. - - - Given a starting index, return the index of the first on-channel - token. - - - All debugging events that a recognizer can trigger. - - - I did not create a separate AST debugging interface as it would create - lots of extra classes and DebugParser has a dbg var defined, which makes - it hard to change to ASTDebugEventListener. I looked hard at this issue - and it is easier to understand as one monolithic event interface for all - possible events. Hopefully, adding ST debugging stuff won't be bad. Leave - for future. 4/26/2006. - - - - - The parser has just entered a rule. No decision has been made about - which alt is predicted. This is fired AFTER init actions have been - executed. Attributes are defined and available etc... - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - - Because rules can have lots of alternatives, it is very useful to - know which alt you are entering. This is 1..n for n alts. - - - - - This is the last thing executed before leaving a rule. It is - executed even if an exception is thrown. This is triggered after - error reporting and recovery have occurred (unless the exception is - not caught in this rule). This implies an "exitAlt" event. - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - Track entry into any (...) subrule other EBNF construct - - - - Every decision, fixed k or arbitrary, has an enter/exit event - so that a GUI can easily track what LT/consume events are - associated with prediction. You will see a single enter/exit - subrule but multiple enter/exit decision events, one for each - loop iteration. - - - - - An input token was consumed; matched by any kind of element. - Trigger after the token was matched by things like match(), matchAny(). - - - - - An off-channel input token was consumed. - Trigger after the token was matched by things like match(), matchAny(). - (unless of course the hidden token is first stuff in the input stream). - - - - - Somebody (anybody) looked ahead. Note that this actually gets - triggered by both LA and LT calls. The debugger will want to know - which Token object was examined. Like consumeToken, this indicates - what token was seen at that depth. A remote debugger cannot look - ahead into a file it doesn't have so LT events must pass the token - even if the info is redundant. - - - - - The parser is going to look arbitrarily ahead; mark this location, - the token stream's marker is sent in case you need it. - - - - - After an arbitrairly long lookahead as with a cyclic DFA (or with - any backtrack), this informs the debugger that stream should be - rewound to the position associated with marker. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. - - - - - To watch a parser move through the grammar, the parser needs to - inform the debugger what line/charPos it is passing in the grammar. - For now, this does not know how to switch from one grammar to the - other and back for island grammars etc... - - - - This should also allow breakpoints because the debugger can stop - the parser whenever it hits this line/pos. - - - - - A recognition exception occurred such as NoViableAltException. I made - this a generic event so that I can alter the exception hierachy later - without having to alter all the debug objects. - - - - Upon error, the stack of enter rule/subrule must be properly unwound. - If no viable alt occurs it is within an enter/exit decision, which - also must be rewound. Even the rewind for each mark must be unwount. - In the Java target this is pretty easy using try/finally, if a bit - ugly in the generated code. The rewind is generated in DFA.predict() - actually so no code needs to be generated for that. For languages - w/o this "finally" feature (C++?), the target implementor will have - to build an event stack or something. - - Across a socket for remote debugging, only the RecognitionException - data fields are transmitted. The token object or whatever that - caused the problem was the last object referenced by LT. The - immediately preceding LT event should hold the unexpected Token or - char. - - Here is a sample event trace for grammar: - - b : C ({;}A|B) // {;} is there to prevent A|B becoming a set - | D - ; - - The sequence for this rule (with no viable alt in the subrule) for - input 'c c' (there are 3 tokens) is: - - commence - LT(1) - enterRule b - location 7 1 - enter decision 3 - LT(1) - exit decision 3 - enterAlt1 - location 7 5 - LT(1) - consumeToken [c/<4>,1:0] - location 7 7 - enterSubRule 2 - enter decision 2 - LT(1) - LT(1) - recognitionException NoViableAltException 2 1 2 - exit decision 2 - exitSubRule 2 - beginResync - LT(1) - consumeToken [c/<4>,1:1] - LT(1) - endResync - LT(-1) - exitRule b - terminate - - - - - Indicates the recognizer is about to consume tokens to resynchronize - the parser. Any consume events from here until the recovered event - are not part of the parse--they are dead tokens. - - - - - Indicates that the recognizer has finished consuming tokens in order - to resychronize. There may be multiple beginResync/endResync pairs - before the recognizer comes out of errorRecovery mode (in which - multiple errors are suppressed). This will be useful - in a gui where you want to probably grey out tokens that are consumed - but not matched to anything in grammar. Anything between - a beginResync/endResync pair was tossed out by the parser. - - - - A semantic predicate was evaluate with this result and action text - - - - Announce that parsing has begun. Not technically useful except for - sending events over a socket. A GUI for example will launch a thread - to connect and communicate with a remote parser. The thread will want - to notify the GUI when a connection is made. ANTLR parsers - trigger this upon entry to the first rule (the ruleLevel is used to - figure this out). - - - - - Parsing is over; successfully or not. Mostly useful for telling - remote debugging listeners that it's time to quit. When the rule - invocation level goes to zero at the end of a rule, we are done - parsing. - - - - - Input for a tree parser is an AST, but we know nothing for sure - about a node except its type and text (obtained from the adaptor). - This is the analog of the consumeToken method. Again, the ID is - the hashCode usually of the node so it only works if hashCode is - not implemented. If the type is UP or DOWN, then - the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - - - The tree parser lookedahead. If the type is UP or DOWN, - then the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - A nil was created (even nil nodes have a unique ID... - they are not "null" per se). As of 4/28/2006, this - seems to be uniquely triggered when starting a new subtree - such as when entering a subrule in automatic mode and when - building a tree in rewrite mode. - - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - - Upon syntax error, recognizers bracket the error with an error node - if they are building ASTs. - - - - - - Announce a new node built from token elements such as type etc... - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID, type, text are - set. - - - - Announce a new node built from an existing token. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only node.ID and token.tokenIndex - are set. - - - - Make a node the new root of an existing root. See - - - Note: the newRootID parameter is possibly different - than the TreeAdaptor.becomeRoot() newRoot parameter. - In our case, it will always be the result of calling - TreeAdaptor.becomeRoot() and not root_n or whatever. - - The listener should assume that this event occurs - only when the current subrule (or rule) subtree is - being reset to newRootID. - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Make childID a child of rootID. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Set the token start/stop token index for a subtree root or node. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - A DFA implemented as a set of transition tables. - - - Any state that has a semantic predicate edge is special; those states - are generated with if-then-else structures in a specialStateTransition() - which is generated by cyclicDFA template. - - There are at most 32767 states (16-bit signed short). - Could get away with byte sometimes but would have to generate different - types and the simulation code too. For a point of reference, the Java - lexer's Tokens rule DFA has 326 states roughly. - - - - Which recognizer encloses this DFA? Needed to check backtracking - - - - From the input stream, predict what alternative will succeed - using this DFA (representing the covering regular approximation - to the underlying CFL). Return an alternative number 1..n. Throw - an exception upon error. - - - - A hook for debugging interface - - - - Given a String that has a run-length-encoding of some unsigned shorts - like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid - static short[] which generates so much init code that the class won't - compile. :( - - - - Hideous duplication of code, but I need different typed arrays out :( - - - The recognizer did not match anything for a (..)+ loop. - - - - A semantic predicate failed during validation. Validation of predicates - occurs when normally parsing the alternative just like matching a token. - Disambiguating predicate evaluation occurs when we hoist a predicate into - a prediction decision. - - - - AST rules have trees - - - Has a value potentially if output=AST; - - - AST rules have trees - - - Has a value potentially if output=AST; - - - A source of characters for an ANTLR lexer - - - - For infinite streams, you don't need this; primarily I'm providing - a useful interface for action code. Just make sure actions don't - use this on streams that don't support it. - - - - - Get the ith character of lookahead. This is the same usually as - LA(i). This will be used for labels in the generated - lexer code. I'd prefer to return a char here type-wise, but it's - probably better to be 32-bit clean and be consistent with LA. - - - - ANTLR tracks the line information automatically - Because this stream can rewind, we need to be able to reset the line - - - The index of the character relative to the beginning of the line 0..n-1 - - - - A simple stream of integers used when all I care about is the char - or token type sequence (such as interpretation). - - - - - Get int at current input pointer + i ahead where i=1 is next int. - Negative indexes are allowed. LA(-1) is previous token (token - just matched). LA(-i) where i is before first token should - yield -1, invalid char / EOF. - - - - - Tell the stream to start buffering if it hasn't already. Return - current input position, Index, or some other marker so that - when passed to rewind() you get back to the same spot. - rewind(mark()) should not affect the input cursor. The Lexer - track line/col info as well as input index so its markers are - not pure input indexes. Same for tree node streams. - - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the symbol about to be - read not the most recently read symbol. - - - - - Reset the stream so that next call to index would return marker. - The marker will usually be Index but it doesn't have to be. It's - just a marker to indicate what state the stream was in. This is - essentially calling release() and seek(). If there are markers - created after this marker argument, this routine must unroll them - like a stack. Assume the state the stream was in when this marker - was created. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. It is - like invoking rewind(last marker) but it should not "pop" - the marker off. It's like seek(last marker's input position). - - - - - You may want to commit to a backtrack but don't want to force the - stream to keep bookkeeping objects around for a marker that is - no longer necessary. This will have the same behavior as - rewind() except it releases resources without the backward seek. - This must throw away resources for all markers back to the marker - argument. So if you're nested 5 levels of mark(), and then release(2) - you have to release resources for depths 2..5. - - - - - Set the input cursor to the position indicated by index. This is - normally used to seek ahead in the input stream. No buffering is - required to do this unless you know your stream will use seek to - move backwards such as when backtracking. - - - - This is different from rewind in its multi-directional - requirement and in that its argument is strictly an input cursor (index). - - For char streams, seeking forward must update the stream state such - as line number. For seeking backwards, you will be presumably - backtracking using the mark/rewind mechanism that restores state and - so this method does not need to update state when seeking backwards. - - Currently, this method is only used for efficient backtracking using - memoization, but in the future it may be used for incremental parsing. - - The index is 0..n-1. A seek to position i means that LA(1) will - return the ith symbol. So, seeking to 0 means LA(1) will return the - first element in the stream. - - - - - Only makes sense for streams that buffer everything up probably, but - might be useful to display the entire stream or for testing. This - value includes a single EOF. - - - - - Where are you getting symbols from? Normally, implementations will - pass the buck all the way to the lexer who can ask its input stream - for the file name or whatever. - - - - - Rules can have start/stop info. - - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - - Rules can have start/stop info. - - The element type of the input stream. - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - Get the text of the token - - - The line number on which this token was matched; line=1..n - - - The index of the first character relative to the beginning of the line 0..n-1 - - - - An index from 0..n-1 of the token object in the input stream. - This must be valid in order to use the ANTLRWorks debugger. - - - - - From what character stream was this token created? You don't have to - implement but it's nice to know where a Token comes from if you have - include files etc... on the input. - - - - - A source of tokens must provide a sequence of tokens via nextToken() - and also must reveal it's source of characters; CommonToken's text is - computed from a CharStream; it only store indices into the char stream. - - - - Errors from the lexer are never passed to the parser. Either you want - to keep going or you do not upon token recognition error. If you do not - want to continue lexing then you do not want to continue parsing. Just - throw an exception not under RecognitionException and Java will naturally - toss you all the way out of the recognizers. If you want to continue - lexing then you should not throw an exception to the parser--it has already - requested a token. Keep lexing until you get a valid one. Just report - errors and keep going, looking for a valid token. - - - - - Return a Token object from your input stream (usually a CharStream). - Do not fail/return upon lexing error; keep chewing on the characters - until you get a good one; errors are not passed through to the parser. - - - - - Where are you getting tokens from? normally the implication will simply - ask lexers input stream. - - - - A stream of tokens accessing tokens from a TokenSource - - - Get Token at current input pointer + i ahead where i=1 is next Token. - i<0 indicates tokens in the past. So -1 is previous token and -2 is - two tokens ago. LT(0) is undefined. For i>=n, return Token.EOFToken. - Return null for LT(0) and any index that results in an absolute address - that is negative. - - - - How far ahead has the stream been asked to look? The return - value is a valid index from 0..n-1. - - - - - Get a token at an absolute index i; 0..n-1. This is really only - needed for profiling and debugging and token stream rewriting. - If you don't want to buffer up tokens, then this method makes no - sense for you. Naturally you can't use the rewrite stream feature. - I believe DebugTokenStream can easily be altered to not use - this method, removing the dependency. - - - - - Where is this stream pulling tokens from? This is not the name, but - the object that provides Token objects. - - - - - Return the text of all tokens from start to stop, inclusive. - If the stream does not buffer all the tokens then it can just - return "" or null; Users should not access $ruleLabel.text in - an action of course in that case. - - - - - Because the user is not required to use a token with an index stored - in it, we must provide a means for two token objects themselves to - indicate the start/end location. Most often this will just delegate - to the other toString(int,int). This is also parallel with - the TreeNodeStream.toString(Object,Object). - - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - - Record every single token pulled from the source so we can reproduce - chunks of it later. - - - - Map from token type to channel to override some Tokens' channel numbers - - - Set of token types; discard any tokens with this type - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - By default, track all incoming tokens - - - Track the last mark() call result value for use in rewind(). - - - - The index into the tokens list of the current token (next token - to consume). p==-1 indicates that the tokens list is empty - - - - - How deep have we gone? - - - - Reset this token stream by setting its token source. - - - - Load all tokens from the token source and put in tokens. - This is done upon first LT request because you might want to - set some token type / channel overrides before filling buffer. - - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - - - Walk past any token not on the channel the parser is listening to. - - - - Given a starting index, return the index of the first on-channel token. - - - - A simple filter mechanism whereby you can tell this token stream - to force all tokens of type ttype to be on channel. For example, - when interpreting, we cannot exec actions so we need to tell - the stream to force all WS and NEWLINE to be a different, ignored - channel. - - - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - - Get the ith token from the current position 1..n where k=1 is the - first symbol of lookahead. - - - - Look backwards k tokens on-channel tokens - - - - Return absolute token i; ignore which channel the tokens are on; - that is, count all tokens not just on-channel tokens. - - - - - A lexer is recognizer that draws input symbols from a character stream. - lexer grammars result in a subclass of this object. A Lexer object - uses simplified match() and error recovery mechanisms in the interest - of speed. - - - - Where is the lexer drawing characters from? - - - - Gets or sets the text matched so far for the current token or any text override. - - - Setting this value replaces any previously set value, and overrides the original text. - - - - Return a token from this source; i.e., match a token on the char stream. - - - Returns the EOF token (default), if you need - to return a custom token instead override this method. - - - - Instruct the lexer to skip creating a token for current lexer rule - and look for another token. nextToken() knows to keep looking when - a lexer rule finishes with token set to SKIP_TOKEN. Recall that - if token==null at end of any token rule, it creates one for you - and emits it. - - - - This is the lexer entry point that sets instance var 'token' - - - - Currently does not support multiple emits per nextToken invocation - for efficiency reasons. Subclass and override this method and - nextToken (to push tokens into a list and pull from that list rather - than a single variable as this implementation does). - - - - - The standard method called to automatically emit a token at the - outermost lexical rule. The token object should point into the - char buffer start..stop. If there is a text override in 'text', - use that to set the token's text. Override this method to emit - custom Token objects. - - - - If you are building trees, then you should also override - Parser or TreeParser.getMissingSymbol(). - - - - What is the index of the current character of lookahead? - - - - Lexers can normally match any char in it's vocabulary after matching - a token, so do the easy thing and just kill a character and hope - it all works out. You can instead use the rule invocation stack - to do sophisticated error recovery if you are in a fragment rule. - - - - A queue that can dequeue and get(i) in O(1) and grow arbitrarily large. - A linked list is fast at dequeue but slow at get(i). An array is - the reverse. This is O(1) for both operations. - - List grows until you dequeue last element at end of buffer. Then - it resets to start filling at 0 again. If adds/removes are balanced, the - buffer will not grow too large. - - No iterator stuff as that's not how we'll use it. - - - dynamically-sized buffer of elements - - - index of next element to fill - - - - How deep have we gone? - - - - - Return element {@code i} elements ahead of current element. {@code i==0} - gets current element. This is not an absolute index into {@link #data} - since {@code p} defines the start of the real list. - - - - Get and remove first element in queue - - - Return string of current buffer contents; non-destructive - - - - A lookahead queue that knows how to mark/release locations in the buffer for - backtracking purposes. Any markers force the {@link FastQueue} superclass to - keep all elements until no more markers; then can reset to avoid growing a - huge buffer. - - - - Absolute token index. It's the index of the symbol about to be - read via {@code LT(1)}. Goes from 0 to numtokens. - - - This is the {@code LT(-1)} element for the first element in {@link #data}. - - - Track object returned by nextElement upon end of stream; - Return it later when they ask for LT passed end of input. - - - Track the last mark() call result value for use in rewind(). - - - tracks how deep mark() calls are nested - - - - Implement nextElement to supply a stream of elements to this - lookahead buffer. Return EOF upon end of the stream we're pulling from. - - - - - Get and remove first element in queue; override - {@link FastQueue#remove()}; it's the same, just checks for backtracking. - - - - Make sure we have at least one element to remove, even if EOF - - - - Make sure we have 'need' elements from current position p. Last valid - p index is data.size()-1. p+need-1 is the data index 'need' elements - ahead. If we need 1 element, (p+1-1)==p must be < data.size(). - - - - add n elements to buffer - - - Size of entire stream is unknown; we only know buffer size from FastQueue - - - - Seek to a 0-indexed absolute token index. Normally used to seek backwards - in the buffer. Does not force loading of nodes. - - - To preserve backward compatibility, this method allows seeking past the - end of the currently buffered data. In this case, the input pointer will - be moved but the data will only actually be loaded upon the next call to - {@link #consume} or {@link #LT} for {@code k>0}. - - - - A mismatched char or Token or tree node - - - - We were expecting a token but it's not found. The current token - is actually what we wanted next. Used for tree node errors too. - - - - - A parser for TokenStreams. "parser grammars" result in a subclass - of this. - - - - Gets or sets the token stream; resets the parser upon a set. - - - - Rules that return more than a single value must return an object - containing all the values. Besides the properties defined in - RuleLabelScope.predefinedRulePropertiesScope there may be user-defined - return values. This class simply defines the minimum properties that - are always defined and methods to access the others that might be - available depending on output option such as template and tree. - - - - Note text is not an actual property of the return value, it is computed - from start and stop using the input stream's toString() method. I - could add a ctor to this so that we can pass in and store the input - stream, but I'm not sure we want to do that. It would seem to be undefined - to get the .text property anyway if the rule matches tokens from multiple - input streams. - - I do not use getters for fields of objects that are used simply to - group values such as this aggregate. The getters/setters are there to - satisfy the superclass interface. - - - - The root of the ANTLR exception hierarchy. - - - To avoid English-only error messages and to generally make things - as flexible as possible, these exceptions are not created with strings, - but rather the information necessary to generate an error. Then - the various reporting methods in Parser and Lexer can be overridden - to generate a localized error message. For example, MismatchedToken - exceptions are built with the expected token type. - So, don't expect getMessage() to return anything. - - Note that as of Java 1.4, you can access the stack trace, which means - that you can compute the complete trace of rules from the start symbol. - This gives you considerable context information with which to generate - useful error messages. - - ANTLR generates code that throws exceptions upon recognition error and - also generates code to catch these exceptions in each rule. If you - want to quit upon first error, you can turn off the automatic error - handling mechanism using rulecatch action, but you still need to - override methods mismatch and recoverFromMismatchSet. - - In general, the recognition exceptions can track where in a grammar a - problem occurred and/or what was the expected input. While the parser - knows its state (such as current input symbol and line info) that - state can change before the exception is reported so current token index - is computed and stored at exception time. From this info, you can - perhaps print an entire line of input not just a single token, for example. - Better to just say the recognizer had a problem and then let the parser - figure out a fancy report. - - - - What input stream did the error occur in? - - - - What was the lookahead index when this exception was thrown? - - - - What is index of token/char were we looking at when the error occurred? - - - - The current Token when an error occurred. Since not all streams - can retrieve the ith Token, we have to track the Token object. - For parsers. Even when it's a tree parser, token might be set. - - - - - If this is a tree parser exception, node is set to the node with - the problem. - - - - The current char when an error occurred. For lexers. - - - - Track the line (1-based) at which the error occurred in case this is - generated from a lexer. We need to track this since the - unexpected char doesn't carry the line info. - - - - - The 0-based index into the line where the error occurred. - - - - - If you are parsing a tree node stream, you will encounter som - imaginary nodes w/o line/col info. We now search backwards looking - for most recent token with line/col info, but notify getErrorHeader() - that info is approximate. - - - - Used for remote debugger deserialization - - - Return the token type or char of the unexpected input element - - - - The set of fields needed by an abstract recognizer to recognize input - and recover from errors etc... As a separate state object, it can be - shared among multiple grammars; e.g., when one grammar imports another. - - - - These fields are publically visible but the actual state pointer per - parser is protected. - - - - - Track the set of token types that can follow any rule invocation. - Stack grows upwards. When it hits the max, it grows 2x in size - and keeps going. - - - - - This is true when we see an error and before having successfully - matched a token. Prevents generation of more than one error message - per error. - - - - - The index into the input stream where the last error occurred. - This is used to prevent infinite loops where an error is found - but no token is consumed during recovery...another error is found, - ad naseum. This is a failsafe mechanism to guarantee that at least - one token/tree node is consumed for two errors. - - - - - In lieu of a return value, this indicates that a rule or token - has failed to match. Reset to false upon valid token match. - - - - Did the recognizer encounter a syntax error? Track how many. - - - - If 0, no backtracking is going on. Safe to exec actions etc... - If >0 then it's the level of backtracking. - - - - - An array[size num rules] of dictionaries that tracks - the stop token index for each rule. ruleMemo[ruleIndex] is - the memoization table for ruleIndex. For key ruleStartIndex, you - get back the stop token for associated rule or MEMO_RULE_FAILED. - - - This is only used if rule memoization is on (which it is by default). - - - - The goal of all lexer rules/methods is to create a token object. - This is an instance variable as multiple rules may collaborate to - create a single token. nextToken will return this object after - matching lexer rule(s). If you subclass to allow multiple token - emissions, then set this to the last token to be matched or - something nonnull so that the auto token emit mechanism will not - emit another token. - - - - - What character index in the stream did the current token start at? - Needed, for example, to get the text for current token. Set at - the start of nextToken. - - - - The line on which the first character of the token resides - - - The character position of first character within the line - - - The channel number for the current token - - - The token type for the current token - - - - You can set the text for the current token to override what is in - the input char buffer. Use setText() or can set this instance var. - - - - - All tokens go to the parser (unless skip() is called in that rule) - on a particular "channel". The parser tunes to a particular channel - so that whitespace etc... can go to the parser on a "hidden" channel. - - - - - Anything on different channel than DEFAULT_CHANNEL is not parsed - by parser. - - - - Useful for dumping out the input stream after doing some - augmentation or other manipulations. - - You can insert stuff, replace, and delete chunks. Note that the - operations are done lazily--only if you convert the buffer to a - String. This is very efficient because you are not moving data around - all the time. As the buffer of tokens is converted to strings, the - toString() method(s) check to see if there is an operation at the - current index. If so, the operation is done and then normal String - rendering continues on the buffer. This is like having multiple Turing - machine instruction streams (programs) operating on a single input tape. :) - - Since the operations are done lazily at toString-time, operations do not - screw up the token index values. That is, an insert operation at token - index i does not change the index values for tokens i+1..n-1. - - Because operations never actually alter the buffer, you may always get - the original token stream back without undoing anything. Since - the instructions are queued up, you can easily simulate transactions and - roll back any changes if there is an error just by removing instructions. - For example, - - CharStream input = new ANTLRFileStream("input"); - TLexer lex = new TLexer(input); - TokenRewriteStream tokens = new TokenRewriteStream(lex); - T parser = new T(tokens); - parser.startRule(); - - Then in the rules, you can execute - Token t,u; - ... - input.insertAfter(t, "text to put after t");} - input.insertAfter(u, "text after u");} - System.out.println(tokens.toString()); - - Actually, you have to cast the 'input' to a TokenRewriteStream. :( - - You can also have multiple "instruction streams" and get multiple - rewrites from a single pass over the input. Just name the instruction - streams and use that name again when printing the buffer. This could be - useful for generating a C file and also its header file--all from the - same buffer: - - tokens.insertAfter("pass1", t, "text to put after t");} - tokens.insertAfter("pass2", u, "text after u");} - System.out.println(tokens.toString("pass1")); - System.out.println(tokens.toString("pass2")); - - If you don't use named rewrite streams, a "default" stream is used as - the first example shows. - - - What index into rewrites List are we? - - - Token buffer index. - - - - Execute the rewrite operation by possibly adding to the buffer. - Return the index of the next token to operate on. - - - - - I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp - instructions. - - - - - You may have multiple, named streams of rewrite operations. - I'm calling these things "programs." - Maps String (name) -> rewrite (List) - - - - Map String (program name) -> Integer index - - - - Rollback the instruction stream for a program so that - the indicated instruction (via instructionIndex) is no - longer in the stream. UNTESTED! - - - - Reset the program so that no instructions exist - - - We need to combine operations and report invalid operations (like - overlapping replaces that are not completed nested). Inserts to - same index need to be combined etc... Here are the cases: - - I.i.u I.j.v leave alone, nonoverlapping - I.i.u I.i.v combine: Iivu - - R.i-j.u R.x-y.v | i-j in x-y delete first R - R.i-j.u R.i-j.v delete first R - R.i-j.u R.x-y.v | x-y in i-j ERROR - R.i-j.u R.x-y.v | boundaries overlap ERROR - - Delete special case of replace (text==null): - D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) - - I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before - we're not deleting i) - I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping - R.x-y.v I.i.u | i in x-y ERROR - R.x-y.v I.x.u R.x-y.uv (combine, delete I) - R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping - - I.i.u = insert u before op @ index i - R.x-y.u = replace x-y indexed tokens with u - - First we need to examine replaces. For any replace op: - - 1. wipe out any insertions before op within that range. - 2. Drop any replace op before that is contained completely within - that range. - 3. Throw exception upon boundary overlap with any previous replace. - - Then we can deal with inserts: - - 1. for any inserts to same index, combine even if not adjacent. - 2. for any prior replace with same left boundary, combine this - insert with replace and delete this replace. - 3. throw exception if index in same range as previous replace - - Don't actually delete; make op null in list. Easier to walk list. - Later we can throw as we add to index -> op map. - - Note that I.2 R.2-2 will wipe out I.2 even though, technically, the - inserted stuff would be before the replace range. But, if you - add tokens in front of a method body '{' and then delete the method - body, I think the stuff before the '{' you added should disappear too. - - Return a map from token index to operation. - - - Get all operations before an index of a particular kind - - - - In an action, a lexer rule can set token to this SKIP_TOKEN and ANTLR - will avoid creating a token for this symbol and try to fetch another. - - - - imaginary tree navigation type; traverse "get child" link - - - imaginary tree navigation type; finish with a child list - - - - A generic tree implementation with no payload. You must subclass to - actually have any user data. ANTLR v3 uses a list of children approach - instead of the child-sibling approach in v2. A flat tree (a list) is - an empty node whose children represent the list. An empty, but - non-null node is called "nil". - - - - - Create a new node from an existing node does nothing for BaseTree - as there are no fields other than the children list, which cannot - be copied as the children are not considered part of this node. - - - - - Get the children internal List; note that if you directly mess with - the list, do so at your own risk. - - - - BaseTree doesn't track parent pointers. - - - BaseTree doesn't track child indexes. - - - Add t as child of this node. - - - Warning: if t has no children, but child does - and child isNil then this routine moves children to t via - t.children = child.children; i.e., without copying the array. - - - - Add all elements of kids list as children of this node - - - Insert child t at child position i (0..n-1) by shifting children - i+1..n-1 to the right one position. Set parent / indexes properly - but does NOT collapse nil-rooted t's that come in here like addChild. - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - Override in a subclass to change the impl of children list - - - Set the parent and child index values for all child of t - - - Walk upwards looking for ancestor with this token type. - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - Print out a whole tree not just a node - - - Override to say how a node (not a tree) should look as text - - - A TreeAdaptor that works with any Tree implementation. - - - - System.identityHashCode() is not always unique; we have to - track ourselves. That's ok, it's only for debugging, though it's - expensive: we have to create a hashtable with all tree nodes in it. - - - - - Create tree node that holds the start and stop tokens associated - with an error. - - - - If you specify your own kind of tree nodes, you will likely have to - override this method. CommonTree returns Token.INVALID_TOKEN_TYPE - if no token payload but you might have to set token type for diff - node type. - - You don't have to subclass CommonErrorNode; you will likely need to - subclass your own tree node class to avoid class cast exception. - - - - - This is generic in the sense that it will work with any kind of - tree (not just ITree interface). It invokes the adaptor routines - not the tree node routines to do the construction. - - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - Transform ^(nil x) to x and nil to null - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Duplicate a node. This is part of the factory; - override if you want another kind of node to be built. - - - - I could use reflection to prevent having to override this - but reflection is slow. - - - - - Track start/stop token for subtree root created for a rule. - Only works with Tree nodes. For rules that match nothing, - seems like this will yield start=i and stop=i-1 in a nil node. - Might be useful info so I'll not force to be i..i. - - - - A buffered stream of tree nodes. Nodes can be from a tree of ANY kind. - - This node stream sucks all nodes out of the tree specified in - the constructor during construction and makes pointers into - the tree using an array of Object pointers. The stream necessarily - includes pointers to DOWN and UP and EOF nodes. - - This stream knows how to mark/release for backtracking. - - This stream is most suitable for tree interpreters that need to - jump around a lot or for tree parsers requiring speed (at cost of memory). - There is some duplicated functionality here with UnBufferedTreeNodeStream - but just in bookkeeping, not tree walking etc... - - TARGET DEVELOPERS: - - This is the old CommonTreeNodeStream that buffered up entire node stream. - No need to implement really as new CommonTreeNodeStream is much better - and covers what we need. - - @see CommonTreeNodeStream - - - The complete mapping from stream index to tree node. - This buffer includes pointers to DOWN, UP, and EOF nodes. - It is built upon ctor invocation. The elements are type - Object as we don't what the trees look like. - - Load upon first need of the buffer so we can set token types - of interest for reverseIndexing. Slows us down a wee bit to - do all of the if p==-1 testing everywhere though. - - - Pull nodes from which tree? - - - IF this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - Reuse same DOWN, UP navigation nodes unless this is true - - - The index into the nodes list of the current node (next node - to consume). If -1, nodes array not filled yet. - - - Track the last mark() call result value for use in rewind(). - - - Stack of indexes used for push/pop calls - - - Walk tree with depth-first-search and fill nodes buffer. - Don't do DOWN, UP nodes if its a list (t is isNil). - - - What is the stream index for node? 0..n-1 - Return -1 if node not found. - - - As we flatten the tree, we use UP, DOWN nodes to represent - the tree structure. When debugging we need unique nodes - so instantiate new ones when uniqueNavigationNodes is true. - - - Look backwards k nodes - - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - - Used for testing, just return the token type stream - - - Debugging - - - A node representing erroneous token range in token stream - - - - A tree node that is wrapper for a Token object. After 3.0 release - while building tree rewrite stuff, it became clear that computing - parent and child index is very difficult and cumbersome. Better to - spend the space in every tree node. If you don't want these extra - fields, it's easy to cut them out in your own BaseTree subclass. - - - - A single token is the payload - - - - What token indexes bracket all tokens associated with this node - and below? - - - - Who is the parent node of this node; if null, implies node is root - - - What index is this node in the child list? Range: 0..n-1 - - - - For every node in this subtree, make sure it's start/stop token's - are set. Walk depth first, visit bottom up. Only updates nodes - with at least one token index < 0. - - - - - A TreeAdaptor that works with any Tree implementation. It provides - really just factory methods; all the work is done by BaseTreeAdaptor. - If you would like to have different tokens created than ClassicToken - objects, you need to override this and then set the parser tree adaptor to - use your subclass. - - - - To get your parser to build nodes of a different type, override - create(Token), errorNode(), and to be safe, YourTreeClass.dupNode(). - dupNode is called to duplicate nodes during rewrite operations. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - What is the Token associated with this node? If - you are not using CommonTree, then you must - override this in your own adaptor. - - - - Pull nodes from which tree? - - - If this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - The tree iterator we are using - - - Stack of indexes used for push/pop calls - - - Tree (nil A B C) trees like flat A B C streams - - - Tracks tree depth. Level=0 means we're at root node level. - - - Tracks the last node before the start of {@link #data} which contains - position information to provide information for error reporting. This is - tracked in addition to {@link #prevElement} which may or may not contain - position information. - - @see #hasPositionInformation - @see RecognitionException#extractInformationFromTreeNodeStream - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - Returns an element containing position information. If {@code allowApproximateLocation} is {@code false}, then - this method will return the {@code LT(1)} element if it contains position information, and otherwise return {@code null}. - If {@code allowApproximateLocation} is {@code true}, then this method will return the last known element containing position information. - - @see #hasPositionInformation - - - For debugging; destructive: moves tree iterator to end. - - - A utility class to generate DOT diagrams (graphviz) from - arbitrary trees. You can pass in your own templates and - can pass in any kind of tree or use Tree interface method. - I wanted this separator so that you don't have to include - ST just to use the org.antlr.runtime.tree.* package. - This is a set of non-static methods so you can subclass - to override. For example, here is an invocation: - - CharStream input = new ANTLRInputStream(System.in); - TLexer lex = new TLexer(input); - CommonTokenStream tokens = new CommonTokenStream(lex); - TParser parser = new TParser(tokens); - TParser.e_return r = parser.e(); - Tree t = (Tree)r.tree; - System.out.println(t.toStringTree()); - DOTTreeGenerator gen = new DOTTreeGenerator(); - StringTemplate st = gen.toDOT(t); - System.out.println(st); - - - Track node to number mapping so we can get proper node name back - - - Track node number so we can get unique node names - - - Generate DOT (graphviz) for a whole tree not just a node. - For example, 3+4*5 should generate: - - digraph { - node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier", - width=.4, height=.2]; - edge [arrowsize=.7] - "+"->3 - "+"->"*" - "*"->4 - "*"->5 - } - - Takes a Tree interface object. - - - - @author Sam Harwell - - - Returns an element containing concrete information about the current - position in the stream. - - @param allowApproximateLocation if {@code false}, this method returns - {@code null} if an element containing exact information about the current - position is not available - - - Determines if the specified {@code element} contains concrete position - information. - - @param element the element to check - @return {@code true} if {@code element} contains concrete position - information, otherwise {@code false} - - - - What does a tree look like? ANTLR has a number of support classes - such as CommonTreeNodeStream that work on these kinds of trees. You - don't have to make your trees implement this interface, but if you do, - you'll be able to use more support code. - - - - NOTE: When constructing trees, ANTLR can build any kind of tree; it can - even use Token objects as trees if you add a child list to your tokens. - - This is a tree node without any payload; just navigation and factory stuff. - - - - Is there is a node above with token type ttype? - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - This node is what child index? 0..n-1 - - - Set the parent and child index values for all children - - - - Add t as a child to this node. If t is null, do nothing. If t - is nil, add all children of t to this' children. - - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - - Indicates the node is a nil node but may still have children, meaning - the tree is a flat list. - - - - - What is the smallest token index (indexing from 0) for this node - and its children? - - - - - What is the largest token index (indexing from 0) for this node - and its children? - - - - Return a token type; needed for tree parsing - - - In case we don't have a token payload, what is the line for errors? - - - - How to create and navigate trees. Rather than have a separate factory - and adaptor, I've merged them. Makes sense to encapsulate. - - - - This takes the place of the tree construction code generated in the - generated code in 2.x and the ASTFactory. - - I do not need to know the type of a tree at all so they are all - generic Objects. This may increase the amount of typecasting needed. :( - - - - - Create a tree node from Token object; for CommonTree type trees, - then the token just becomes the payload. This is the most - common create call. - - - - Override if you want another kind of node to be built. - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel]. - - - - This should invoke createToken(Token). - - - - - Same as create(tokenType,fromToken) except set the text too. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel, "IMAG"]. - - - - This should invoke createToken(Token). - - - - - Same as create(fromToken) except set the text too. - This is invoked when the text terminal option is set, as in - IMAG<text='IMAG'>. - - - - This should invoke createToken(Token). - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG["IMAG"]. - - - - This should invoke createToken(int,String). - - - - Duplicate a single tree node. - Override if you want another kind of node to be built. - - - Duplicate tree recursively, using dupNode() for each node - - - - Return a nil node (an empty but non-null node) that can hold - a list of element as the children. If you want a flat tree (a list) - use "t=adaptor.nil(); t.addChild(x); t.addChild(y);" - - - - - Return a tree node representing an error. This node records the - tokens consumed during error recovery. The start token indicates the - input symbol at which the error was detected. The stop token indicates - the last symbol consumed during recovery. - - - - You must specify the input stream so that the erroneous text can - be packaged up in the error node. The exception could be useful - to some applications; default implementation stores ptr to it in - the CommonErrorNode. - - This only makes sense during token parsing, not tree parsing. - Tree parsing should happen only when parsing and tree construction - succeed. - - - - Is tree considered a nil node used to make lists of child nodes? - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. Do nothing if t or child is null. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - - Given the root of the subtree created for this rule, post process - it to do any simplifications or whatever you want. A required - behavior is to convert ^(nil singleSubtree) to singleSubtree - as the setting of start/stop indexes relies on a single non-nil root - for non-flat trees. - - - - Flat trees such as for lists like "idlist : ID+ ;" are left alone - unless there is only one ID. For a list, the start/stop indexes - are set in the nil node. - - This method is executed after all rule tree construction and right - before setTokenBoundaries(). - - - - For identifying trees. - - - How to identify nodes so we can say "add node to a prior node"? - Even becomeRoot is an issue. Use System.identityHashCode(node) - usually. - - - - - Create a node for newRoot make it the root of oldRoot. - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - Return node created for newRoot. - - - - Be advised: when debugging ASTs, the DebugTreeAdaptor manually - calls create(Token child) and then plain becomeRoot(node, node) - because it needs to trap calls to create, but it can't since it delegates - to not inherits from the TreeAdaptor. - - - - For tree parsing, I need to know the token type of a node - - - Node constructors can set the type of a node - - - Node constructors can set the text of a node - - - - Return the token object from which this node was created. - Currently used only for printing an error message. - The error display routine in BaseRecognizer needs to - display where the input the error occurred. If your - tree of limitation does not store information that can - lead you to the token, you can create a token filled with - the appropriate information and pass that back. See - BaseRecognizer.getErrorMessage(). - - - - - Where are the bounds in the input token stream for this node and - all children? Each rule that creates AST nodes will call this - method right before returning. Flat trees (i.e., lists) will - still usually have a nil root node just to hold the children list. - That node would contain the start/stop indexes then. - - - - Get the token start index for this subtree; return -1 if no such index - - - Get the token stop index for this subtree; return -1 if no such index - - - Get a child 0..n-1 node - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - Remove ith child and shift children down from right. - - - How many children? If 0, then this is a leaf node - - - - Who is the parent node of this node; if null, implies node is root. - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - What index is this node in the child list? Range: 0..n-1 - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - Replace from start to stop child index of parent with t, which might - be a list. Number of children may be different after this call. - - - - If parent is null, don't do anything; must be at root of overall tree. - Can't replace whatever points to the parent externally. Do nothing. - - - - A stream of tree nodes, accessing nodes from a tree of some kind - - - - Get a tree node at an absolute index i; 0..n-1. - If you don't want to buffer up nodes, then this method makes no - sense for you. - - - - - Get tree node at current input pointer + ahead where - ==1 is next node. <0 indicates nodes in the past. So - {@code LT(-1)} is previous node, but implementations are not required to - provide results for < -1. {@code LT(0)} is undefined. For - <=n, return . Return for {@code LT(0)} - and any index that results in an absolute address that is negative. - - - - This is analogous to , but this returns a tree node - instead of a . Makes code generation identical for both - parser and tree grammars. - - - - - Where is this stream pulling nodes from? This is not the name, but - the object that provides node objects. - - - - - If the tree associated with this stream was created from a - {@link TokenStream}, you can specify it here. Used to do rule - {@code $text} attribute in tree parser. Optional unless you use tree - parser rule {@code $text} attribute or {@code output=template} and - {@code rewrite=true} options. - - - - - What adaptor can tell me how to interpret/navigate nodes and - trees. E.g., get text of a node. - - - - - As we flatten the tree, we use {@link Token#UP}, {@link Token#DOWN} nodes - to represent the tree structure. When debugging we need unique nodes so - we have to instantiate new ones. When doing normal tree parsing, it's - slow and a waste of memory to create unique navigation nodes. Default - should be {@code false}. - - - - - Return the text of all nodes from {@code start} to {@code stop}, - inclusive. If the stream does not buffer all the nodes then it can still - walk recursively from start until stop. You can always return - {@code null} or {@code ""} too, but users should not access - {@code $ruleLabel.text} in an action of course in that case. - - - - - Replace children of {@code parent} from index {@code startChildIndex} to - {@code stopChildIndex} with {@code t}, which might be a list. Number of - children may be different after this call. The stream is notified because - it is walking the tree and might need to know you are monkeying with the - underlying tree. Also, it might be able to modify the node stream to - avoid restreaming for future phases. - - - - If {@code parent} is {@code null}, don't do anything; must be at root of - overall tree. Can't replace whatever points to the parent externally. Do - nothing. - - - - - How to execute code for node t when a visitor visits node t. Execute - pre() before visiting children and execute post() after visiting children. - - - - - Execute an action before visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. Children of returned value will be - visited if using TreeVisitor.visit(). - - - - - Execute an action after visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. - - - - - A record of the rules used to match a token sequence. The tokens - end up as the leaves of this tree and rule nodes are the interior nodes. - This really adds no functionality, it is just an alias for CommonTree - that is more meaningful (specific) and holds a String to display for a node. - - - - - Emit a token and all hidden nodes before. EOF node holds all - hidden tokens after last real token. - - - - - Print out the leaves of this tree, which means printing original - input back out. - - - - - Base class for all exceptions thrown during AST rewrite construction. - This signifies a case where the cardinality of two or more elements - in a subrule are different: (ID INT)+ where |ID|!=|INT| - - - - No elements within a (...)+ in a rewrite rule - - - Ref to ID or expr but no tokens in ID stream or subtrees in expr stream - - - - A generic list of elements tracked in an alternative to be used in - a -> rewrite rule. We need to subclass to fill in the next() method, - which returns either an AST node wrapped around a token payload or - an existing subtree. - - - - Once you start next()ing, do not try to add more elements. It will - break the cursor tracking I believe. - - TODO: add mechanism to detect/puke on modification after reading from stream - - - - - - - - Cursor 0..n-1. If singleElement!=null, cursor is 0 until you next(), - which bumps it to 1 meaning no more elements. - - - - Track single elements w/o creating a list. Upon 2nd add, alloc list - - - The list of tokens or subtrees we are tracking - - - Once a node / subtree has been used in a stream, it must be dup'd - from then on. Streams are reset after subrules so that the streams - can be reused in future subrules. So, reset must set a dirty bit. - If dirty, then next() always returns a dup. - - - The element or stream description; usually has name of the token or - rule reference that this list tracks. Can include rulename too, but - the exception would track that info. - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Reset the condition of this stream so that it appears we have - not consumed any of its elements. Elements themselves are untouched. - Once we reset the stream, any future use will need duplicates. Set - the dirty bit. - - - - - Return the next element in the stream. If out of elements, throw - an exception unless size()==1. If size is 1, then return elements[0]. - Return a duplicate node/subtree if stream is out of elements and - size==1. If we've already used the element, dup (dirty bit set). - - - - - Do the work of getting the next element, making sure that it's - a tree node or subtree. Deal with the optimization of single- - element list versus list of size > 1. Throw an exception - if the stream is empty or we're out of elements and size>1. - protected so you can override in a subclass if necessary. - - - - - When constructing trees, sometimes we need to dup a token or AST - subtree. Dup'ing a token means just creating another AST node - around it. For trees, you must call the adaptor.dupTree() unless - the element is for a tree root; then it must be a node dup. - - - - - Ensure stream emits trees; tokens must be converted to AST nodes. - AST nodes can be passed through unmolested. - - - - - Queues up nodes matched on left side of -> in a tree parser. This is - the analog of RewriteRuleTokenStream for normal parsers. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Treat next element as a single node even if it's a subtree. - This is used instead of next() when the result has to be a - tree root node. Also prevents us from duplicating recently-added - children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration - must dup the type node, but ID has been added. - - - - Referencing a rule result twice is ok; dup entire tree as - we can't be adding trees as root; e.g., expr expr. - - Hideous code duplication here with super.next(). Can't think of - a proper way to refactor. This needs to always call dup node - and super.next() doesn't know which to call: dup node or dup tree. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Get next token from stream and make a node for it - - - - Don't convert to a tree unless they explicitly call nextTree. - This way we can do hetero tree nodes in rewrite. - - - - Return a node stream from a doubly-linked tree whose nodes - know what child index they are. No remove() is supported. - - Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure. - - - If we emit UP/DOWN nodes, we need to spit out multiple nodes per - next() call. - - - - A parser for a stream of tree nodes. "tree grammars" result in a subclass - of this. All the error reporting and recovery is shared with Parser via - the BaseRecognizer superclass. - - - - Set the input stream - - - - Match '.' in tree parser has special meaning. Skip node or - entire tree if node has children. If children, scan until - corresponding UP node. - - - - - We have DOWN/UP nodes in the stream that have no line info; override. - plus we want to alter the exception type. Don't try to recover - from tree parser errors inline... - - - - - Prefix error message with the grammar name because message is - always intended for the programmer because the parser built - the input tree not the user. - - - - - Tree parsers parse nodes they usually have a token object as - payload. Set the exception token and do the default behavior. - - - - The tree pattern to lex like "(A B C)" - - - Index into input string - - - Current char - - - How long is the pattern in char? - - - Set when token type is ID or ARG (name mimics Java's StreamTokenizer) - - - Override this if you need transformation tracing to go somewhere - other than stdout or if you're not using ITree-derived trees. - - - - This is identical to the ParserRuleReturnScope except that - the start property is a tree nodes not Token object - when you are parsing trees. - - - - Gets the first node or root node of tree matched for this rule. - - - Do a depth first walk of a tree, applying pre() and post() actions as we go. - - - - Visit every node in tree t and trigger an action for each node - before/after having visited all of its children. Bottom up walk. - Execute both actions even if t has no children. Ignore return - results from transforming children since they will have altered - the child list of this node (their parent). Return result of - applying post action to this node. - - - - - Build and navigate trees with this object. Must know about the names - of tokens so you have to pass in a map or array of token names (from which - this class can build the map). I.e., Token DECL means nothing unless the - class can translate it to a token type. - - - - In order to create nodes and navigate, this class needs a TreeAdaptor. - - This class can build a token type -> node index for repeated use or for - iterating over the various nodes with a particular type. - - This class works in conjunction with the TreeAdaptor rather than moving - all this functionality into the adaptor. An adaptor helps build and - navigate trees using methods. This class helps you do it with string - patterns like "(A B C)". You can create a tree from that pattern or - match subtrees against it. - - - - - When using %label:TOKENNAME in a tree for parse(), we must - track the label. - - - - This adaptor creates TreePattern objects for use during scan() - - - - Compute a Map<String, Integer> that is an inverted index of - tokenNames (which maps int token types to names). - - - - Using the map of token names to token types, return the type. - - - - Walk the entire tree and make a node name to nodes mapping. - For now, use recursion but later nonrecursive version may be - more efficient. Returns Map<Integer, List> where the List is - of your AST node type. The Integer is the token type of the node. - - - - TODO: save this index so that find and visit are faster - - - - Do the work for index - - - Return a List of tree nodes with token type ttype - - - Return a List of subtrees matching pattern. - - - - Visit every ttype node in t, invoking the visitor. This is a quicker - version of the general visit(t, pattern) method. The labels arg - of the visitor action method is never set (it's null) since using - a token type rather than a pattern doesn't let us set a label. - - - - Do the recursive work for visit - - - - For all subtrees that match the pattern, execute the visit action. - The implementation uses the root node of the pattern in combination - with visit(t, ttype, visitor) so nil-rooted patterns are not allowed. - Patterns with wildcard roots are also not allowed. - - - - - Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels - on the various nodes and '.' (dot) as the node/subtree wildcard, - return true if the pattern matches and fill the labels Map with - the labels pointing at the appropriate nodes. Return false if - the pattern is malformed or the tree does not match. - - - - If a node specifies a text arg in pattern, then that must match - for that node in t. - - TODO: what's a better way to indicate bad pattern? Exceptions are a hassle - - - - - Do the work for parse. Check to see if the t2 pattern fits the - structure and token types in t1. Check text if the pattern has - text arguments on nodes. Fill labels map with pointers to nodes - in tree matched against nodes in pattern with labels. - - - - - Create a tree or node from the indicated tree pattern that closely - follows ANTLR tree grammar tree element syntax: - - (root child1 ... child2). - - - - You can also just pass in a node: ID - - Any node can have a text argument: ID[foo] - (notice there are no quotes around foo--it's clear it's a string). - - nil is a special name meaning "give me a nil node". Useful for - making lists: (nil A B C) is a list of A B C. - - - - - Compare t1 and t2; return true if token types/text, structure match exactly. - The trees are examined in their entirety so that (A B) does not match - (A B C) nor (A (B C)). - - - - TODO: allow them to pass in a comparator - TODO: have a version that is nonstatic so it can use instance adaptor - - I cannot rely on the tree node's equals() implementation as I make - no constraints at all on the node types nor interface etc... - - - - - Compare type, structure, and text of two trees, assuming adaptor in - this instance of a TreeWizard. - - - - A token stream that pulls tokens from the code source on-demand and - without tracking a complete buffer of the tokens. This stream buffers - the minimum number of tokens possible. It's the same as - OnDemandTokenStream except that OnDemandTokenStream buffers all tokens. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - - You can only look backwards 1 token: LT(-1). - - Use this when you need to read from a socket or other infinite stream. - - @see BufferedTokenStream - @see CommonTokenStream - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - An extra token while parsing a TokenStream - - - diff --git a/packages/Antlr3.Runtime.3.5.1/lib/netstandard1.1/Antlr3.Runtime.dll b/packages/Antlr3.Runtime.3.5.1/lib/netstandard1.1/Antlr3.Runtime.dll deleted file mode 100644 index 1bab12edd..000000000 Binary files a/packages/Antlr3.Runtime.3.5.1/lib/netstandard1.1/Antlr3.Runtime.dll and /dev/null differ diff --git a/packages/Antlr3.Runtime.3.5.1/lib/netstandard1.1/Antlr3.Runtime.xml b/packages/Antlr3.Runtime.3.5.1/lib/netstandard1.1/Antlr3.Runtime.xml deleted file mode 100644 index 31d731fa3..000000000 --- a/packages/Antlr3.Runtime.3.5.1/lib/netstandard1.1/Antlr3.Runtime.xml +++ /dev/null @@ -1,3220 +0,0 @@ - - - - Antlr3.Runtime - - - - - A kind of ReaderStream that pulls from an InputStream. - Useful for reading from stdin and specifying file encodings etc... - - - - - Vacuum all input from a Reader and then treat it like a StringStream. - Manage the buffer manually to avoid unnecessary data copying. - - - - If you need encoding, use ANTLRInputStream. - - - - - A pretty quick CharStream that pulls all data from an array - directly. Every method call counts in the lexer. Java's - strings aren't very good so I'm avoiding. - - - - The data being scanned - - - How many characters are actually in the buffer - - - 0..n-1 index into string of next char - - - line number 1..n within the input - - - The index of the character relative to the beginning of the line 0..n-1 - - - tracks how deep mark() calls are nested - - - - A list of CharStreamState objects that tracks the stream state - values line, charPositionInLine, and p that can change as you - move through the input stream. Indexed from 1..markDepth. - A null is kept @ index 0. Create upon first call to mark(). - - - - Track the last mark() call result value for use in rewind(). - - - What is name or source of this char stream? - - - Copy data in string to a local char array - - - This is the preferred constructor as no data is copied - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the index of char to - be returned from LA(1). - - - - - Reset the stream so that it's in the same state it was - when the object was created *except* the data array is not - touched. - - - - - consume() ahead until p==index; can't just set p=index as we must - update line and charPositionInLine. - - - - - A generic recognizer that can handle recognizers generated from - lexer, parser, and tree grammars. This is all the parsing - support code essentially; most of it is error recovery stuff and - backtracking. - - - - - State of a lexer, parser, or tree parser are collected into a state - object so the state can be shared. This sharing is needed to - have one grammar import others and share same error variables - and other state variables. It's a kind of explicit multiple - inheritance via delegation of methods and shared state. - - - - reset the parser's state; subclasses must rewinds the input stream - - - - Match current input symbol against ttype. Attempt - single token insertion or deletion error recovery. If - that fails, throw MismatchedTokenException. - - - - To turn off single token insertion or deletion error - recovery, override recoverFromMismatchedToken() and have it - throw an exception. See TreeParser.recoverFromMismatchedToken(). - This way any error in a rule will cause an exception and - immediate exit from rule. Rule would recover by resynchronizing - to the set of symbols that can follow rule ref. - - - - Match the wildcard: in a symbol - - - Report a recognition problem. - - - This method sets errorRecovery to indicate the parser is recovering - not parsing. Once in recovery mode, no errors are generated. - To get out of recovery mode, the parser must successfully match - a token (after a resync). So it will go: - - 1. error occurs - 2. enter recovery mode, report error - 3. consume until token found in resynch set - 4. try to resume parsing - 5. next match() will reset errorRecovery mode - - If you override, make sure to update syntaxErrors if you care about that. - - - - What error message should be generated for the various exception types? - - - Not very object-oriented code, but I like having all error message - generation within one method rather than spread among all of the - exception classes. This also makes it much easier for the exception - handling because the exception classes do not have to have pointers back - to this object to access utility routines and so on. Also, changing - the message for an exception type would be difficult because you - would have to subclassing exception, but then somehow get ANTLR - to make those kinds of exception objects instead of the default. - This looks weird, but trust me--it makes the most sense in terms - of flexibility. - - For grammar debugging, you will want to override this to add - more information such as the stack frame with - getRuleInvocationStack(e, this.getClass().getName()) and, - for no viable alts, the decision description and state etc... - - Override this to change the message generated for one or more - exception types. - - - - - Get number of recognition errors (lexer, parser, tree parser). Each - recognizer tracks its own number. So parser and lexer each have - separate count. Does not count the spurious errors found between - an error and next valid token match - - - - - - What is the error header, normally line/character position information? - - - - How should a token be displayed in an error message? The default - is to display just the text, but during development you might - want to have a lot of information spit out. Override in that case - to use t.ToString() (which, for CommonToken, dumps everything about - the token). This is better than forcing you to override a method in - your token objects because you don't have to go modify your lexer - so that it creates a new Java type. - - - - Override this method to change where error messages go - - - - Recover from an error found on the input stream. This is - for NoViableAlt and mismatched symbol exceptions. If you enable - single token insertion and deletion, this will usually not - handle mismatched symbol exceptions but there could be a mismatched - token that the match() routine could not recover from. - - - - - A hook to listen in on the token consumption during error recovery. - The DebugParser subclasses this to fire events to the listenter. - - - - - Compute the context-sensitive FOLLOW set for current rule. - This is set of token types that can follow a specific rule - reference given a specific call chain. You get the set of - viable tokens that can possibly come next (lookahead depth 1) - given the current call chain. Contrast this with the - definition of plain FOLLOW for rule r: - - - FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)} - - where x in T* and alpha, beta in V*; T is set of terminals and - V is the set of terminals and nonterminals. In other words, - FOLLOW(r) is the set of all tokens that can possibly follow - references to r in *any* sentential form (context). At - runtime, however, we know precisely which context applies as - we have the call chain. We may compute the exact (rather - than covering superset) set of following tokens. - - For example, consider grammar: - - stat : ID '=' expr ';' // FOLLOW(stat)=={EOF} - | "return" expr '.' - ; - expr : atom ('+' atom)* ; // FOLLOW(expr)=={';','.',')'} - atom : INT // FOLLOW(atom)=={'+',')',';','.'} - | '(' expr ')' - ; - - The FOLLOW sets are all inclusive whereas context-sensitive - FOLLOW sets are precisely what could follow a rule reference. - For input input "i=(3);", here is the derivation: - - stat => ID '=' expr ';' - => ID '=' atom ('+' atom)* ';' - => ID '=' '(' expr ')' ('+' atom)* ';' - => ID '=' '(' atom ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ';' - - At the "3" token, you'd have a call chain of - - stat -> expr -> atom -> expr -> atom - - What can follow that specific nested ref to atom? Exactly ')' - as you can see by looking at the derivation of this specific - input. Contrast this with the FOLLOW(atom)={'+',')',';','.'}. - - You want the exact viable token set when recovering from a - token mismatch. Upon token mismatch, if LA(1) is member of - the viable next token set, then you know there is most likely - a missing token in the input stream. "Insert" one by just not - throwing an exception. - - - Attempt to recover from a single missing or extra token. - - EXTRA TOKEN - - LA(1) is not what we are looking for. If LA(2) has the right token, - however, then assume LA(1) is some extra spurious token. Delete it - and LA(2) as if we were doing a normal match(), which advances the - input. - - MISSING TOKEN - - If current token is consistent with what could come after - ttype then it is ok to "insert" the missing token, else throw - exception For example, Input "i=(3;" is clearly missing the - ')'. When the parser returns from the nested call to expr, it - will have call chain: - - stat -> expr -> atom - - and it will be trying to match the ')' at this point in the - derivation: - - => ID '=' '(' INT ')' ('+' atom)* ';' - ^ - match() will see that ';' doesn't match ')' and report a - mismatched token error. To recover, it sees that LA(1)==';' - is in the set of tokens that can follow the ')' token - reference in rule atom. It can assume that you forgot the ')'. - - - Not currently used - - - - Match needs to return the current input symbol, which gets put - into the label for the associated token ref; e.g., x=ID. Token - and tree parsers need to return different objects. Rather than test - for input stream type or change the IntStream interface, I use - a simple method to ask the recognizer to tell me what the current - input symbol is. - - - This is ignored for lexers. - - - Conjure up a missing token during error recovery. - - - The recognizer attempts to recover from single missing - symbols. But, actions might refer to that missing symbol. - For example, x=ID {f($x);}. The action clearly assumes - that there has been an identifier matched previously and that - $x points at that token. If that token is missing, but - the next token in the stream is what we want we assume that - this token is missing and we keep going. Because we - have to return some token to replace the missing token, - we have to conjure one up. This method gives the user control - over the tokens returned for missing tokens. Mostly, - you will want to create something special for identifier - tokens. For literals such as '{' and ',', the default - action in the parser or tree parser works. It simply creates - a CommonToken of the appropriate type. The text will be the token. - If you change what tokens must be created by the lexer, - override this method to create the appropriate tokens. - - - - Consume tokens until one matches the given token set - - - Push a rule's follow set using our own hardcoded stack - - - Return whether or not a backtracking attempt failed. - - - - Used to print out token names like ID during debugging and - error reporting. The generated parsers implement a method - that overrides this to point to their String[] tokenNames. - - - - - For debugging and other purposes, might want the grammar name. - Have ANTLR generate an implementation for this method. - - - - - A convenience method for use most often with template rewrites. - Convert a list of to a list of . - - - - - Given a rule number and a start token index number, return - MEMO_RULE_UNKNOWN if the rule has not parsed input starting from - start index. If this rule has parsed input starting from the - start index before, then return where the rule stopped parsing. - It returns the index of the last token matched by the rule. - - - - For now we use a hashtable and just the slow Object-based one. - Later, we can make a special one for ints and also one that - tosses out data after we commit past input position i. - - - - - Has this rule already parsed input at the current index in the - input stream? Return the stop token index or MEMO_RULE_UNKNOWN. - If we attempted but failed to parse properly before, return - MEMO_RULE_FAILED. - - - - This method has a side-effect: if we have seen this input for - this rule and successfully parsed before, then seek ahead to - 1 past the stop token matched for this rule last time. - - - - - Record whether or not this rule parsed the input at this position - successfully. Use a standard java hashtable for now. - - - - return how many rule/input-index pairs there are in total. - TODO: this includes synpreds. :( - - - - A stripped-down version of org.antlr.misc.BitSet that is just - good enough to handle runtime requirements such as FOLLOW sets - for automatic error recovery. - - - - - We will often need to do a mod operator (i mod nbits). Its - turns out that, for powers of two, this mod operation is - same as (i & (nbits-1)). Since mod is slow, we use a - precomputed mod mask to do the mod instead. - - - - The actual data bits - - - Construct a bitset of size one word (64 bits) - - - Construction from a static array of longs - - - Construction from a list of integers - - - Construct a bitset given the size - The size of the bitset in bits - - - return this | a in a new set - - - or this element into this set (grow as necessary to accommodate) - - - Grows the set to a larger number of bits. - element that must fit in set - - - Sets the size of a set. - how many words the new set should be - - - return how much space is being used by the bits array not how many actually have member bits on. - - - Is this contained within a? - - - Buffer all input tokens but do on-demand fetching of new tokens from - lexer. Useful when the parser or lexer has to set context/mode info before - proper lexing of future tokens. The ST template parser needs this, - for example, because it has to constantly flip back and forth between - inside/output templates. E.g., <names:{hi, <it>}> has to parse names - as part of an expression but "hi, <it>" as a nested template. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - (UnbufferedTokenStream is the same way.) - - This is not a subclass of UnbufferedTokenStream because I don't want - to confuse small moving window of tokens it uses for the full buffer. - - - Record every single token pulled from the source so we can reproduce - chunks of it later. The buffer in LookaheadStream overlaps sometimes - as its moving window moves through the input. This list captures - everything so we can access complete input text. - - - Track the last mark() call result value for use in rewind(). - - - The index into the tokens list of the current token (next token - to consume). tokens[p] should be LT(1). p=-1 indicates need - to initialize with first token. The ctor doesn't get a token. - First call to LT(1) or whatever gets the first token and sets p=0; - - - - How deep have we gone? - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - Walk past any token not on the channel the parser is listening to. - - - Make sure index i in tokens has a token. - - - add n elements to buffer - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - When walking ahead with cyclic DFA or for syntactic predicates, - we need to record the state of the input stream (char index, - line, etc...) so that we can rewind the state after scanning ahead. - - - This is the complete state of a stream. - - - Index into the char stream of next lookahead char - - - What line number is the scanner at before processing buffer[p]? - - - What char position 0..n-1 in line is scanner before processing buffer[p]? - - - - A Token object like we'd use in ANTLR 2.x; has an actual string created - and associated with this object. These objects are needed for imaginary - tree nodes that have payload objects. We need to create a Token object - that has a string; the tree node will point at this token. CommonToken - has indexes into a char stream and hence cannot be used to introduce - new strings. - - - - What token number is this from 0..n-1 tokens - - - - We need to be able to change the text once in a while. If - this is non-null, then getText should return this. Note that - start/stop are not affected by changing this. - - - - What token number is this from 0..n-1 tokens; < 0 implies invalid index - - - The char position into the input buffer where this token starts - - - The char position into the input buffer where this token stops - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - Reset this token stream by setting its token source. - - - Always leave p on an on-channel token. - - - Given a starting index, return the index of the first on-channel - token. - - - All debugging events that a recognizer can trigger. - - - I did not create a separate AST debugging interface as it would create - lots of extra classes and DebugParser has a dbg var defined, which makes - it hard to change to ASTDebugEventListener. I looked hard at this issue - and it is easier to understand as one monolithic event interface for all - possible events. Hopefully, adding ST debugging stuff won't be bad. Leave - for future. 4/26/2006. - - - - - The parser has just entered a rule. No decision has been made about - which alt is predicted. This is fired AFTER init actions have been - executed. Attributes are defined and available etc... - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - - Because rules can have lots of alternatives, it is very useful to - know which alt you are entering. This is 1..n for n alts. - - - - - This is the last thing executed before leaving a rule. It is - executed even if an exception is thrown. This is triggered after - error reporting and recovery have occurred (unless the exception is - not caught in this rule). This implies an "exitAlt" event. - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - Track entry into any (...) subrule other EBNF construct - - - - Every decision, fixed k or arbitrary, has an enter/exit event - so that a GUI can easily track what LT/consume events are - associated with prediction. You will see a single enter/exit - subrule but multiple enter/exit decision events, one for each - loop iteration. - - - - - An input token was consumed; matched by any kind of element. - Trigger after the token was matched by things like match(), matchAny(). - - - - - An off-channel input token was consumed. - Trigger after the token was matched by things like match(), matchAny(). - (unless of course the hidden token is first stuff in the input stream). - - - - - Somebody (anybody) looked ahead. Note that this actually gets - triggered by both LA and LT calls. The debugger will want to know - which Token object was examined. Like consumeToken, this indicates - what token was seen at that depth. A remote debugger cannot look - ahead into a file it doesn't have so LT events must pass the token - even if the info is redundant. - - - - - The parser is going to look arbitrarily ahead; mark this location, - the token stream's marker is sent in case you need it. - - - - - After an arbitrairly long lookahead as with a cyclic DFA (or with - any backtrack), this informs the debugger that stream should be - rewound to the position associated with marker. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. - - - - - To watch a parser move through the grammar, the parser needs to - inform the debugger what line/charPos it is passing in the grammar. - For now, this does not know how to switch from one grammar to the - other and back for island grammars etc... - - - - This should also allow breakpoints because the debugger can stop - the parser whenever it hits this line/pos. - - - - - A recognition exception occurred such as NoViableAltException. I made - this a generic event so that I can alter the exception hierachy later - without having to alter all the debug objects. - - - - Upon error, the stack of enter rule/subrule must be properly unwound. - If no viable alt occurs it is within an enter/exit decision, which - also must be rewound. Even the rewind for each mark must be unwount. - In the Java target this is pretty easy using try/finally, if a bit - ugly in the generated code. The rewind is generated in DFA.predict() - actually so no code needs to be generated for that. For languages - w/o this "finally" feature (C++?), the target implementor will have - to build an event stack or something. - - Across a socket for remote debugging, only the RecognitionException - data fields are transmitted. The token object or whatever that - caused the problem was the last object referenced by LT. The - immediately preceding LT event should hold the unexpected Token or - char. - - Here is a sample event trace for grammar: - - b : C ({;}A|B) // {;} is there to prevent A|B becoming a set - | D - ; - - The sequence for this rule (with no viable alt in the subrule) for - input 'c c' (there are 3 tokens) is: - - commence - LT(1) - enterRule b - location 7 1 - enter decision 3 - LT(1) - exit decision 3 - enterAlt1 - location 7 5 - LT(1) - consumeToken [c/<4>,1:0] - location 7 7 - enterSubRule 2 - enter decision 2 - LT(1) - LT(1) - recognitionException NoViableAltException 2 1 2 - exit decision 2 - exitSubRule 2 - beginResync - LT(1) - consumeToken [c/<4>,1:1] - LT(1) - endResync - LT(-1) - exitRule b - terminate - - - - - Indicates the recognizer is about to consume tokens to resynchronize - the parser. Any consume events from here until the recovered event - are not part of the parse--they are dead tokens. - - - - - Indicates that the recognizer has finished consuming tokens in order - to resychronize. There may be multiple beginResync/endResync pairs - before the recognizer comes out of errorRecovery mode (in which - multiple errors are suppressed). This will be useful - in a gui where you want to probably grey out tokens that are consumed - but not matched to anything in grammar. Anything between - a beginResync/endResync pair was tossed out by the parser. - - - - A semantic predicate was evaluate with this result and action text - - - - Announce that parsing has begun. Not technically useful except for - sending events over a socket. A GUI for example will launch a thread - to connect and communicate with a remote parser. The thread will want - to notify the GUI when a connection is made. ANTLR parsers - trigger this upon entry to the first rule (the ruleLevel is used to - figure this out). - - - - - Parsing is over; successfully or not. Mostly useful for telling - remote debugging listeners that it's time to quit. When the rule - invocation level goes to zero at the end of a rule, we are done - parsing. - - - - - Input for a tree parser is an AST, but we know nothing for sure - about a node except its type and text (obtained from the adaptor). - This is the analog of the consumeToken method. Again, the ID is - the hashCode usually of the node so it only works if hashCode is - not implemented. If the type is UP or DOWN, then - the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - - - The tree parser lookedahead. If the type is UP or DOWN, - then the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - A nil was created (even nil nodes have a unique ID... - they are not "null" per se). As of 4/28/2006, this - seems to be uniquely triggered when starting a new subtree - such as when entering a subrule in automatic mode and when - building a tree in rewrite mode. - - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - - Upon syntax error, recognizers bracket the error with an error node - if they are building ASTs. - - - - - - Announce a new node built from token elements such as type etc... - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID, type, text are - set. - - - - Announce a new node built from an existing token. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only node.ID and token.tokenIndex - are set. - - - - Make a node the new root of an existing root. See - - - Note: the newRootID parameter is possibly different - than the TreeAdaptor.becomeRoot() newRoot parameter. - In our case, it will always be the result of calling - TreeAdaptor.becomeRoot() and not root_n or whatever. - - The listener should assume that this event occurs - only when the current subrule (or rule) subtree is - being reset to newRootID. - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Make childID a child of rootID. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Set the token start/stop token index for a subtree root or node. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - A DFA implemented as a set of transition tables. - - - Any state that has a semantic predicate edge is special; those states - are generated with if-then-else structures in a specialStateTransition() - which is generated by cyclicDFA template. - - There are at most 32767 states (16-bit signed short). - Could get away with byte sometimes but would have to generate different - types and the simulation code too. For a point of reference, the Java - lexer's Tokens rule DFA has 326 states roughly. - - - - Which recognizer encloses this DFA? Needed to check backtracking - - - - From the input stream, predict what alternative will succeed - using this DFA (representing the covering regular approximation - to the underlying CFL). Return an alternative number 1..n. Throw - an exception upon error. - - - - A hook for debugging interface - - - - Given a String that has a run-length-encoding of some unsigned shorts - like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid - static short[] which generates so much init code that the class won't - compile. :( - - - - Hideous duplication of code, but I need different typed arrays out :( - - - The recognizer did not match anything for a (..)+ loop. - - - - A semantic predicate failed during validation. Validation of predicates - occurs when normally parsing the alternative just like matching a token. - Disambiguating predicate evaluation occurs when we hoist a predicate into - a prediction decision. - - - - AST rules have trees - - - Has a value potentially if output=AST; - - - AST rules have trees - - - Has a value potentially if output=AST; - - - A source of characters for an ANTLR lexer - - - - For infinite streams, you don't need this; primarily I'm providing - a useful interface for action code. Just make sure actions don't - use this on streams that don't support it. - - - - - Get the ith character of lookahead. This is the same usually as - LA(i). This will be used for labels in the generated - lexer code. I'd prefer to return a char here type-wise, but it's - probably better to be 32-bit clean and be consistent with LA. - - - - ANTLR tracks the line information automatically - Because this stream can rewind, we need to be able to reset the line - - - The index of the character relative to the beginning of the line 0..n-1 - - - - A simple stream of integers used when all I care about is the char - or token type sequence (such as interpretation). - - - - - Get int at current input pointer + i ahead where i=1 is next int. - Negative indexes are allowed. LA(-1) is previous token (token - just matched). LA(-i) where i is before first token should - yield -1, invalid char / EOF. - - - - - Tell the stream to start buffering if it hasn't already. Return - current input position, Index, or some other marker so that - when passed to rewind() you get back to the same spot. - rewind(mark()) should not affect the input cursor. The Lexer - track line/col info as well as input index so its markers are - not pure input indexes. Same for tree node streams. - - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the symbol about to be - read not the most recently read symbol. - - - - - Reset the stream so that next call to index would return marker. - The marker will usually be Index but it doesn't have to be. It's - just a marker to indicate what state the stream was in. This is - essentially calling release() and seek(). If there are markers - created after this marker argument, this routine must unroll them - like a stack. Assume the state the stream was in when this marker - was created. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. It is - like invoking rewind(last marker) but it should not "pop" - the marker off. It's like seek(last marker's input position). - - - - - You may want to commit to a backtrack but don't want to force the - stream to keep bookkeeping objects around for a marker that is - no longer necessary. This will have the same behavior as - rewind() except it releases resources without the backward seek. - This must throw away resources for all markers back to the marker - argument. So if you're nested 5 levels of mark(), and then release(2) - you have to release resources for depths 2..5. - - - - - Set the input cursor to the position indicated by index. This is - normally used to seek ahead in the input stream. No buffering is - required to do this unless you know your stream will use seek to - move backwards such as when backtracking. - - - - This is different from rewind in its multi-directional - requirement and in that its argument is strictly an input cursor (index). - - For char streams, seeking forward must update the stream state such - as line number. For seeking backwards, you will be presumably - backtracking using the mark/rewind mechanism that restores state and - so this method does not need to update state when seeking backwards. - - Currently, this method is only used for efficient backtracking using - memoization, but in the future it may be used for incremental parsing. - - The index is 0..n-1. A seek to position i means that LA(1) will - return the ith symbol. So, seeking to 0 means LA(1) will return the - first element in the stream. - - - - - Only makes sense for streams that buffer everything up probably, but - might be useful to display the entire stream or for testing. This - value includes a single EOF. - - - - - Where are you getting symbols from? Normally, implementations will - pass the buck all the way to the lexer who can ask its input stream - for the file name or whatever. - - - - - Rules can have start/stop info. - - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - - Rules can have start/stop info. - - The element type of the input stream. - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - Get the text of the token - - - The line number on which this token was matched; line=1..n - - - The index of the first character relative to the beginning of the line 0..n-1 - - - - An index from 0..n-1 of the token object in the input stream. - This must be valid in order to use the ANTLRWorks debugger. - - - - - From what character stream was this token created? You don't have to - implement but it's nice to know where a Token comes from if you have - include files etc... on the input. - - - - - A source of tokens must provide a sequence of tokens via nextToken() - and also must reveal it's source of characters; CommonToken's text is - computed from a CharStream; it only store indices into the char stream. - - - - Errors from the lexer are never passed to the parser. Either you want - to keep going or you do not upon token recognition error. If you do not - want to continue lexing then you do not want to continue parsing. Just - throw an exception not under RecognitionException and Java will naturally - toss you all the way out of the recognizers. If you want to continue - lexing then you should not throw an exception to the parser--it has already - requested a token. Keep lexing until you get a valid one. Just report - errors and keep going, looking for a valid token. - - - - - Return a Token object from your input stream (usually a CharStream). - Do not fail/return upon lexing error; keep chewing on the characters - until you get a good one; errors are not passed through to the parser. - - - - - Where are you getting tokens from? normally the implication will simply - ask lexers input stream. - - - - A stream of tokens accessing tokens from a TokenSource - - - Get Token at current input pointer + i ahead where i=1 is next Token. - i<0 indicates tokens in the past. So -1 is previous token and -2 is - two tokens ago. LT(0) is undefined. For i>=n, return Token.EOFToken. - Return null for LT(0) and any index that results in an absolute address - that is negative. - - - - How far ahead has the stream been asked to look? The return - value is a valid index from 0..n-1. - - - - - Get a token at an absolute index i; 0..n-1. This is really only - needed for profiling and debugging and token stream rewriting. - If you don't want to buffer up tokens, then this method makes no - sense for you. Naturally you can't use the rewrite stream feature. - I believe DebugTokenStream can easily be altered to not use - this method, removing the dependency. - - - - - Where is this stream pulling tokens from? This is not the name, but - the object that provides Token objects. - - - - - Return the text of all tokens from start to stop, inclusive. - If the stream does not buffer all the tokens then it can just - return "" or null; Users should not access $ruleLabel.text in - an action of course in that case. - - - - - Because the user is not required to use a token with an index stored - in it, we must provide a means for two token objects themselves to - indicate the start/end location. Most often this will just delegate - to the other toString(int,int). This is also parallel with - the TreeNodeStream.toString(Object,Object). - - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - - Record every single token pulled from the source so we can reproduce - chunks of it later. - - - - Map from token type to channel to override some Tokens' channel numbers - - - Set of token types; discard any tokens with this type - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - By default, track all incoming tokens - - - Track the last mark() call result value for use in rewind(). - - - - The index into the tokens list of the current token (next token - to consume). p==-1 indicates that the tokens list is empty - - - - - How deep have we gone? - - - - Reset this token stream by setting its token source. - - - - Load all tokens from the token source and put in tokens. - This is done upon first LT request because you might want to - set some token type / channel overrides before filling buffer. - - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - - - Walk past any token not on the channel the parser is listening to. - - - - Given a starting index, return the index of the first on-channel token. - - - - A simple filter mechanism whereby you can tell this token stream - to force all tokens of type ttype to be on channel. For example, - when interpreting, we cannot exec actions so we need to tell - the stream to force all WS and NEWLINE to be a different, ignored - channel. - - - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - - Get the ith token from the current position 1..n where k=1 is the - first symbol of lookahead. - - - - Look backwards k tokens on-channel tokens - - - - Return absolute token i; ignore which channel the tokens are on; - that is, count all tokens not just on-channel tokens. - - - - - A lexer is recognizer that draws input symbols from a character stream. - lexer grammars result in a subclass of this object. A Lexer object - uses simplified match() and error recovery mechanisms in the interest - of speed. - - - - Where is the lexer drawing characters from? - - - - Gets or sets the text matched so far for the current token or any text override. - - - Setting this value replaces any previously set value, and overrides the original text. - - - - Return a token from this source; i.e., match a token on the char stream. - - - Returns the EOF token (default), if you need - to return a custom token instead override this method. - - - - Instruct the lexer to skip creating a token for current lexer rule - and look for another token. nextToken() knows to keep looking when - a lexer rule finishes with token set to SKIP_TOKEN. Recall that - if token==null at end of any token rule, it creates one for you - and emits it. - - - - This is the lexer entry point that sets instance var 'token' - - - - Currently does not support multiple emits per nextToken invocation - for efficiency reasons. Subclass and override this method and - nextToken (to push tokens into a list and pull from that list rather - than a single variable as this implementation does). - - - - - The standard method called to automatically emit a token at the - outermost lexical rule. The token object should point into the - char buffer start..stop. If there is a text override in 'text', - use that to set the token's text. Override this method to emit - custom Token objects. - - - - If you are building trees, then you should also override - Parser or TreeParser.getMissingSymbol(). - - - - What is the index of the current character of lookahead? - - - - Lexers can normally match any char in it's vocabulary after matching - a token, so do the easy thing and just kill a character and hope - it all works out. You can instead use the rule invocation stack - to do sophisticated error recovery if you are in a fragment rule. - - - - A queue that can dequeue and get(i) in O(1) and grow arbitrarily large. - A linked list is fast at dequeue but slow at get(i). An array is - the reverse. This is O(1) for both operations. - - List grows until you dequeue last element at end of buffer. Then - it resets to start filling at 0 again. If adds/removes are balanced, the - buffer will not grow too large. - - No iterator stuff as that's not how we'll use it. - - - dynamically-sized buffer of elements - - - index of next element to fill - - - - How deep have we gone? - - - - - Return element {@code i} elements ahead of current element. {@code i==0} - gets current element. This is not an absolute index into {@link #data} - since {@code p} defines the start of the real list. - - - - Get and remove first element in queue - - - Return string of current buffer contents; non-destructive - - - - A lookahead queue that knows how to mark/release locations in the buffer for - backtracking purposes. Any markers force the {@link FastQueue} superclass to - keep all elements until no more markers; then can reset to avoid growing a - huge buffer. - - - - Absolute token index. It's the index of the symbol about to be - read via {@code LT(1)}. Goes from 0 to numtokens. - - - This is the {@code LT(-1)} element for the first element in {@link #data}. - - - Track object returned by nextElement upon end of stream; - Return it later when they ask for LT passed end of input. - - - Track the last mark() call result value for use in rewind(). - - - tracks how deep mark() calls are nested - - - - Implement nextElement to supply a stream of elements to this - lookahead buffer. Return EOF upon end of the stream we're pulling from. - - - - - Get and remove first element in queue; override - {@link FastQueue#remove()}; it's the same, just checks for backtracking. - - - - Make sure we have at least one element to remove, even if EOF - - - - Make sure we have 'need' elements from current position p. Last valid - p index is data.size()-1. p+need-1 is the data index 'need' elements - ahead. If we need 1 element, (p+1-1)==p must be < data.size(). - - - - add n elements to buffer - - - Size of entire stream is unknown; we only know buffer size from FastQueue - - - - Seek to a 0-indexed absolute token index. Normally used to seek backwards - in the buffer. Does not force loading of nodes. - - - To preserve backward compatibility, this method allows seeking past the - end of the currently buffered data. In this case, the input pointer will - be moved but the data will only actually be loaded upon the next call to - {@link #consume} or {@link #LT} for {@code k>0}. - - - - A mismatched char or Token or tree node - - - - We were expecting a token but it's not found. The current token - is actually what we wanted next. Used for tree node errors too. - - - - - A parser for TokenStreams. "parser grammars" result in a subclass - of this. - - - - Gets or sets the token stream; resets the parser upon a set. - - - - Rules that return more than a single value must return an object - containing all the values. Besides the properties defined in - RuleLabelScope.predefinedRulePropertiesScope there may be user-defined - return values. This class simply defines the minimum properties that - are always defined and methods to access the others that might be - available depending on output option such as template and tree. - - - - Note text is not an actual property of the return value, it is computed - from start and stop using the input stream's toString() method. I - could add a ctor to this so that we can pass in and store the input - stream, but I'm not sure we want to do that. It would seem to be undefined - to get the .text property anyway if the rule matches tokens from multiple - input streams. - - I do not use getters for fields of objects that are used simply to - group values such as this aggregate. The getters/setters are there to - satisfy the superclass interface. - - - - The root of the ANTLR exception hierarchy. - - - To avoid English-only error messages and to generally make things - as flexible as possible, these exceptions are not created with strings, - but rather the information necessary to generate an error. Then - the various reporting methods in Parser and Lexer can be overridden - to generate a localized error message. For example, MismatchedToken - exceptions are built with the expected token type. - So, don't expect getMessage() to return anything. - - Note that as of Java 1.4, you can access the stack trace, which means - that you can compute the complete trace of rules from the start symbol. - This gives you considerable context information with which to generate - useful error messages. - - ANTLR generates code that throws exceptions upon recognition error and - also generates code to catch these exceptions in each rule. If you - want to quit upon first error, you can turn off the automatic error - handling mechanism using rulecatch action, but you still need to - override methods mismatch and recoverFromMismatchSet. - - In general, the recognition exceptions can track where in a grammar a - problem occurred and/or what was the expected input. While the parser - knows its state (such as current input symbol and line info) that - state can change before the exception is reported so current token index - is computed and stored at exception time. From this info, you can - perhaps print an entire line of input not just a single token, for example. - Better to just say the recognizer had a problem and then let the parser - figure out a fancy report. - - - - What input stream did the error occur in? - - - - What was the lookahead index when this exception was thrown? - - - - What is index of token/char were we looking at when the error occurred? - - - - The current Token when an error occurred. Since not all streams - can retrieve the ith Token, we have to track the Token object. - For parsers. Even when it's a tree parser, token might be set. - - - - - If this is a tree parser exception, node is set to the node with - the problem. - - - - The current char when an error occurred. For lexers. - - - - Track the line (1-based) at which the error occurred in case this is - generated from a lexer. We need to track this since the - unexpected char doesn't carry the line info. - - - - - The 0-based index into the line where the error occurred. - - - - - If you are parsing a tree node stream, you will encounter som - imaginary nodes w/o line/col info. We now search backwards looking - for most recent token with line/col info, but notify getErrorHeader() - that info is approximate. - - - - Used for remote debugger deserialization - - - Return the token type or char of the unexpected input element - - - - The set of fields needed by an abstract recognizer to recognize input - and recover from errors etc... As a separate state object, it can be - shared among multiple grammars; e.g., when one grammar imports another. - - - - These fields are publically visible but the actual state pointer per - parser is protected. - - - - - Track the set of token types that can follow any rule invocation. - Stack grows upwards. When it hits the max, it grows 2x in size - and keeps going. - - - - - This is true when we see an error and before having successfully - matched a token. Prevents generation of more than one error message - per error. - - - - - The index into the input stream where the last error occurred. - This is used to prevent infinite loops where an error is found - but no token is consumed during recovery...another error is found, - ad naseum. This is a failsafe mechanism to guarantee that at least - one token/tree node is consumed for two errors. - - - - - In lieu of a return value, this indicates that a rule or token - has failed to match. Reset to false upon valid token match. - - - - Did the recognizer encounter a syntax error? Track how many. - - - - If 0, no backtracking is going on. Safe to exec actions etc... - If >0 then it's the level of backtracking. - - - - - An array[size num rules] of dictionaries that tracks - the stop token index for each rule. ruleMemo[ruleIndex] is - the memoization table for ruleIndex. For key ruleStartIndex, you - get back the stop token for associated rule or MEMO_RULE_FAILED. - - - This is only used if rule memoization is on (which it is by default). - - - - The goal of all lexer rules/methods is to create a token object. - This is an instance variable as multiple rules may collaborate to - create a single token. nextToken will return this object after - matching lexer rule(s). If you subclass to allow multiple token - emissions, then set this to the last token to be matched or - something nonnull so that the auto token emit mechanism will not - emit another token. - - - - - What character index in the stream did the current token start at? - Needed, for example, to get the text for current token. Set at - the start of nextToken. - - - - The line on which the first character of the token resides - - - The character position of first character within the line - - - The channel number for the current token - - - The token type for the current token - - - - You can set the text for the current token to override what is in - the input char buffer. Use setText() or can set this instance var. - - - - - All tokens go to the parser (unless skip() is called in that rule) - on a particular "channel". The parser tunes to a particular channel - so that whitespace etc... can go to the parser on a "hidden" channel. - - - - - Anything on different channel than DEFAULT_CHANNEL is not parsed - by parser. - - - - Useful for dumping out the input stream after doing some - augmentation or other manipulations. - - You can insert stuff, replace, and delete chunks. Note that the - operations are done lazily--only if you convert the buffer to a - String. This is very efficient because you are not moving data around - all the time. As the buffer of tokens is converted to strings, the - toString() method(s) check to see if there is an operation at the - current index. If so, the operation is done and then normal String - rendering continues on the buffer. This is like having multiple Turing - machine instruction streams (programs) operating on a single input tape. :) - - Since the operations are done lazily at toString-time, operations do not - screw up the token index values. That is, an insert operation at token - index i does not change the index values for tokens i+1..n-1. - - Because operations never actually alter the buffer, you may always get - the original token stream back without undoing anything. Since - the instructions are queued up, you can easily simulate transactions and - roll back any changes if there is an error just by removing instructions. - For example, - - CharStream input = new ANTLRFileStream("input"); - TLexer lex = new TLexer(input); - TokenRewriteStream tokens = new TokenRewriteStream(lex); - T parser = new T(tokens); - parser.startRule(); - - Then in the rules, you can execute - Token t,u; - ... - input.insertAfter(t, "text to put after t");} - input.insertAfter(u, "text after u");} - System.out.println(tokens.toString()); - - Actually, you have to cast the 'input' to a TokenRewriteStream. :( - - You can also have multiple "instruction streams" and get multiple - rewrites from a single pass over the input. Just name the instruction - streams and use that name again when printing the buffer. This could be - useful for generating a C file and also its header file--all from the - same buffer: - - tokens.insertAfter("pass1", t, "text to put after t");} - tokens.insertAfter("pass2", u, "text after u");} - System.out.println(tokens.toString("pass1")); - System.out.println(tokens.toString("pass2")); - - If you don't use named rewrite streams, a "default" stream is used as - the first example shows. - - - What index into rewrites List are we? - - - Token buffer index. - - - - Execute the rewrite operation by possibly adding to the buffer. - Return the index of the next token to operate on. - - - - - I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp - instructions. - - - - - You may have multiple, named streams of rewrite operations. - I'm calling these things "programs." - Maps String (name) -> rewrite (List) - - - - Map String (program name) -> Integer index - - - - Rollback the instruction stream for a program so that - the indicated instruction (via instructionIndex) is no - longer in the stream. UNTESTED! - - - - Reset the program so that no instructions exist - - - We need to combine operations and report invalid operations (like - overlapping replaces that are not completed nested). Inserts to - same index need to be combined etc... Here are the cases: - - I.i.u I.j.v leave alone, nonoverlapping - I.i.u I.i.v combine: Iivu - - R.i-j.u R.x-y.v | i-j in x-y delete first R - R.i-j.u R.i-j.v delete first R - R.i-j.u R.x-y.v | x-y in i-j ERROR - R.i-j.u R.x-y.v | boundaries overlap ERROR - - Delete special case of replace (text==null): - D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) - - I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before - we're not deleting i) - I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping - R.x-y.v I.i.u | i in x-y ERROR - R.x-y.v I.x.u R.x-y.uv (combine, delete I) - R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping - - I.i.u = insert u before op @ index i - R.x-y.u = replace x-y indexed tokens with u - - First we need to examine replaces. For any replace op: - - 1. wipe out any insertions before op within that range. - 2. Drop any replace op before that is contained completely within - that range. - 3. Throw exception upon boundary overlap with any previous replace. - - Then we can deal with inserts: - - 1. for any inserts to same index, combine even if not adjacent. - 2. for any prior replace with same left boundary, combine this - insert with replace and delete this replace. - 3. throw exception if index in same range as previous replace - - Don't actually delete; make op null in list. Easier to walk list. - Later we can throw as we add to index -> op map. - - Note that I.2 R.2-2 will wipe out I.2 even though, technically, the - inserted stuff would be before the replace range. But, if you - add tokens in front of a method body '{' and then delete the method - body, I think the stuff before the '{' you added should disappear too. - - Return a map from token index to operation. - - - Get all operations before an index of a particular kind - - - - In an action, a lexer rule can set token to this SKIP_TOKEN and ANTLR - will avoid creating a token for this symbol and try to fetch another. - - - - imaginary tree navigation type; traverse "get child" link - - - imaginary tree navigation type; finish with a child list - - - - A generic tree implementation with no payload. You must subclass to - actually have any user data. ANTLR v3 uses a list of children approach - instead of the child-sibling approach in v2. A flat tree (a list) is - an empty node whose children represent the list. An empty, but - non-null node is called "nil". - - - - - Create a new node from an existing node does nothing for BaseTree - as there are no fields other than the children list, which cannot - be copied as the children are not considered part of this node. - - - - - Get the children internal List; note that if you directly mess with - the list, do so at your own risk. - - - - BaseTree doesn't track parent pointers. - - - BaseTree doesn't track child indexes. - - - Add t as child of this node. - - - Warning: if t has no children, but child does - and child isNil then this routine moves children to t via - t.children = child.children; i.e., without copying the array. - - - - Add all elements of kids list as children of this node - - - Insert child t at child position i (0..n-1) by shifting children - i+1..n-1 to the right one position. Set parent / indexes properly - but does NOT collapse nil-rooted t's that come in here like addChild. - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - Override in a subclass to change the impl of children list - - - Set the parent and child index values for all child of t - - - Walk upwards looking for ancestor with this token type. - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - Print out a whole tree not just a node - - - Override to say how a node (not a tree) should look as text - - - A TreeAdaptor that works with any Tree implementation. - - - - System.identityHashCode() is not always unique; we have to - track ourselves. That's ok, it's only for debugging, though it's - expensive: we have to create a hashtable with all tree nodes in it. - - - - - Create tree node that holds the start and stop tokens associated - with an error. - - - - If you specify your own kind of tree nodes, you will likely have to - override this method. CommonTree returns Token.INVALID_TOKEN_TYPE - if no token payload but you might have to set token type for diff - node type. - - You don't have to subclass CommonErrorNode; you will likely need to - subclass your own tree node class to avoid class cast exception. - - - - - This is generic in the sense that it will work with any kind of - tree (not just ITree interface). It invokes the adaptor routines - not the tree node routines to do the construction. - - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - Transform ^(nil x) to x and nil to null - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Duplicate a node. This is part of the factory; - override if you want another kind of node to be built. - - - - I could use reflection to prevent having to override this - but reflection is slow. - - - - - Track start/stop token for subtree root created for a rule. - Only works with Tree nodes. For rules that match nothing, - seems like this will yield start=i and stop=i-1 in a nil node. - Might be useful info so I'll not force to be i..i. - - - - A buffered stream of tree nodes. Nodes can be from a tree of ANY kind. - - This node stream sucks all nodes out of the tree specified in - the constructor during construction and makes pointers into - the tree using an array of Object pointers. The stream necessarily - includes pointers to DOWN and UP and EOF nodes. - - This stream knows how to mark/release for backtracking. - - This stream is most suitable for tree interpreters that need to - jump around a lot or for tree parsers requiring speed (at cost of memory). - There is some duplicated functionality here with UnBufferedTreeNodeStream - but just in bookkeeping, not tree walking etc... - - TARGET DEVELOPERS: - - This is the old CommonTreeNodeStream that buffered up entire node stream. - No need to implement really as new CommonTreeNodeStream is much better - and covers what we need. - - @see CommonTreeNodeStream - - - The complete mapping from stream index to tree node. - This buffer includes pointers to DOWN, UP, and EOF nodes. - It is built upon ctor invocation. The elements are type - Object as we don't what the trees look like. - - Load upon first need of the buffer so we can set token types - of interest for reverseIndexing. Slows us down a wee bit to - do all of the if p==-1 testing everywhere though. - - - Pull nodes from which tree? - - - IF this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - Reuse same DOWN, UP navigation nodes unless this is true - - - The index into the nodes list of the current node (next node - to consume). If -1, nodes array not filled yet. - - - Track the last mark() call result value for use in rewind(). - - - Stack of indexes used for push/pop calls - - - Walk tree with depth-first-search and fill nodes buffer. - Don't do DOWN, UP nodes if its a list (t is isNil). - - - What is the stream index for node? 0..n-1 - Return -1 if node not found. - - - As we flatten the tree, we use UP, DOWN nodes to represent - the tree structure. When debugging we need unique nodes - so instantiate new ones when uniqueNavigationNodes is true. - - - Look backwards k nodes - - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - - Used for testing, just return the token type stream - - - Debugging - - - A node representing erroneous token range in token stream - - - - A tree node that is wrapper for a Token object. After 3.0 release - while building tree rewrite stuff, it became clear that computing - parent and child index is very difficult and cumbersome. Better to - spend the space in every tree node. If you don't want these extra - fields, it's easy to cut them out in your own BaseTree subclass. - - - - A single token is the payload - - - - What token indexes bracket all tokens associated with this node - and below? - - - - Who is the parent node of this node; if null, implies node is root - - - What index is this node in the child list? Range: 0..n-1 - - - - For every node in this subtree, make sure it's start/stop token's - are set. Walk depth first, visit bottom up. Only updates nodes - with at least one token index < 0. - - - - - A TreeAdaptor that works with any Tree implementation. It provides - really just factory methods; all the work is done by BaseTreeAdaptor. - If you would like to have different tokens created than ClassicToken - objects, you need to override this and then set the parser tree adaptor to - use your subclass. - - - - To get your parser to build nodes of a different type, override - create(Token), errorNode(), and to be safe, YourTreeClass.dupNode(). - dupNode is called to duplicate nodes during rewrite operations. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - What is the Token associated with this node? If - you are not using CommonTree, then you must - override this in your own adaptor. - - - - Pull nodes from which tree? - - - If this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - The tree iterator we are using - - - Stack of indexes used for push/pop calls - - - Tree (nil A B C) trees like flat A B C streams - - - Tracks tree depth. Level=0 means we're at root node level. - - - Tracks the last node before the start of {@link #data} which contains - position information to provide information for error reporting. This is - tracked in addition to {@link #prevElement} which may or may not contain - position information. - - @see #hasPositionInformation - @see RecognitionException#extractInformationFromTreeNodeStream - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - Returns an element containing position information. If {@code allowApproximateLocation} is {@code false}, then - this method will return the {@code LT(1)} element if it contains position information, and otherwise return {@code null}. - If {@code allowApproximateLocation} is {@code true}, then this method will return the last known element containing position information. - - @see #hasPositionInformation - - - For debugging; destructive: moves tree iterator to end. - - - A utility class to generate DOT diagrams (graphviz) from - arbitrary trees. You can pass in your own templates and - can pass in any kind of tree or use Tree interface method. - I wanted this separator so that you don't have to include - ST just to use the org.antlr.runtime.tree.* package. - This is a set of non-static methods so you can subclass - to override. For example, here is an invocation: - - CharStream input = new ANTLRInputStream(System.in); - TLexer lex = new TLexer(input); - CommonTokenStream tokens = new CommonTokenStream(lex); - TParser parser = new TParser(tokens); - TParser.e_return r = parser.e(); - Tree t = (Tree)r.tree; - System.out.println(t.toStringTree()); - DOTTreeGenerator gen = new DOTTreeGenerator(); - StringTemplate st = gen.toDOT(t); - System.out.println(st); - - - Track node to number mapping so we can get proper node name back - - - Track node number so we can get unique node names - - - Generate DOT (graphviz) for a whole tree not just a node. - For example, 3+4*5 should generate: - - digraph { - node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier", - width=.4, height=.2]; - edge [arrowsize=.7] - "+"->3 - "+"->"*" - "*"->4 - "*"->5 - } - - Takes a Tree interface object. - - - - @author Sam Harwell - - - Returns an element containing concrete information about the current - position in the stream. - - @param allowApproximateLocation if {@code false}, this method returns - {@code null} if an element containing exact information about the current - position is not available - - - Determines if the specified {@code element} contains concrete position - information. - - @param element the element to check - @return {@code true} if {@code element} contains concrete position - information, otherwise {@code false} - - - - What does a tree look like? ANTLR has a number of support classes - such as CommonTreeNodeStream that work on these kinds of trees. You - don't have to make your trees implement this interface, but if you do, - you'll be able to use more support code. - - - - NOTE: When constructing trees, ANTLR can build any kind of tree; it can - even use Token objects as trees if you add a child list to your tokens. - - This is a tree node without any payload; just navigation and factory stuff. - - - - Is there is a node above with token type ttype? - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - This node is what child index? 0..n-1 - - - Set the parent and child index values for all children - - - - Add t as a child to this node. If t is null, do nothing. If t - is nil, add all children of t to this' children. - - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - - Indicates the node is a nil node but may still have children, meaning - the tree is a flat list. - - - - - What is the smallest token index (indexing from 0) for this node - and its children? - - - - - What is the largest token index (indexing from 0) for this node - and its children? - - - - Return a token type; needed for tree parsing - - - In case we don't have a token payload, what is the line for errors? - - - - How to create and navigate trees. Rather than have a separate factory - and adaptor, I've merged them. Makes sense to encapsulate. - - - - This takes the place of the tree construction code generated in the - generated code in 2.x and the ASTFactory. - - I do not need to know the type of a tree at all so they are all - generic Objects. This may increase the amount of typecasting needed. :( - - - - - Create a tree node from Token object; for CommonTree type trees, - then the token just becomes the payload. This is the most - common create call. - - - - Override if you want another kind of node to be built. - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel]. - - - - This should invoke createToken(Token). - - - - - Same as create(tokenType,fromToken) except set the text too. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel, "IMAG"]. - - - - This should invoke createToken(Token). - - - - - Same as create(fromToken) except set the text too. - This is invoked when the text terminal option is set, as in - IMAG<text='IMAG'>. - - - - This should invoke createToken(Token). - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG["IMAG"]. - - - - This should invoke createToken(int,String). - - - - Duplicate a single tree node. - Override if you want another kind of node to be built. - - - Duplicate tree recursively, using dupNode() for each node - - - - Return a nil node (an empty but non-null node) that can hold - a list of element as the children. If you want a flat tree (a list) - use "t=adaptor.nil(); t.addChild(x); t.addChild(y);" - - - - - Return a tree node representing an error. This node records the - tokens consumed during error recovery. The start token indicates the - input symbol at which the error was detected. The stop token indicates - the last symbol consumed during recovery. - - - - You must specify the input stream so that the erroneous text can - be packaged up in the error node. The exception could be useful - to some applications; default implementation stores ptr to it in - the CommonErrorNode. - - This only makes sense during token parsing, not tree parsing. - Tree parsing should happen only when parsing and tree construction - succeed. - - - - Is tree considered a nil node used to make lists of child nodes? - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. Do nothing if t or child is null. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - - Given the root of the subtree created for this rule, post process - it to do any simplifications or whatever you want. A required - behavior is to convert ^(nil singleSubtree) to singleSubtree - as the setting of start/stop indexes relies on a single non-nil root - for non-flat trees. - - - - Flat trees such as for lists like "idlist : ID+ ;" are left alone - unless there is only one ID. For a list, the start/stop indexes - are set in the nil node. - - This method is executed after all rule tree construction and right - before setTokenBoundaries(). - - - - For identifying trees. - - - How to identify nodes so we can say "add node to a prior node"? - Even becomeRoot is an issue. Use System.identityHashCode(node) - usually. - - - - - Create a node for newRoot make it the root of oldRoot. - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - Return node created for newRoot. - - - - Be advised: when debugging ASTs, the DebugTreeAdaptor manually - calls create(Token child) and then plain becomeRoot(node, node) - because it needs to trap calls to create, but it can't since it delegates - to not inherits from the TreeAdaptor. - - - - For tree parsing, I need to know the token type of a node - - - Node constructors can set the type of a node - - - Node constructors can set the text of a node - - - - Return the token object from which this node was created. - Currently used only for printing an error message. - The error display routine in BaseRecognizer needs to - display where the input the error occurred. If your - tree of limitation does not store information that can - lead you to the token, you can create a token filled with - the appropriate information and pass that back. See - BaseRecognizer.getErrorMessage(). - - - - - Where are the bounds in the input token stream for this node and - all children? Each rule that creates AST nodes will call this - method right before returning. Flat trees (i.e., lists) will - still usually have a nil root node just to hold the children list. - That node would contain the start/stop indexes then. - - - - Get the token start index for this subtree; return -1 if no such index - - - Get the token stop index for this subtree; return -1 if no such index - - - Get a child 0..n-1 node - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - Remove ith child and shift children down from right. - - - How many children? If 0, then this is a leaf node - - - - Who is the parent node of this node; if null, implies node is root. - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - What index is this node in the child list? Range: 0..n-1 - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - Replace from start to stop child index of parent with t, which might - be a list. Number of children may be different after this call. - - - - If parent is null, don't do anything; must be at root of overall tree. - Can't replace whatever points to the parent externally. Do nothing. - - - - A stream of tree nodes, accessing nodes from a tree of some kind - - - - Get a tree node at an absolute index i; 0..n-1. - If you don't want to buffer up nodes, then this method makes no - sense for you. - - - - - Get tree node at current input pointer + ahead where - ==1 is next node. <0 indicates nodes in the past. So - {@code LT(-1)} is previous node, but implementations are not required to - provide results for < -1. {@code LT(0)} is undefined. For - <=n, return . Return for {@code LT(0)} - and any index that results in an absolute address that is negative. - - - - This is analogous to , but this returns a tree node - instead of a . Makes code generation identical for both - parser and tree grammars. - - - - - Where is this stream pulling nodes from? This is not the name, but - the object that provides node objects. - - - - - If the tree associated with this stream was created from a - {@link TokenStream}, you can specify it here. Used to do rule - {@code $text} attribute in tree parser. Optional unless you use tree - parser rule {@code $text} attribute or {@code output=template} and - {@code rewrite=true} options. - - - - - What adaptor can tell me how to interpret/navigate nodes and - trees. E.g., get text of a node. - - - - - As we flatten the tree, we use {@link Token#UP}, {@link Token#DOWN} nodes - to represent the tree structure. When debugging we need unique nodes so - we have to instantiate new ones. When doing normal tree parsing, it's - slow and a waste of memory to create unique navigation nodes. Default - should be {@code false}. - - - - - Return the text of all nodes from {@code start} to {@code stop}, - inclusive. If the stream does not buffer all the nodes then it can still - walk recursively from start until stop. You can always return - {@code null} or {@code ""} too, but users should not access - {@code $ruleLabel.text} in an action of course in that case. - - - - - Replace children of {@code parent} from index {@code startChildIndex} to - {@code stopChildIndex} with {@code t}, which might be a list. Number of - children may be different after this call. The stream is notified because - it is walking the tree and might need to know you are monkeying with the - underlying tree. Also, it might be able to modify the node stream to - avoid restreaming for future phases. - - - - If {@code parent} is {@code null}, don't do anything; must be at root of - overall tree. Can't replace whatever points to the parent externally. Do - nothing. - - - - - How to execute code for node t when a visitor visits node t. Execute - pre() before visiting children and execute post() after visiting children. - - - - - Execute an action before visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. Children of returned value will be - visited if using TreeVisitor.visit(). - - - - - Execute an action after visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. - - - - - A record of the rules used to match a token sequence. The tokens - end up as the leaves of this tree and rule nodes are the interior nodes. - This really adds no functionality, it is just an alias for CommonTree - that is more meaningful (specific) and holds a String to display for a node. - - - - - Emit a token and all hidden nodes before. EOF node holds all - hidden tokens after last real token. - - - - - Print out the leaves of this tree, which means printing original - input back out. - - - - - Base class for all exceptions thrown during AST rewrite construction. - This signifies a case where the cardinality of two or more elements - in a subrule are different: (ID INT)+ where |ID|!=|INT| - - - - No elements within a (...)+ in a rewrite rule - - - Ref to ID or expr but no tokens in ID stream or subtrees in expr stream - - - - A generic list of elements tracked in an alternative to be used in - a -> rewrite rule. We need to subclass to fill in the next() method, - which returns either an AST node wrapped around a token payload or - an existing subtree. - - - - Once you start next()ing, do not try to add more elements. It will - break the cursor tracking I believe. - - TODO: add mechanism to detect/puke on modification after reading from stream - - - - - - - - Cursor 0..n-1. If singleElement!=null, cursor is 0 until you next(), - which bumps it to 1 meaning no more elements. - - - - Track single elements w/o creating a list. Upon 2nd add, alloc list - - - The list of tokens or subtrees we are tracking - - - Once a node / subtree has been used in a stream, it must be dup'd - from then on. Streams are reset after subrules so that the streams - can be reused in future subrules. So, reset must set a dirty bit. - If dirty, then next() always returns a dup. - - - The element or stream description; usually has name of the token or - rule reference that this list tracks. Can include rulename too, but - the exception would track that info. - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Reset the condition of this stream so that it appears we have - not consumed any of its elements. Elements themselves are untouched. - Once we reset the stream, any future use will need duplicates. Set - the dirty bit. - - - - - Return the next element in the stream. If out of elements, throw - an exception unless size()==1. If size is 1, then return elements[0]. - Return a duplicate node/subtree if stream is out of elements and - size==1. If we've already used the element, dup (dirty bit set). - - - - - Do the work of getting the next element, making sure that it's - a tree node or subtree. Deal with the optimization of single- - element list versus list of size > 1. Throw an exception - if the stream is empty or we're out of elements and size>1. - protected so you can override in a subclass if necessary. - - - - - When constructing trees, sometimes we need to dup a token or AST - subtree. Dup'ing a token means just creating another AST node - around it. For trees, you must call the adaptor.dupTree() unless - the element is for a tree root; then it must be a node dup. - - - - - Ensure stream emits trees; tokens must be converted to AST nodes. - AST nodes can be passed through unmolested. - - - - - Queues up nodes matched on left side of -> in a tree parser. This is - the analog of RewriteRuleTokenStream for normal parsers. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Treat next element as a single node even if it's a subtree. - This is used instead of next() when the result has to be a - tree root node. Also prevents us from duplicating recently-added - children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration - must dup the type node, but ID has been added. - - - - Referencing a rule result twice is ok; dup entire tree as - we can't be adding trees as root; e.g., expr expr. - - Hideous code duplication here with super.next(). Can't think of - a proper way to refactor. This needs to always call dup node - and super.next() doesn't know which to call: dup node or dup tree. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Get next token from stream and make a node for it - - - - Don't convert to a tree unless they explicitly call nextTree. - This way we can do hetero tree nodes in rewrite. - - - - Return a node stream from a doubly-linked tree whose nodes - know what child index they are. No remove() is supported. - - Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure. - - - If we emit UP/DOWN nodes, we need to spit out multiple nodes per - next() call. - - - - A parser for a stream of tree nodes. "tree grammars" result in a subclass - of this. All the error reporting and recovery is shared with Parser via - the BaseRecognizer superclass. - - - - Set the input stream - - - - Match '.' in tree parser has special meaning. Skip node or - entire tree if node has children. If children, scan until - corresponding UP node. - - - - - We have DOWN/UP nodes in the stream that have no line info; override. - plus we want to alter the exception type. Don't try to recover - from tree parser errors inline... - - - - - Prefix error message with the grammar name because message is - always intended for the programmer because the parser built - the input tree not the user. - - - - - Tree parsers parse nodes they usually have a token object as - payload. Set the exception token and do the default behavior. - - - - The tree pattern to lex like "(A B C)" - - - Index into input string - - - Current char - - - How long is the pattern in char? - - - Set when token type is ID or ARG (name mimics Java's StreamTokenizer) - - - Override this if you need transformation tracing to go somewhere - other than stdout or if you're not using ITree-derived trees. - - - - This is identical to the ParserRuleReturnScope except that - the start property is a tree nodes not Token object - when you are parsing trees. - - - - Gets the first node or root node of tree matched for this rule. - - - Do a depth first walk of a tree, applying pre() and post() actions as we go. - - - - Visit every node in tree t and trigger an action for each node - before/after having visited all of its children. Bottom up walk. - Execute both actions even if t has no children. Ignore return - results from transforming children since they will have altered - the child list of this node (their parent). Return result of - applying post action to this node. - - - - - Build and navigate trees with this object. Must know about the names - of tokens so you have to pass in a map or array of token names (from which - this class can build the map). I.e., Token DECL means nothing unless the - class can translate it to a token type. - - - - In order to create nodes and navigate, this class needs a TreeAdaptor. - - This class can build a token type -> node index for repeated use or for - iterating over the various nodes with a particular type. - - This class works in conjunction with the TreeAdaptor rather than moving - all this functionality into the adaptor. An adaptor helps build and - navigate trees using methods. This class helps you do it with string - patterns like "(A B C)". You can create a tree from that pattern or - match subtrees against it. - - - - - When using %label:TOKENNAME in a tree for parse(), we must - track the label. - - - - This adaptor creates TreePattern objects for use during scan() - - - - Compute a Map<String, Integer> that is an inverted index of - tokenNames (which maps int token types to names). - - - - Using the map of token names to token types, return the type. - - - - Walk the entire tree and make a node name to nodes mapping. - For now, use recursion but later nonrecursive version may be - more efficient. Returns Map<Integer, List> where the List is - of your AST node type. The Integer is the token type of the node. - - - - TODO: save this index so that find and visit are faster - - - - Do the work for index - - - Return a List of tree nodes with token type ttype - - - Return a List of subtrees matching pattern. - - - - Visit every ttype node in t, invoking the visitor. This is a quicker - version of the general visit(t, pattern) method. The labels arg - of the visitor action method is never set (it's null) since using - a token type rather than a pattern doesn't let us set a label. - - - - Do the recursive work for visit - - - - For all subtrees that match the pattern, execute the visit action. - The implementation uses the root node of the pattern in combination - with visit(t, ttype, visitor) so nil-rooted patterns are not allowed. - Patterns with wildcard roots are also not allowed. - - - - - Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels - on the various nodes and '.' (dot) as the node/subtree wildcard, - return true if the pattern matches and fill the labels Map with - the labels pointing at the appropriate nodes. Return false if - the pattern is malformed or the tree does not match. - - - - If a node specifies a text arg in pattern, then that must match - for that node in t. - - TODO: what's a better way to indicate bad pattern? Exceptions are a hassle - - - - - Do the work for parse. Check to see if the t2 pattern fits the - structure and token types in t1. Check text if the pattern has - text arguments on nodes. Fill labels map with pointers to nodes - in tree matched against nodes in pattern with labels. - - - - - Create a tree or node from the indicated tree pattern that closely - follows ANTLR tree grammar tree element syntax: - - (root child1 ... child2). - - - - You can also just pass in a node: ID - - Any node can have a text argument: ID[foo] - (notice there are no quotes around foo--it's clear it's a string). - - nil is a special name meaning "give me a nil node". Useful for - making lists: (nil A B C) is a list of A B C. - - - - - Compare t1 and t2; return true if token types/text, structure match exactly. - The trees are examined in their entirety so that (A B) does not match - (A B C) nor (A (B C)). - - - - TODO: allow them to pass in a comparator - TODO: have a version that is nonstatic so it can use instance adaptor - - I cannot rely on the tree node's equals() implementation as I make - no constraints at all on the node types nor interface etc... - - - - - Compare type, structure, and text of two trees, assuming adaptor in - this instance of a TreeWizard. - - - - A token stream that pulls tokens from the code source on-demand and - without tracking a complete buffer of the tokens. This stream buffers - the minimum number of tokens possible. It's the same as - OnDemandTokenStream except that OnDemandTokenStream buffers all tokens. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - - You can only look backwards 1 token: LT(-1). - - Use this when you need to read from a socket or other infinite stream. - - @see BufferedTokenStream - @see CommonTokenStream - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - An extra token while parsing a TokenStream - - - diff --git a/packages/Antlr3.Runtime.3.5.1/lib/portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Antlr3.Runtime.dll b/packages/Antlr3.Runtime.3.5.1/lib/portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Antlr3.Runtime.dll deleted file mode 100644 index 63a4ba847..000000000 Binary files a/packages/Antlr3.Runtime.3.5.1/lib/portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Antlr3.Runtime.dll and /dev/null differ diff --git a/packages/Antlr3.Runtime.3.5.1/lib/portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Antlr3.Runtime.xml b/packages/Antlr3.Runtime.3.5.1/lib/portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Antlr3.Runtime.xml deleted file mode 100644 index 31d731fa3..000000000 --- a/packages/Antlr3.Runtime.3.5.1/lib/portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Antlr3.Runtime.xml +++ /dev/null @@ -1,3220 +0,0 @@ - - - - Antlr3.Runtime - - - - - A kind of ReaderStream that pulls from an InputStream. - Useful for reading from stdin and specifying file encodings etc... - - - - - Vacuum all input from a Reader and then treat it like a StringStream. - Manage the buffer manually to avoid unnecessary data copying. - - - - If you need encoding, use ANTLRInputStream. - - - - - A pretty quick CharStream that pulls all data from an array - directly. Every method call counts in the lexer. Java's - strings aren't very good so I'm avoiding. - - - - The data being scanned - - - How many characters are actually in the buffer - - - 0..n-1 index into string of next char - - - line number 1..n within the input - - - The index of the character relative to the beginning of the line 0..n-1 - - - tracks how deep mark() calls are nested - - - - A list of CharStreamState objects that tracks the stream state - values line, charPositionInLine, and p that can change as you - move through the input stream. Indexed from 1..markDepth. - A null is kept @ index 0. Create upon first call to mark(). - - - - Track the last mark() call result value for use in rewind(). - - - What is name or source of this char stream? - - - Copy data in string to a local char array - - - This is the preferred constructor as no data is copied - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the index of char to - be returned from LA(1). - - - - - Reset the stream so that it's in the same state it was - when the object was created *except* the data array is not - touched. - - - - - consume() ahead until p==index; can't just set p=index as we must - update line and charPositionInLine. - - - - - A generic recognizer that can handle recognizers generated from - lexer, parser, and tree grammars. This is all the parsing - support code essentially; most of it is error recovery stuff and - backtracking. - - - - - State of a lexer, parser, or tree parser are collected into a state - object so the state can be shared. This sharing is needed to - have one grammar import others and share same error variables - and other state variables. It's a kind of explicit multiple - inheritance via delegation of methods and shared state. - - - - reset the parser's state; subclasses must rewinds the input stream - - - - Match current input symbol against ttype. Attempt - single token insertion or deletion error recovery. If - that fails, throw MismatchedTokenException. - - - - To turn off single token insertion or deletion error - recovery, override recoverFromMismatchedToken() and have it - throw an exception. See TreeParser.recoverFromMismatchedToken(). - This way any error in a rule will cause an exception and - immediate exit from rule. Rule would recover by resynchronizing - to the set of symbols that can follow rule ref. - - - - Match the wildcard: in a symbol - - - Report a recognition problem. - - - This method sets errorRecovery to indicate the parser is recovering - not parsing. Once in recovery mode, no errors are generated. - To get out of recovery mode, the parser must successfully match - a token (after a resync). So it will go: - - 1. error occurs - 2. enter recovery mode, report error - 3. consume until token found in resynch set - 4. try to resume parsing - 5. next match() will reset errorRecovery mode - - If you override, make sure to update syntaxErrors if you care about that. - - - - What error message should be generated for the various exception types? - - - Not very object-oriented code, but I like having all error message - generation within one method rather than spread among all of the - exception classes. This also makes it much easier for the exception - handling because the exception classes do not have to have pointers back - to this object to access utility routines and so on. Also, changing - the message for an exception type would be difficult because you - would have to subclassing exception, but then somehow get ANTLR - to make those kinds of exception objects instead of the default. - This looks weird, but trust me--it makes the most sense in terms - of flexibility. - - For grammar debugging, you will want to override this to add - more information such as the stack frame with - getRuleInvocationStack(e, this.getClass().getName()) and, - for no viable alts, the decision description and state etc... - - Override this to change the message generated for one or more - exception types. - - - - - Get number of recognition errors (lexer, parser, tree parser). Each - recognizer tracks its own number. So parser and lexer each have - separate count. Does not count the spurious errors found between - an error and next valid token match - - - - - - What is the error header, normally line/character position information? - - - - How should a token be displayed in an error message? The default - is to display just the text, but during development you might - want to have a lot of information spit out. Override in that case - to use t.ToString() (which, for CommonToken, dumps everything about - the token). This is better than forcing you to override a method in - your token objects because you don't have to go modify your lexer - so that it creates a new Java type. - - - - Override this method to change where error messages go - - - - Recover from an error found on the input stream. This is - for NoViableAlt and mismatched symbol exceptions. If you enable - single token insertion and deletion, this will usually not - handle mismatched symbol exceptions but there could be a mismatched - token that the match() routine could not recover from. - - - - - A hook to listen in on the token consumption during error recovery. - The DebugParser subclasses this to fire events to the listenter. - - - - - Compute the context-sensitive FOLLOW set for current rule. - This is set of token types that can follow a specific rule - reference given a specific call chain. You get the set of - viable tokens that can possibly come next (lookahead depth 1) - given the current call chain. Contrast this with the - definition of plain FOLLOW for rule r: - - - FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)} - - where x in T* and alpha, beta in V*; T is set of terminals and - V is the set of terminals and nonterminals. In other words, - FOLLOW(r) is the set of all tokens that can possibly follow - references to r in *any* sentential form (context). At - runtime, however, we know precisely which context applies as - we have the call chain. We may compute the exact (rather - than covering superset) set of following tokens. - - For example, consider grammar: - - stat : ID '=' expr ';' // FOLLOW(stat)=={EOF} - | "return" expr '.' - ; - expr : atom ('+' atom)* ; // FOLLOW(expr)=={';','.',')'} - atom : INT // FOLLOW(atom)=={'+',')',';','.'} - | '(' expr ')' - ; - - The FOLLOW sets are all inclusive whereas context-sensitive - FOLLOW sets are precisely what could follow a rule reference. - For input input "i=(3);", here is the derivation: - - stat => ID '=' expr ';' - => ID '=' atom ('+' atom)* ';' - => ID '=' '(' expr ')' ('+' atom)* ';' - => ID '=' '(' atom ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ('+' atom)* ';' - => ID '=' '(' INT ')' ';' - - At the "3" token, you'd have a call chain of - - stat -> expr -> atom -> expr -> atom - - What can follow that specific nested ref to atom? Exactly ')' - as you can see by looking at the derivation of this specific - input. Contrast this with the FOLLOW(atom)={'+',')',';','.'}. - - You want the exact viable token set when recovering from a - token mismatch. Upon token mismatch, if LA(1) is member of - the viable next token set, then you know there is most likely - a missing token in the input stream. "Insert" one by just not - throwing an exception. - - - Attempt to recover from a single missing or extra token. - - EXTRA TOKEN - - LA(1) is not what we are looking for. If LA(2) has the right token, - however, then assume LA(1) is some extra spurious token. Delete it - and LA(2) as if we were doing a normal match(), which advances the - input. - - MISSING TOKEN - - If current token is consistent with what could come after - ttype then it is ok to "insert" the missing token, else throw - exception For example, Input "i=(3;" is clearly missing the - ')'. When the parser returns from the nested call to expr, it - will have call chain: - - stat -> expr -> atom - - and it will be trying to match the ')' at this point in the - derivation: - - => ID '=' '(' INT ')' ('+' atom)* ';' - ^ - match() will see that ';' doesn't match ')' and report a - mismatched token error. To recover, it sees that LA(1)==';' - is in the set of tokens that can follow the ')' token - reference in rule atom. It can assume that you forgot the ')'. - - - Not currently used - - - - Match needs to return the current input symbol, which gets put - into the label for the associated token ref; e.g., x=ID. Token - and tree parsers need to return different objects. Rather than test - for input stream type or change the IntStream interface, I use - a simple method to ask the recognizer to tell me what the current - input symbol is. - - - This is ignored for lexers. - - - Conjure up a missing token during error recovery. - - - The recognizer attempts to recover from single missing - symbols. But, actions might refer to that missing symbol. - For example, x=ID {f($x);}. The action clearly assumes - that there has been an identifier matched previously and that - $x points at that token. If that token is missing, but - the next token in the stream is what we want we assume that - this token is missing and we keep going. Because we - have to return some token to replace the missing token, - we have to conjure one up. This method gives the user control - over the tokens returned for missing tokens. Mostly, - you will want to create something special for identifier - tokens. For literals such as '{' and ',', the default - action in the parser or tree parser works. It simply creates - a CommonToken of the appropriate type. The text will be the token. - If you change what tokens must be created by the lexer, - override this method to create the appropriate tokens. - - - - Consume tokens until one matches the given token set - - - Push a rule's follow set using our own hardcoded stack - - - Return whether or not a backtracking attempt failed. - - - - Used to print out token names like ID during debugging and - error reporting. The generated parsers implement a method - that overrides this to point to their String[] tokenNames. - - - - - For debugging and other purposes, might want the grammar name. - Have ANTLR generate an implementation for this method. - - - - - A convenience method for use most often with template rewrites. - Convert a list of to a list of . - - - - - Given a rule number and a start token index number, return - MEMO_RULE_UNKNOWN if the rule has not parsed input starting from - start index. If this rule has parsed input starting from the - start index before, then return where the rule stopped parsing. - It returns the index of the last token matched by the rule. - - - - For now we use a hashtable and just the slow Object-based one. - Later, we can make a special one for ints and also one that - tosses out data after we commit past input position i. - - - - - Has this rule already parsed input at the current index in the - input stream? Return the stop token index or MEMO_RULE_UNKNOWN. - If we attempted but failed to parse properly before, return - MEMO_RULE_FAILED. - - - - This method has a side-effect: if we have seen this input for - this rule and successfully parsed before, then seek ahead to - 1 past the stop token matched for this rule last time. - - - - - Record whether or not this rule parsed the input at this position - successfully. Use a standard java hashtable for now. - - - - return how many rule/input-index pairs there are in total. - TODO: this includes synpreds. :( - - - - A stripped-down version of org.antlr.misc.BitSet that is just - good enough to handle runtime requirements such as FOLLOW sets - for automatic error recovery. - - - - - We will often need to do a mod operator (i mod nbits). Its - turns out that, for powers of two, this mod operation is - same as (i & (nbits-1)). Since mod is slow, we use a - precomputed mod mask to do the mod instead. - - - - The actual data bits - - - Construct a bitset of size one word (64 bits) - - - Construction from a static array of longs - - - Construction from a list of integers - - - Construct a bitset given the size - The size of the bitset in bits - - - return this | a in a new set - - - or this element into this set (grow as necessary to accommodate) - - - Grows the set to a larger number of bits. - element that must fit in set - - - Sets the size of a set. - how many words the new set should be - - - return how much space is being used by the bits array not how many actually have member bits on. - - - Is this contained within a? - - - Buffer all input tokens but do on-demand fetching of new tokens from - lexer. Useful when the parser or lexer has to set context/mode info before - proper lexing of future tokens. The ST template parser needs this, - for example, because it has to constantly flip back and forth between - inside/output templates. E.g., <names:{hi, <it>}> has to parse names - as part of an expression but "hi, <it>" as a nested template. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - (UnbufferedTokenStream is the same way.) - - This is not a subclass of UnbufferedTokenStream because I don't want - to confuse small moving window of tokens it uses for the full buffer. - - - Record every single token pulled from the source so we can reproduce - chunks of it later. The buffer in LookaheadStream overlaps sometimes - as its moving window moves through the input. This list captures - everything so we can access complete input text. - - - Track the last mark() call result value for use in rewind(). - - - The index into the tokens list of the current token (next token - to consume). tokens[p] should be LT(1). p=-1 indicates need - to initialize with first token. The ctor doesn't get a token. - First call to LT(1) or whatever gets the first token and sets p=0; - - - - How deep have we gone? - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - Walk past any token not on the channel the parser is listening to. - - - Make sure index i in tokens has a token. - - - add n elements to buffer - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - When walking ahead with cyclic DFA or for syntactic predicates, - we need to record the state of the input stream (char index, - line, etc...) so that we can rewind the state after scanning ahead. - - - This is the complete state of a stream. - - - Index into the char stream of next lookahead char - - - What line number is the scanner at before processing buffer[p]? - - - What char position 0..n-1 in line is scanner before processing buffer[p]? - - - - A Token object like we'd use in ANTLR 2.x; has an actual string created - and associated with this object. These objects are needed for imaginary - tree nodes that have payload objects. We need to create a Token object - that has a string; the tree node will point at this token. CommonToken - has indexes into a char stream and hence cannot be used to introduce - new strings. - - - - What token number is this from 0..n-1 tokens - - - - We need to be able to change the text once in a while. If - this is non-null, then getText should return this. Note that - start/stop are not affected by changing this. - - - - What token number is this from 0..n-1 tokens; < 0 implies invalid index - - - The char position into the input buffer where this token starts - - - The char position into the input buffer where this token stops - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - Reset this token stream by setting its token source. - - - Always leave p on an on-channel token. - - - Given a starting index, return the index of the first on-channel - token. - - - All debugging events that a recognizer can trigger. - - - I did not create a separate AST debugging interface as it would create - lots of extra classes and DebugParser has a dbg var defined, which makes - it hard to change to ASTDebugEventListener. I looked hard at this issue - and it is easier to understand as one monolithic event interface for all - possible events. Hopefully, adding ST debugging stuff won't be bad. Leave - for future. 4/26/2006. - - - - - The parser has just entered a rule. No decision has been made about - which alt is predicted. This is fired AFTER init actions have been - executed. Attributes are defined and available etc... - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - - Because rules can have lots of alternatives, it is very useful to - know which alt you are entering. This is 1..n for n alts. - - - - - This is the last thing executed before leaving a rule. It is - executed even if an exception is thrown. This is triggered after - error reporting and recovery have occurred (unless the exception is - not caught in this rule). This implies an "exitAlt" event. - The grammarFileName allows composite grammars to jump around among - multiple grammar files. - - - - Track entry into any (...) subrule other EBNF construct - - - - Every decision, fixed k or arbitrary, has an enter/exit event - so that a GUI can easily track what LT/consume events are - associated with prediction. You will see a single enter/exit - subrule but multiple enter/exit decision events, one for each - loop iteration. - - - - - An input token was consumed; matched by any kind of element. - Trigger after the token was matched by things like match(), matchAny(). - - - - - An off-channel input token was consumed. - Trigger after the token was matched by things like match(), matchAny(). - (unless of course the hidden token is first stuff in the input stream). - - - - - Somebody (anybody) looked ahead. Note that this actually gets - triggered by both LA and LT calls. The debugger will want to know - which Token object was examined. Like consumeToken, this indicates - what token was seen at that depth. A remote debugger cannot look - ahead into a file it doesn't have so LT events must pass the token - even if the info is redundant. - - - - - The parser is going to look arbitrarily ahead; mark this location, - the token stream's marker is sent in case you need it. - - - - - After an arbitrairly long lookahead as with a cyclic DFA (or with - any backtrack), this informs the debugger that stream should be - rewound to the position associated with marker. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. - - - - - To watch a parser move through the grammar, the parser needs to - inform the debugger what line/charPos it is passing in the grammar. - For now, this does not know how to switch from one grammar to the - other and back for island grammars etc... - - - - This should also allow breakpoints because the debugger can stop - the parser whenever it hits this line/pos. - - - - - A recognition exception occurred such as NoViableAltException. I made - this a generic event so that I can alter the exception hierachy later - without having to alter all the debug objects. - - - - Upon error, the stack of enter rule/subrule must be properly unwound. - If no viable alt occurs it is within an enter/exit decision, which - also must be rewound. Even the rewind for each mark must be unwount. - In the Java target this is pretty easy using try/finally, if a bit - ugly in the generated code. The rewind is generated in DFA.predict() - actually so no code needs to be generated for that. For languages - w/o this "finally" feature (C++?), the target implementor will have - to build an event stack or something. - - Across a socket for remote debugging, only the RecognitionException - data fields are transmitted. The token object or whatever that - caused the problem was the last object referenced by LT. The - immediately preceding LT event should hold the unexpected Token or - char. - - Here is a sample event trace for grammar: - - b : C ({;}A|B) // {;} is there to prevent A|B becoming a set - | D - ; - - The sequence for this rule (with no viable alt in the subrule) for - input 'c c' (there are 3 tokens) is: - - commence - LT(1) - enterRule b - location 7 1 - enter decision 3 - LT(1) - exit decision 3 - enterAlt1 - location 7 5 - LT(1) - consumeToken [c/<4>,1:0] - location 7 7 - enterSubRule 2 - enter decision 2 - LT(1) - LT(1) - recognitionException NoViableAltException 2 1 2 - exit decision 2 - exitSubRule 2 - beginResync - LT(1) - consumeToken [c/<4>,1:1] - LT(1) - endResync - LT(-1) - exitRule b - terminate - - - - - Indicates the recognizer is about to consume tokens to resynchronize - the parser. Any consume events from here until the recovered event - are not part of the parse--they are dead tokens. - - - - - Indicates that the recognizer has finished consuming tokens in order - to resychronize. There may be multiple beginResync/endResync pairs - before the recognizer comes out of errorRecovery mode (in which - multiple errors are suppressed). This will be useful - in a gui where you want to probably grey out tokens that are consumed - but not matched to anything in grammar. Anything between - a beginResync/endResync pair was tossed out by the parser. - - - - A semantic predicate was evaluate with this result and action text - - - - Announce that parsing has begun. Not technically useful except for - sending events over a socket. A GUI for example will launch a thread - to connect and communicate with a remote parser. The thread will want - to notify the GUI when a connection is made. ANTLR parsers - trigger this upon entry to the first rule (the ruleLevel is used to - figure this out). - - - - - Parsing is over; successfully or not. Mostly useful for telling - remote debugging listeners that it's time to quit. When the rule - invocation level goes to zero at the end of a rule, we are done - parsing. - - - - - Input for a tree parser is an AST, but we know nothing for sure - about a node except its type and text (obtained from the adaptor). - This is the analog of the consumeToken method. Again, the ID is - the hashCode usually of the node so it only works if hashCode is - not implemented. If the type is UP or DOWN, then - the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - - - The tree parser lookedahead. If the type is UP or DOWN, - then the ID is not really meaningful as it's fixed--there is - just one UP node and one DOWN navigation node. - - - - - A nil was created (even nil nodes have a unique ID... - they are not "null" per se). As of 4/28/2006, this - seems to be uniquely triggered when starting a new subtree - such as when entering a subrule in automatic mode and when - building a tree in rewrite mode. - - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - - Upon syntax error, recognizers bracket the error with an error node - if they are building ASTs. - - - - - - Announce a new node built from token elements such as type etc... - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID, type, text are - set. - - - - Announce a new node built from an existing token. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only node.ID and token.tokenIndex - are set. - - - - Make a node the new root of an existing root. See - - - Note: the newRootID parameter is possibly different - than the TreeAdaptor.becomeRoot() newRoot parameter. - In our case, it will always be the result of calling - TreeAdaptor.becomeRoot() and not root_n or whatever. - - The listener should assume that this event occurs - only when the current subrule (or rule) subtree is - being reset to newRootID. - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Make childID a child of rootID. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only IDs are set. - - - - - - Set the token start/stop token index for a subtree root or node. - - - If you are receiving this event over a socket via - RemoteDebugEventSocketListener then only t.ID is set. - - - - A DFA implemented as a set of transition tables. - - - Any state that has a semantic predicate edge is special; those states - are generated with if-then-else structures in a specialStateTransition() - which is generated by cyclicDFA template. - - There are at most 32767 states (16-bit signed short). - Could get away with byte sometimes but would have to generate different - types and the simulation code too. For a point of reference, the Java - lexer's Tokens rule DFA has 326 states roughly. - - - - Which recognizer encloses this DFA? Needed to check backtracking - - - - From the input stream, predict what alternative will succeed - using this DFA (representing the covering regular approximation - to the underlying CFL). Return an alternative number 1..n. Throw - an exception upon error. - - - - A hook for debugging interface - - - - Given a String that has a run-length-encoding of some unsigned shorts - like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid - static short[] which generates so much init code that the class won't - compile. :( - - - - Hideous duplication of code, but I need different typed arrays out :( - - - The recognizer did not match anything for a (..)+ loop. - - - - A semantic predicate failed during validation. Validation of predicates - occurs when normally parsing the alternative just like matching a token. - Disambiguating predicate evaluation occurs when we hoist a predicate into - a prediction decision. - - - - AST rules have trees - - - Has a value potentially if output=AST; - - - AST rules have trees - - - Has a value potentially if output=AST; - - - A source of characters for an ANTLR lexer - - - - For infinite streams, you don't need this; primarily I'm providing - a useful interface for action code. Just make sure actions don't - use this on streams that don't support it. - - - - - Get the ith character of lookahead. This is the same usually as - LA(i). This will be used for labels in the generated - lexer code. I'd prefer to return a char here type-wise, but it's - probably better to be 32-bit clean and be consistent with LA. - - - - ANTLR tracks the line information automatically - Because this stream can rewind, we need to be able to reset the line - - - The index of the character relative to the beginning of the line 0..n-1 - - - - A simple stream of integers used when all I care about is the char - or token type sequence (such as interpretation). - - - - - Get int at current input pointer + i ahead where i=1 is next int. - Negative indexes are allowed. LA(-1) is previous token (token - just matched). LA(-i) where i is before first token should - yield -1, invalid char / EOF. - - - - - Tell the stream to start buffering if it hasn't already. Return - current input position, Index, or some other marker so that - when passed to rewind() you get back to the same spot. - rewind(mark()) should not affect the input cursor. The Lexer - track line/col info as well as input index so its markers are - not pure input indexes. Same for tree node streams. - - - - - Return the current input symbol index 0..n where n indicates the - last symbol has been read. The index is the symbol about to be - read not the most recently read symbol. - - - - - Reset the stream so that next call to index would return marker. - The marker will usually be Index but it doesn't have to be. It's - just a marker to indicate what state the stream was in. This is - essentially calling release() and seek(). If there are markers - created after this marker argument, this routine must unroll them - like a stack. Assume the state the stream was in when this marker - was created. - - - - - Rewind to the input position of the last marker. - Used currently only after a cyclic DFA and just - before starting a sem/syn predicate to get the - input position back to the start of the decision. - Do not "pop" the marker off the state. mark(i) - and rewind(i) should balance still. It is - like invoking rewind(last marker) but it should not "pop" - the marker off. It's like seek(last marker's input position). - - - - - You may want to commit to a backtrack but don't want to force the - stream to keep bookkeeping objects around for a marker that is - no longer necessary. This will have the same behavior as - rewind() except it releases resources without the backward seek. - This must throw away resources for all markers back to the marker - argument. So if you're nested 5 levels of mark(), and then release(2) - you have to release resources for depths 2..5. - - - - - Set the input cursor to the position indicated by index. This is - normally used to seek ahead in the input stream. No buffering is - required to do this unless you know your stream will use seek to - move backwards such as when backtracking. - - - - This is different from rewind in its multi-directional - requirement and in that its argument is strictly an input cursor (index). - - For char streams, seeking forward must update the stream state such - as line number. For seeking backwards, you will be presumably - backtracking using the mark/rewind mechanism that restores state and - so this method does not need to update state when seeking backwards. - - Currently, this method is only used for efficient backtracking using - memoization, but in the future it may be used for incremental parsing. - - The index is 0..n-1. A seek to position i means that LA(1) will - return the ith symbol. So, seeking to 0 means LA(1) will return the - first element in the stream. - - - - - Only makes sense for streams that buffer everything up probably, but - might be useful to display the entire stream or for testing. This - value includes a single EOF. - - - - - Where are you getting symbols from? Normally, implementations will - pass the buck all the way to the lexer who can ask its input stream - for the file name or whatever. - - - - - Rules can have start/stop info. - - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - - Rules can have start/stop info. - - The element type of the input stream. - - - - Gets the start element from the input stream - - - - - Gets the stop element from the input stream - - - - Get the text of the token - - - The line number on which this token was matched; line=1..n - - - The index of the first character relative to the beginning of the line 0..n-1 - - - - An index from 0..n-1 of the token object in the input stream. - This must be valid in order to use the ANTLRWorks debugger. - - - - - From what character stream was this token created? You don't have to - implement but it's nice to know where a Token comes from if you have - include files etc... on the input. - - - - - A source of tokens must provide a sequence of tokens via nextToken() - and also must reveal it's source of characters; CommonToken's text is - computed from a CharStream; it only store indices into the char stream. - - - - Errors from the lexer are never passed to the parser. Either you want - to keep going or you do not upon token recognition error. If you do not - want to continue lexing then you do not want to continue parsing. Just - throw an exception not under RecognitionException and Java will naturally - toss you all the way out of the recognizers. If you want to continue - lexing then you should not throw an exception to the parser--it has already - requested a token. Keep lexing until you get a valid one. Just report - errors and keep going, looking for a valid token. - - - - - Return a Token object from your input stream (usually a CharStream). - Do not fail/return upon lexing error; keep chewing on the characters - until you get a good one; errors are not passed through to the parser. - - - - - Where are you getting tokens from? normally the implication will simply - ask lexers input stream. - - - - A stream of tokens accessing tokens from a TokenSource - - - Get Token at current input pointer + i ahead where i=1 is next Token. - i<0 indicates tokens in the past. So -1 is previous token and -2 is - two tokens ago. LT(0) is undefined. For i>=n, return Token.EOFToken. - Return null for LT(0) and any index that results in an absolute address - that is negative. - - - - How far ahead has the stream been asked to look? The return - value is a valid index from 0..n-1. - - - - - Get a token at an absolute index i; 0..n-1. This is really only - needed for profiling and debugging and token stream rewriting. - If you don't want to buffer up tokens, then this method makes no - sense for you. Naturally you can't use the rewrite stream feature. - I believe DebugTokenStream can easily be altered to not use - this method, removing the dependency. - - - - - Where is this stream pulling tokens from? This is not the name, but - the object that provides Token objects. - - - - - Return the text of all tokens from start to stop, inclusive. - If the stream does not buffer all the tokens then it can just - return "" or null; Users should not access $ruleLabel.text in - an action of course in that case. - - - - - Because the user is not required to use a token with an index stored - in it, we must provide a means for two token objects themselves to - indicate the start/end location. Most often this will just delegate - to the other toString(int,int). This is also parallel with - the TreeNodeStream.toString(Object,Object). - - - - - The most common stream of tokens is one where every token is buffered up - and tokens are prefiltered for a certain channel (the parser will only - see these tokens and cannot change the filter channel number during the - parse). - - - TODO: how to access the full token stream? How to track all tokens matched per rule? - - - - Record every single token pulled from the source so we can reproduce - chunks of it later. - - - - Map from token type to channel to override some Tokens' channel numbers - - - Set of token types; discard any tokens with this type - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - By default, track all incoming tokens - - - Track the last mark() call result value for use in rewind(). - - - - The index into the tokens list of the current token (next token - to consume). p==-1 indicates that the tokens list is empty - - - - - How deep have we gone? - - - - Reset this token stream by setting its token source. - - - - Load all tokens from the token source and put in tokens. - This is done upon first LT request because you might want to - set some token type / channel overrides before filling buffer. - - - - - Move the input pointer to the next incoming token. The stream - must become active with LT(1) available. consume() simply - moves the input pointer so that LT(1) points at the next - input symbol. Consume at least one token. - - - - Walk past any token not on the channel the parser is listening to. - - - - Given a starting index, return the index of the first on-channel token. - - - - A simple filter mechanism whereby you can tell this token stream - to force all tokens of type ttype to be on channel. For example, - when interpreting, we cannot exec actions so we need to tell - the stream to force all WS and NEWLINE to be a different, ignored - channel. - - - - - Given a start and stop index, return a List of all tokens in - the token type BitSet. Return null if no tokens were found. This - method looks at both on and off channel tokens. - - - - - Get the ith token from the current position 1..n where k=1 is the - first symbol of lookahead. - - - - Look backwards k tokens on-channel tokens - - - - Return absolute token i; ignore which channel the tokens are on; - that is, count all tokens not just on-channel tokens. - - - - - A lexer is recognizer that draws input symbols from a character stream. - lexer grammars result in a subclass of this object. A Lexer object - uses simplified match() and error recovery mechanisms in the interest - of speed. - - - - Where is the lexer drawing characters from? - - - - Gets or sets the text matched so far for the current token or any text override. - - - Setting this value replaces any previously set value, and overrides the original text. - - - - Return a token from this source; i.e., match a token on the char stream. - - - Returns the EOF token (default), if you need - to return a custom token instead override this method. - - - - Instruct the lexer to skip creating a token for current lexer rule - and look for another token. nextToken() knows to keep looking when - a lexer rule finishes with token set to SKIP_TOKEN. Recall that - if token==null at end of any token rule, it creates one for you - and emits it. - - - - This is the lexer entry point that sets instance var 'token' - - - - Currently does not support multiple emits per nextToken invocation - for efficiency reasons. Subclass and override this method and - nextToken (to push tokens into a list and pull from that list rather - than a single variable as this implementation does). - - - - - The standard method called to automatically emit a token at the - outermost lexical rule. The token object should point into the - char buffer start..stop. If there is a text override in 'text', - use that to set the token's text. Override this method to emit - custom Token objects. - - - - If you are building trees, then you should also override - Parser or TreeParser.getMissingSymbol(). - - - - What is the index of the current character of lookahead? - - - - Lexers can normally match any char in it's vocabulary after matching - a token, so do the easy thing and just kill a character and hope - it all works out. You can instead use the rule invocation stack - to do sophisticated error recovery if you are in a fragment rule. - - - - A queue that can dequeue and get(i) in O(1) and grow arbitrarily large. - A linked list is fast at dequeue but slow at get(i). An array is - the reverse. This is O(1) for both operations. - - List grows until you dequeue last element at end of buffer. Then - it resets to start filling at 0 again. If adds/removes are balanced, the - buffer will not grow too large. - - No iterator stuff as that's not how we'll use it. - - - dynamically-sized buffer of elements - - - index of next element to fill - - - - How deep have we gone? - - - - - Return element {@code i} elements ahead of current element. {@code i==0} - gets current element. This is not an absolute index into {@link #data} - since {@code p} defines the start of the real list. - - - - Get and remove first element in queue - - - Return string of current buffer contents; non-destructive - - - - A lookahead queue that knows how to mark/release locations in the buffer for - backtracking purposes. Any markers force the {@link FastQueue} superclass to - keep all elements until no more markers; then can reset to avoid growing a - huge buffer. - - - - Absolute token index. It's the index of the symbol about to be - read via {@code LT(1)}. Goes from 0 to numtokens. - - - This is the {@code LT(-1)} element for the first element in {@link #data}. - - - Track object returned by nextElement upon end of stream; - Return it later when they ask for LT passed end of input. - - - Track the last mark() call result value for use in rewind(). - - - tracks how deep mark() calls are nested - - - - Implement nextElement to supply a stream of elements to this - lookahead buffer. Return EOF upon end of the stream we're pulling from. - - - - - Get and remove first element in queue; override - {@link FastQueue#remove()}; it's the same, just checks for backtracking. - - - - Make sure we have at least one element to remove, even if EOF - - - - Make sure we have 'need' elements from current position p. Last valid - p index is data.size()-1. p+need-1 is the data index 'need' elements - ahead. If we need 1 element, (p+1-1)==p must be < data.size(). - - - - add n elements to buffer - - - Size of entire stream is unknown; we only know buffer size from FastQueue - - - - Seek to a 0-indexed absolute token index. Normally used to seek backwards - in the buffer. Does not force loading of nodes. - - - To preserve backward compatibility, this method allows seeking past the - end of the currently buffered data. In this case, the input pointer will - be moved but the data will only actually be loaded upon the next call to - {@link #consume} or {@link #LT} for {@code k>0}. - - - - A mismatched char or Token or tree node - - - - We were expecting a token but it's not found. The current token - is actually what we wanted next. Used for tree node errors too. - - - - - A parser for TokenStreams. "parser grammars" result in a subclass - of this. - - - - Gets or sets the token stream; resets the parser upon a set. - - - - Rules that return more than a single value must return an object - containing all the values. Besides the properties defined in - RuleLabelScope.predefinedRulePropertiesScope there may be user-defined - return values. This class simply defines the minimum properties that - are always defined and methods to access the others that might be - available depending on output option such as template and tree. - - - - Note text is not an actual property of the return value, it is computed - from start and stop using the input stream's toString() method. I - could add a ctor to this so that we can pass in and store the input - stream, but I'm not sure we want to do that. It would seem to be undefined - to get the .text property anyway if the rule matches tokens from multiple - input streams. - - I do not use getters for fields of objects that are used simply to - group values such as this aggregate. The getters/setters are there to - satisfy the superclass interface. - - - - The root of the ANTLR exception hierarchy. - - - To avoid English-only error messages and to generally make things - as flexible as possible, these exceptions are not created with strings, - but rather the information necessary to generate an error. Then - the various reporting methods in Parser and Lexer can be overridden - to generate a localized error message. For example, MismatchedToken - exceptions are built with the expected token type. - So, don't expect getMessage() to return anything. - - Note that as of Java 1.4, you can access the stack trace, which means - that you can compute the complete trace of rules from the start symbol. - This gives you considerable context information with which to generate - useful error messages. - - ANTLR generates code that throws exceptions upon recognition error and - also generates code to catch these exceptions in each rule. If you - want to quit upon first error, you can turn off the automatic error - handling mechanism using rulecatch action, but you still need to - override methods mismatch and recoverFromMismatchSet. - - In general, the recognition exceptions can track where in a grammar a - problem occurred and/or what was the expected input. While the parser - knows its state (such as current input symbol and line info) that - state can change before the exception is reported so current token index - is computed and stored at exception time. From this info, you can - perhaps print an entire line of input not just a single token, for example. - Better to just say the recognizer had a problem and then let the parser - figure out a fancy report. - - - - What input stream did the error occur in? - - - - What was the lookahead index when this exception was thrown? - - - - What is index of token/char were we looking at when the error occurred? - - - - The current Token when an error occurred. Since not all streams - can retrieve the ith Token, we have to track the Token object. - For parsers. Even when it's a tree parser, token might be set. - - - - - If this is a tree parser exception, node is set to the node with - the problem. - - - - The current char when an error occurred. For lexers. - - - - Track the line (1-based) at which the error occurred in case this is - generated from a lexer. We need to track this since the - unexpected char doesn't carry the line info. - - - - - The 0-based index into the line where the error occurred. - - - - - If you are parsing a tree node stream, you will encounter som - imaginary nodes w/o line/col info. We now search backwards looking - for most recent token with line/col info, but notify getErrorHeader() - that info is approximate. - - - - Used for remote debugger deserialization - - - Return the token type or char of the unexpected input element - - - - The set of fields needed by an abstract recognizer to recognize input - and recover from errors etc... As a separate state object, it can be - shared among multiple grammars; e.g., when one grammar imports another. - - - - These fields are publically visible but the actual state pointer per - parser is protected. - - - - - Track the set of token types that can follow any rule invocation. - Stack grows upwards. When it hits the max, it grows 2x in size - and keeps going. - - - - - This is true when we see an error and before having successfully - matched a token. Prevents generation of more than one error message - per error. - - - - - The index into the input stream where the last error occurred. - This is used to prevent infinite loops where an error is found - but no token is consumed during recovery...another error is found, - ad naseum. This is a failsafe mechanism to guarantee that at least - one token/tree node is consumed for two errors. - - - - - In lieu of a return value, this indicates that a rule or token - has failed to match. Reset to false upon valid token match. - - - - Did the recognizer encounter a syntax error? Track how many. - - - - If 0, no backtracking is going on. Safe to exec actions etc... - If >0 then it's the level of backtracking. - - - - - An array[size num rules] of dictionaries that tracks - the stop token index for each rule. ruleMemo[ruleIndex] is - the memoization table for ruleIndex. For key ruleStartIndex, you - get back the stop token for associated rule or MEMO_RULE_FAILED. - - - This is only used if rule memoization is on (which it is by default). - - - - The goal of all lexer rules/methods is to create a token object. - This is an instance variable as multiple rules may collaborate to - create a single token. nextToken will return this object after - matching lexer rule(s). If you subclass to allow multiple token - emissions, then set this to the last token to be matched or - something nonnull so that the auto token emit mechanism will not - emit another token. - - - - - What character index in the stream did the current token start at? - Needed, for example, to get the text for current token. Set at - the start of nextToken. - - - - The line on which the first character of the token resides - - - The character position of first character within the line - - - The channel number for the current token - - - The token type for the current token - - - - You can set the text for the current token to override what is in - the input char buffer. Use setText() or can set this instance var. - - - - - All tokens go to the parser (unless skip() is called in that rule) - on a particular "channel". The parser tunes to a particular channel - so that whitespace etc... can go to the parser on a "hidden" channel. - - - - - Anything on different channel than DEFAULT_CHANNEL is not parsed - by parser. - - - - Useful for dumping out the input stream after doing some - augmentation or other manipulations. - - You can insert stuff, replace, and delete chunks. Note that the - operations are done lazily--only if you convert the buffer to a - String. This is very efficient because you are not moving data around - all the time. As the buffer of tokens is converted to strings, the - toString() method(s) check to see if there is an operation at the - current index. If so, the operation is done and then normal String - rendering continues on the buffer. This is like having multiple Turing - machine instruction streams (programs) operating on a single input tape. :) - - Since the operations are done lazily at toString-time, operations do not - screw up the token index values. That is, an insert operation at token - index i does not change the index values for tokens i+1..n-1. - - Because operations never actually alter the buffer, you may always get - the original token stream back without undoing anything. Since - the instructions are queued up, you can easily simulate transactions and - roll back any changes if there is an error just by removing instructions. - For example, - - CharStream input = new ANTLRFileStream("input"); - TLexer lex = new TLexer(input); - TokenRewriteStream tokens = new TokenRewriteStream(lex); - T parser = new T(tokens); - parser.startRule(); - - Then in the rules, you can execute - Token t,u; - ... - input.insertAfter(t, "text to put after t");} - input.insertAfter(u, "text after u");} - System.out.println(tokens.toString()); - - Actually, you have to cast the 'input' to a TokenRewriteStream. :( - - You can also have multiple "instruction streams" and get multiple - rewrites from a single pass over the input. Just name the instruction - streams and use that name again when printing the buffer. This could be - useful for generating a C file and also its header file--all from the - same buffer: - - tokens.insertAfter("pass1", t, "text to put after t");} - tokens.insertAfter("pass2", u, "text after u");} - System.out.println(tokens.toString("pass1")); - System.out.println(tokens.toString("pass2")); - - If you don't use named rewrite streams, a "default" stream is used as - the first example shows. - - - What index into rewrites List are we? - - - Token buffer index. - - - - Execute the rewrite operation by possibly adding to the buffer. - Return the index of the next token to operate on. - - - - - I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp - instructions. - - - - - You may have multiple, named streams of rewrite operations. - I'm calling these things "programs." - Maps String (name) -> rewrite (List) - - - - Map String (program name) -> Integer index - - - - Rollback the instruction stream for a program so that - the indicated instruction (via instructionIndex) is no - longer in the stream. UNTESTED! - - - - Reset the program so that no instructions exist - - - We need to combine operations and report invalid operations (like - overlapping replaces that are not completed nested). Inserts to - same index need to be combined etc... Here are the cases: - - I.i.u I.j.v leave alone, nonoverlapping - I.i.u I.i.v combine: Iivu - - R.i-j.u R.x-y.v | i-j in x-y delete first R - R.i-j.u R.i-j.v delete first R - R.i-j.u R.x-y.v | x-y in i-j ERROR - R.i-j.u R.x-y.v | boundaries overlap ERROR - - Delete special case of replace (text==null): - D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) - - I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before - we're not deleting i) - I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping - R.x-y.v I.i.u | i in x-y ERROR - R.x-y.v I.x.u R.x-y.uv (combine, delete I) - R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping - - I.i.u = insert u before op @ index i - R.x-y.u = replace x-y indexed tokens with u - - First we need to examine replaces. For any replace op: - - 1. wipe out any insertions before op within that range. - 2. Drop any replace op before that is contained completely within - that range. - 3. Throw exception upon boundary overlap with any previous replace. - - Then we can deal with inserts: - - 1. for any inserts to same index, combine even if not adjacent. - 2. for any prior replace with same left boundary, combine this - insert with replace and delete this replace. - 3. throw exception if index in same range as previous replace - - Don't actually delete; make op null in list. Easier to walk list. - Later we can throw as we add to index -> op map. - - Note that I.2 R.2-2 will wipe out I.2 even though, technically, the - inserted stuff would be before the replace range. But, if you - add tokens in front of a method body '{' and then delete the method - body, I think the stuff before the '{' you added should disappear too. - - Return a map from token index to operation. - - - Get all operations before an index of a particular kind - - - - In an action, a lexer rule can set token to this SKIP_TOKEN and ANTLR - will avoid creating a token for this symbol and try to fetch another. - - - - imaginary tree navigation type; traverse "get child" link - - - imaginary tree navigation type; finish with a child list - - - - A generic tree implementation with no payload. You must subclass to - actually have any user data. ANTLR v3 uses a list of children approach - instead of the child-sibling approach in v2. A flat tree (a list) is - an empty node whose children represent the list. An empty, but - non-null node is called "nil". - - - - - Create a new node from an existing node does nothing for BaseTree - as there are no fields other than the children list, which cannot - be copied as the children are not considered part of this node. - - - - - Get the children internal List; note that if you directly mess with - the list, do so at your own risk. - - - - BaseTree doesn't track parent pointers. - - - BaseTree doesn't track child indexes. - - - Add t as child of this node. - - - Warning: if t has no children, but child does - and child isNil then this routine moves children to t via - t.children = child.children; i.e., without copying the array. - - - - Add all elements of kids list as children of this node - - - Insert child t at child position i (0..n-1) by shifting children - i+1..n-1 to the right one position. Set parent / indexes properly - but does NOT collapse nil-rooted t's that come in here like addChild. - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - Override in a subclass to change the impl of children list - - - Set the parent and child index values for all child of t - - - Walk upwards looking for ancestor with this token type. - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - Print out a whole tree not just a node - - - Override to say how a node (not a tree) should look as text - - - A TreeAdaptor that works with any Tree implementation. - - - - System.identityHashCode() is not always unique; we have to - track ourselves. That's ok, it's only for debugging, though it's - expensive: we have to create a hashtable with all tree nodes in it. - - - - - Create tree node that holds the start and stop tokens associated - with an error. - - - - If you specify your own kind of tree nodes, you will likely have to - override this method. CommonTree returns Token.INVALID_TOKEN_TYPE - if no token payload but you might have to set token type for diff - node type. - - You don't have to subclass CommonErrorNode; you will likely need to - subclass your own tree node class to avoid class cast exception. - - - - - This is generic in the sense that it will work with any kind of - tree (not just ITree interface). It invokes the adaptor routines - not the tree node routines to do the construction. - - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - Transform ^(nil x) to x and nil to null - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Duplicate a node. This is part of the factory; - override if you want another kind of node to be built. - - - - I could use reflection to prevent having to override this - but reflection is slow. - - - - - Track start/stop token for subtree root created for a rule. - Only works with Tree nodes. For rules that match nothing, - seems like this will yield start=i and stop=i-1 in a nil node. - Might be useful info so I'll not force to be i..i. - - - - A buffered stream of tree nodes. Nodes can be from a tree of ANY kind. - - This node stream sucks all nodes out of the tree specified in - the constructor during construction and makes pointers into - the tree using an array of Object pointers. The stream necessarily - includes pointers to DOWN and UP and EOF nodes. - - This stream knows how to mark/release for backtracking. - - This stream is most suitable for tree interpreters that need to - jump around a lot or for tree parsers requiring speed (at cost of memory). - There is some duplicated functionality here with UnBufferedTreeNodeStream - but just in bookkeeping, not tree walking etc... - - TARGET DEVELOPERS: - - This is the old CommonTreeNodeStream that buffered up entire node stream. - No need to implement really as new CommonTreeNodeStream is much better - and covers what we need. - - @see CommonTreeNodeStream - - - The complete mapping from stream index to tree node. - This buffer includes pointers to DOWN, UP, and EOF nodes. - It is built upon ctor invocation. The elements are type - Object as we don't what the trees look like. - - Load upon first need of the buffer so we can set token types - of interest for reverseIndexing. Slows us down a wee bit to - do all of the if p==-1 testing everywhere though. - - - Pull nodes from which tree? - - - IF this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - Reuse same DOWN, UP navigation nodes unless this is true - - - The index into the nodes list of the current node (next node - to consume). If -1, nodes array not filled yet. - - - Track the last mark() call result value for use in rewind(). - - - Stack of indexes used for push/pop calls - - - Walk tree with depth-first-search and fill nodes buffer. - Don't do DOWN, UP nodes if its a list (t is isNil). - - - What is the stream index for node? 0..n-1 - Return -1 if node not found. - - - As we flatten the tree, we use UP, DOWN nodes to represent - the tree structure. When debugging we need unique nodes - so instantiate new ones when uniqueNavigationNodes is true. - - - Look backwards k nodes - - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - - Used for testing, just return the token type stream - - - Debugging - - - A node representing erroneous token range in token stream - - - - A tree node that is wrapper for a Token object. After 3.0 release - while building tree rewrite stuff, it became clear that computing - parent and child index is very difficult and cumbersome. Better to - spend the space in every tree node. If you don't want these extra - fields, it's easy to cut them out in your own BaseTree subclass. - - - - A single token is the payload - - - - What token indexes bracket all tokens associated with this node - and below? - - - - Who is the parent node of this node; if null, implies node is root - - - What index is this node in the child list? Range: 0..n-1 - - - - For every node in this subtree, make sure it's start/stop token's - are set. Walk depth first, visit bottom up. Only updates nodes - with at least one token index < 0. - - - - - A TreeAdaptor that works with any Tree implementation. It provides - really just factory methods; all the work is done by BaseTreeAdaptor. - If you would like to have different tokens created than ClassicToken - objects, you need to override this and then set the parser tree adaptor to - use your subclass. - - - - To get your parser to build nodes of a different type, override - create(Token), errorNode(), and to be safe, YourTreeClass.dupNode(). - dupNode is called to duplicate nodes during rewrite operations. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - Tell me how to create a token for use with imaginary token nodes. - For example, there is probably no input symbol associated with imaginary - token DECL, but you need to create it as a payload or whatever for - the DECL node as in ^(DECL type ID). - - - - This is a variant of createToken where the new token is derived from - an actual real input token. Typically this is for converting '{' - tokens to BLOCK etc... You'll see - - r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; - - If you care what the token payload objects' type is, you should - override this method and any other createToken variant. - - - - - What is the Token associated with this node? If - you are not using CommonTree, then you must - override this in your own adaptor. - - - - Pull nodes from which tree? - - - If this tree (root) was created from a token stream, track it. - - - What tree adaptor was used to build these trees - - - The tree iterator we are using - - - Stack of indexes used for push/pop calls - - - Tree (nil A B C) trees like flat A B C streams - - - Tracks tree depth. Level=0 means we're at root node level. - - - Tracks the last node before the start of {@link #data} which contains - position information to provide information for error reporting. This is - tracked in addition to {@link #prevElement} which may or may not contain - position information. - - @see #hasPositionInformation - @see RecognitionException#extractInformationFromTreeNodeStream - - - Make stream jump to a new location, saving old location. - Switch back with pop(). - - - Seek back to previous index saved during last push() call. - Return top of stack (return index). - - - Returns an element containing position information. If {@code allowApproximateLocation} is {@code false}, then - this method will return the {@code LT(1)} element if it contains position information, and otherwise return {@code null}. - If {@code allowApproximateLocation} is {@code true}, then this method will return the last known element containing position information. - - @see #hasPositionInformation - - - For debugging; destructive: moves tree iterator to end. - - - A utility class to generate DOT diagrams (graphviz) from - arbitrary trees. You can pass in your own templates and - can pass in any kind of tree or use Tree interface method. - I wanted this separator so that you don't have to include - ST just to use the org.antlr.runtime.tree.* package. - This is a set of non-static methods so you can subclass - to override. For example, here is an invocation: - - CharStream input = new ANTLRInputStream(System.in); - TLexer lex = new TLexer(input); - CommonTokenStream tokens = new CommonTokenStream(lex); - TParser parser = new TParser(tokens); - TParser.e_return r = parser.e(); - Tree t = (Tree)r.tree; - System.out.println(t.toStringTree()); - DOTTreeGenerator gen = new DOTTreeGenerator(); - StringTemplate st = gen.toDOT(t); - System.out.println(st); - - - Track node to number mapping so we can get proper node name back - - - Track node number so we can get unique node names - - - Generate DOT (graphviz) for a whole tree not just a node. - For example, 3+4*5 should generate: - - digraph { - node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier", - width=.4, height=.2]; - edge [arrowsize=.7] - "+"->3 - "+"->"*" - "*"->4 - "*"->5 - } - - Takes a Tree interface object. - - - - @author Sam Harwell - - - Returns an element containing concrete information about the current - position in the stream. - - @param allowApproximateLocation if {@code false}, this method returns - {@code null} if an element containing exact information about the current - position is not available - - - Determines if the specified {@code element} contains concrete position - information. - - @param element the element to check - @return {@code true} if {@code element} contains concrete position - information, otherwise {@code false} - - - - What does a tree look like? ANTLR has a number of support classes - such as CommonTreeNodeStream that work on these kinds of trees. You - don't have to make your trees implement this interface, but if you do, - you'll be able to use more support code. - - - - NOTE: When constructing trees, ANTLR can build any kind of tree; it can - even use Token objects as trees if you add a child list to your tokens. - - This is a tree node without any payload; just navigation and factory stuff. - - - - Is there is a node above with token type ttype? - - - Walk upwards and get first ancestor with this token type. - - - - Return a list of all ancestors of this node. The first node of - list is the root and the last is the parent of this node. - - - - This node is what child index? 0..n-1 - - - Set the parent and child index values for all children - - - - Add t as a child to this node. If t is null, do nothing. If t - is nil, add all children of t to this' children. - - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - - Delete children from start to stop and replace with t even if t is - a list (nil-root tree). num of children can increase or decrease. - For huge child lists, inserting children can force walking rest of - children to set their childindex; could be slow. - - - - - Indicates the node is a nil node but may still have children, meaning - the tree is a flat list. - - - - - What is the smallest token index (indexing from 0) for this node - and its children? - - - - - What is the largest token index (indexing from 0) for this node - and its children? - - - - Return a token type; needed for tree parsing - - - In case we don't have a token payload, what is the line for errors? - - - - How to create and navigate trees. Rather than have a separate factory - and adaptor, I've merged them. Makes sense to encapsulate. - - - - This takes the place of the tree construction code generated in the - generated code in 2.x and the ASTFactory. - - I do not need to know the type of a tree at all so they are all - generic Objects. This may increase the amount of typecasting needed. :( - - - - - Create a tree node from Token object; for CommonTree type trees, - then the token just becomes the payload. This is the most - common create call. - - - - Override if you want another kind of node to be built. - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel]. - - - - This should invoke createToken(Token). - - - - - Same as create(tokenType,fromToken) except set the text too. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG[$tokenLabel, "IMAG"]. - - - - This should invoke createToken(Token). - - - - - Same as create(fromToken) except set the text too. - This is invoked when the text terminal option is set, as in - IMAG<text='IMAG'>. - - - - This should invoke createToken(Token). - - - - - Create a new node derived from a token, with a new token type. - This is invoked from an imaginary node ref on right side of a - rewrite rule as IMAG["IMAG"]. - - - - This should invoke createToken(int,String). - - - - Duplicate a single tree node. - Override if you want another kind of node to be built. - - - Duplicate tree recursively, using dupNode() for each node - - - - Return a nil node (an empty but non-null node) that can hold - a list of element as the children. If you want a flat tree (a list) - use "t=adaptor.nil(); t.addChild(x); t.addChild(y);" - - - - - Return a tree node representing an error. This node records the - tokens consumed during error recovery. The start token indicates the - input symbol at which the error was detected. The stop token indicates - the last symbol consumed during recovery. - - - - You must specify the input stream so that the erroneous text can - be packaged up in the error node. The exception could be useful - to some applications; default implementation stores ptr to it in - the CommonErrorNode. - - This only makes sense during token parsing, not tree parsing. - Tree parsing should happen only when parsing and tree construction - succeed. - - - - Is tree considered a nil node used to make lists of child nodes? - - - - Add a child to the tree t. If child is a flat tree (a list), make all - in list children of t. Warning: if t has no children, but child does - and child isNil then you can decide it is ok to move children to t via - t.children = child.children; i.e., without copying the array. Just - make sure that this is consistent with have the user will build - ASTs. Do nothing if t or child is null. - - - - - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - old=^(nil a b c), new=r yields ^(r a b c) - old=^(a b c), new=r yields ^(r ^(a b c)) - - If newRoot is a nil-rooted single child tree, use the single - child as the new root node. - - old=^(nil a b c), new=^(nil r) yields ^(r a b c) - old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) - - If oldRoot was null, it's ok, just return newRoot (even if isNil). - - old=null, new=r yields r - old=null, new=^(nil r) yields ^(nil r) - - Return newRoot. Throw an exception if newRoot is not a - simple node or nil root with a single child node--it must be a root - node. If newRoot is ^(nil x) return x as newRoot. - - Be advised that it's ok for newRoot to point at oldRoot's - children; i.e., you don't have to copy the list. We are - constructing these nodes so we should have this control for - efficiency. - - - - - Given the root of the subtree created for this rule, post process - it to do any simplifications or whatever you want. A required - behavior is to convert ^(nil singleSubtree) to singleSubtree - as the setting of start/stop indexes relies on a single non-nil root - for non-flat trees. - - - - Flat trees such as for lists like "idlist : ID+ ;" are left alone - unless there is only one ID. For a list, the start/stop indexes - are set in the nil node. - - This method is executed after all rule tree construction and right - before setTokenBoundaries(). - - - - For identifying trees. - - - How to identify nodes so we can say "add node to a prior node"? - Even becomeRoot is an issue. Use System.identityHashCode(node) - usually. - - - - - Create a node for newRoot make it the root of oldRoot. - If oldRoot is a nil root, just copy or move the children to newRoot. - If not a nil root, make oldRoot a child of newRoot. - - - - Return node created for newRoot. - - - - Be advised: when debugging ASTs, the DebugTreeAdaptor manually - calls create(Token child) and then plain becomeRoot(node, node) - because it needs to trap calls to create, but it can't since it delegates - to not inherits from the TreeAdaptor. - - - - For tree parsing, I need to know the token type of a node - - - Node constructors can set the type of a node - - - Node constructors can set the text of a node - - - - Return the token object from which this node was created. - Currently used only for printing an error message. - The error display routine in BaseRecognizer needs to - display where the input the error occurred. If your - tree of limitation does not store information that can - lead you to the token, you can create a token filled with - the appropriate information and pass that back. See - BaseRecognizer.getErrorMessage(). - - - - - Where are the bounds in the input token stream for this node and - all children? Each rule that creates AST nodes will call this - method right before returning. Flat trees (i.e., lists) will - still usually have a nil root node just to hold the children list. - That node would contain the start/stop indexes then. - - - - Get the token start index for this subtree; return -1 if no such index - - - Get the token stop index for this subtree; return -1 if no such index - - - Get a child 0..n-1 node - - - Set ith child (0..n-1) to t; t must be non-null and non-nil node - - - Remove ith child and shift children down from right. - - - How many children? If 0, then this is a leaf node - - - - Who is the parent node of this node; if null, implies node is root. - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - What index is this node in the child list? Range: 0..n-1 - If your node type doesn't handle this, it's ok but the tree rewrites - in tree parsers need this functionality. - - - - - Replace from start to stop child index of parent with t, which might - be a list. Number of children may be different after this call. - - - - If parent is null, don't do anything; must be at root of overall tree. - Can't replace whatever points to the parent externally. Do nothing. - - - - A stream of tree nodes, accessing nodes from a tree of some kind - - - - Get a tree node at an absolute index i; 0..n-1. - If you don't want to buffer up nodes, then this method makes no - sense for you. - - - - - Get tree node at current input pointer + ahead where - ==1 is next node. <0 indicates nodes in the past. So - {@code LT(-1)} is previous node, but implementations are not required to - provide results for < -1. {@code LT(0)} is undefined. For - <=n, return . Return for {@code LT(0)} - and any index that results in an absolute address that is negative. - - - - This is analogous to , but this returns a tree node - instead of a . Makes code generation identical for both - parser and tree grammars. - - - - - Where is this stream pulling nodes from? This is not the name, but - the object that provides node objects. - - - - - If the tree associated with this stream was created from a - {@link TokenStream}, you can specify it here. Used to do rule - {@code $text} attribute in tree parser. Optional unless you use tree - parser rule {@code $text} attribute or {@code output=template} and - {@code rewrite=true} options. - - - - - What adaptor can tell me how to interpret/navigate nodes and - trees. E.g., get text of a node. - - - - - As we flatten the tree, we use {@link Token#UP}, {@link Token#DOWN} nodes - to represent the tree structure. When debugging we need unique nodes so - we have to instantiate new ones. When doing normal tree parsing, it's - slow and a waste of memory to create unique navigation nodes. Default - should be {@code false}. - - - - - Return the text of all nodes from {@code start} to {@code stop}, - inclusive. If the stream does not buffer all the nodes then it can still - walk recursively from start until stop. You can always return - {@code null} or {@code ""} too, but users should not access - {@code $ruleLabel.text} in an action of course in that case. - - - - - Replace children of {@code parent} from index {@code startChildIndex} to - {@code stopChildIndex} with {@code t}, which might be a list. Number of - children may be different after this call. The stream is notified because - it is walking the tree and might need to know you are monkeying with the - underlying tree. Also, it might be able to modify the node stream to - avoid restreaming for future phases. - - - - If {@code parent} is {@code null}, don't do anything; must be at root of - overall tree. Can't replace whatever points to the parent externally. Do - nothing. - - - - - How to execute code for node t when a visitor visits node t. Execute - pre() before visiting children and execute post() after visiting children. - - - - - Execute an action before visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. Children of returned value will be - visited if using TreeVisitor.visit(). - - - - - Execute an action after visiting children of t. Return t or - a rewritten t. It is up to the visitor to decide what to do - with the return value. - - - - - A record of the rules used to match a token sequence. The tokens - end up as the leaves of this tree and rule nodes are the interior nodes. - This really adds no functionality, it is just an alias for CommonTree - that is more meaningful (specific) and holds a String to display for a node. - - - - - Emit a token and all hidden nodes before. EOF node holds all - hidden tokens after last real token. - - - - - Print out the leaves of this tree, which means printing original - input back out. - - - - - Base class for all exceptions thrown during AST rewrite construction. - This signifies a case where the cardinality of two or more elements - in a subrule are different: (ID INT)+ where |ID|!=|INT| - - - - No elements within a (...)+ in a rewrite rule - - - Ref to ID or expr but no tokens in ID stream or subtrees in expr stream - - - - A generic list of elements tracked in an alternative to be used in - a -> rewrite rule. We need to subclass to fill in the next() method, - which returns either an AST node wrapped around a token payload or - an existing subtree. - - - - Once you start next()ing, do not try to add more elements. It will - break the cursor tracking I believe. - - TODO: add mechanism to detect/puke on modification after reading from stream - - - - - - - - Cursor 0..n-1. If singleElement!=null, cursor is 0 until you next(), - which bumps it to 1 meaning no more elements. - - - - Track single elements w/o creating a list. Upon 2nd add, alloc list - - - The list of tokens or subtrees we are tracking - - - Once a node / subtree has been used in a stream, it must be dup'd - from then on. Streams are reset after subrules so that the streams - can be reused in future subrules. So, reset must set a dirty bit. - If dirty, then next() always returns a dup. - - - The element or stream description; usually has name of the token or - rule reference that this list tracks. Can include rulename too, but - the exception would track that info. - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Reset the condition of this stream so that it appears we have - not consumed any of its elements. Elements themselves are untouched. - Once we reset the stream, any future use will need duplicates. Set - the dirty bit. - - - - - Return the next element in the stream. If out of elements, throw - an exception unless size()==1. If size is 1, then return elements[0]. - Return a duplicate node/subtree if stream is out of elements and - size==1. If we've already used the element, dup (dirty bit set). - - - - - Do the work of getting the next element, making sure that it's - a tree node or subtree. Deal with the optimization of single- - element list versus list of size > 1. Throw an exception - if the stream is empty or we're out of elements and size>1. - protected so you can override in a subclass if necessary. - - - - - When constructing trees, sometimes we need to dup a token or AST - subtree. Dup'ing a token means just creating another AST node - around it. For trees, you must call the adaptor.dupTree() unless - the element is for a tree root; then it must be a node dup. - - - - - Ensure stream emits trees; tokens must be converted to AST nodes. - AST nodes can be passed through unmolested. - - - - - Queues up nodes matched on left side of -> in a tree parser. This is - the analog of RewriteRuleTokenStream for normal parsers. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - - Treat next element as a single node even if it's a subtree. - This is used instead of next() when the result has to be a - tree root node. Also prevents us from duplicating recently-added - children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration - must dup the type node, but ID has been added. - - - - Referencing a rule result twice is ok; dup entire tree as - we can't be adding trees as root; e.g., expr expr. - - Hideous code duplication here with super.next(). Can't think of - a proper way to refactor. This needs to always call dup node - and super.next() doesn't know which to call: dup node or dup tree. - - - - Create a stream with one element - - - Create a stream, but feed off an existing list - - - Get next token from stream and make a node for it - - - - Don't convert to a tree unless they explicitly call nextTree. - This way we can do hetero tree nodes in rewrite. - - - - Return a node stream from a doubly-linked tree whose nodes - know what child index they are. No remove() is supported. - - Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure. - - - If we emit UP/DOWN nodes, we need to spit out multiple nodes per - next() call. - - - - A parser for a stream of tree nodes. "tree grammars" result in a subclass - of this. All the error reporting and recovery is shared with Parser via - the BaseRecognizer superclass. - - - - Set the input stream - - - - Match '.' in tree parser has special meaning. Skip node or - entire tree if node has children. If children, scan until - corresponding UP node. - - - - - We have DOWN/UP nodes in the stream that have no line info; override. - plus we want to alter the exception type. Don't try to recover - from tree parser errors inline... - - - - - Prefix error message with the grammar name because message is - always intended for the programmer because the parser built - the input tree not the user. - - - - - Tree parsers parse nodes they usually have a token object as - payload. Set the exception token and do the default behavior. - - - - The tree pattern to lex like "(A B C)" - - - Index into input string - - - Current char - - - How long is the pattern in char? - - - Set when token type is ID or ARG (name mimics Java's StreamTokenizer) - - - Override this if you need transformation tracing to go somewhere - other than stdout or if you're not using ITree-derived trees. - - - - This is identical to the ParserRuleReturnScope except that - the start property is a tree nodes not Token object - when you are parsing trees. - - - - Gets the first node or root node of tree matched for this rule. - - - Do a depth first walk of a tree, applying pre() and post() actions as we go. - - - - Visit every node in tree t and trigger an action for each node - before/after having visited all of its children. Bottom up walk. - Execute both actions even if t has no children. Ignore return - results from transforming children since they will have altered - the child list of this node (their parent). Return result of - applying post action to this node. - - - - - Build and navigate trees with this object. Must know about the names - of tokens so you have to pass in a map or array of token names (from which - this class can build the map). I.e., Token DECL means nothing unless the - class can translate it to a token type. - - - - In order to create nodes and navigate, this class needs a TreeAdaptor. - - This class can build a token type -> node index for repeated use or for - iterating over the various nodes with a particular type. - - This class works in conjunction with the TreeAdaptor rather than moving - all this functionality into the adaptor. An adaptor helps build and - navigate trees using methods. This class helps you do it with string - patterns like "(A B C)". You can create a tree from that pattern or - match subtrees against it. - - - - - When using %label:TOKENNAME in a tree for parse(), we must - track the label. - - - - This adaptor creates TreePattern objects for use during scan() - - - - Compute a Map<String, Integer> that is an inverted index of - tokenNames (which maps int token types to names). - - - - Using the map of token names to token types, return the type. - - - - Walk the entire tree and make a node name to nodes mapping. - For now, use recursion but later nonrecursive version may be - more efficient. Returns Map<Integer, List> where the List is - of your AST node type. The Integer is the token type of the node. - - - - TODO: save this index so that find and visit are faster - - - - Do the work for index - - - Return a List of tree nodes with token type ttype - - - Return a List of subtrees matching pattern. - - - - Visit every ttype node in t, invoking the visitor. This is a quicker - version of the general visit(t, pattern) method. The labels arg - of the visitor action method is never set (it's null) since using - a token type rather than a pattern doesn't let us set a label. - - - - Do the recursive work for visit - - - - For all subtrees that match the pattern, execute the visit action. - The implementation uses the root node of the pattern in combination - with visit(t, ttype, visitor) so nil-rooted patterns are not allowed. - Patterns with wildcard roots are also not allowed. - - - - - Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels - on the various nodes and '.' (dot) as the node/subtree wildcard, - return true if the pattern matches and fill the labels Map with - the labels pointing at the appropriate nodes. Return false if - the pattern is malformed or the tree does not match. - - - - If a node specifies a text arg in pattern, then that must match - for that node in t. - - TODO: what's a better way to indicate bad pattern? Exceptions are a hassle - - - - - Do the work for parse. Check to see if the t2 pattern fits the - structure and token types in t1. Check text if the pattern has - text arguments on nodes. Fill labels map with pointers to nodes - in tree matched against nodes in pattern with labels. - - - - - Create a tree or node from the indicated tree pattern that closely - follows ANTLR tree grammar tree element syntax: - - (root child1 ... child2). - - - - You can also just pass in a node: ID - - Any node can have a text argument: ID[foo] - (notice there are no quotes around foo--it's clear it's a string). - - nil is a special name meaning "give me a nil node". Useful for - making lists: (nil A B C) is a list of A B C. - - - - - Compare t1 and t2; return true if token types/text, structure match exactly. - The trees are examined in their entirety so that (A B) does not match - (A B C) nor (A (B C)). - - - - TODO: allow them to pass in a comparator - TODO: have a version that is nonstatic so it can use instance adaptor - - I cannot rely on the tree node's equals() implementation as I make - no constraints at all on the node types nor interface etc... - - - - - Compare type, structure, and text of two trees, assuming adaptor in - this instance of a TreeWizard. - - - - A token stream that pulls tokens from the code source on-demand and - without tracking a complete buffer of the tokens. This stream buffers - the minimum number of tokens possible. It's the same as - OnDemandTokenStream except that OnDemandTokenStream buffers all tokens. - - You can't use this stream if you pass whitespace or other off-channel - tokens to the parser. The stream can't ignore off-channel tokens. - - You can only look backwards 1 token: LT(-1). - - Use this when you need to read from a socket or other infinite stream. - - @see BufferedTokenStream - @see CommonTokenStream - - - Skip tokens on any channel but this one; this is how we skip whitespace... - - - An extra token while parsing a TokenStream - - - diff --git a/packages/FluentNHibernate.3.4.0/.signature.p7s b/packages/FluentNHibernate.3.4.0/.signature.p7s deleted file mode 100644 index d30b8b32a..000000000 Binary files a/packages/FluentNHibernate.3.4.0/.signature.p7s and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/FluentNHibernate.3.4.0.nupkg b/packages/FluentNHibernate.3.4.0/FluentNHibernate.3.4.0.nupkg deleted file mode 100644 index fb12795d2..000000000 Binary files a/packages/FluentNHibernate.3.4.0/FluentNHibernate.3.4.0.nupkg and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/LICENSE b/packages/FluentNHibernate.3.4.0/LICENSE deleted file mode 100644 index 6d96b3afe..000000000 --- a/packages/FluentNHibernate.3.4.0/LICENSE +++ /dev/null @@ -1,10 +0,0 @@ -Copyright (c) 2008-2018, James Gregory and contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of James Gregory nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/packages/FluentNHibernate.3.4.0/README.md b/packages/FluentNHibernate.3.4.0/README.md deleted file mode 100644 index 8a2437d23..000000000 --- a/packages/FluentNHibernate.3.4.0/README.md +++ /dev/null @@ -1,37 +0,0 @@ -![FluentNHibernate logo](https://raw.githubusercontent.com/nhibernate/fluent-nhibernate/main/docs/logo.png) - -[![Build status](https://ci.appveyor.com/api/projects/status/684r2ot07i2lrcij/branch/main?svg=true)](https://ci.appveyor.com/project/nhibernate/fluent-nhibernate/branch/main) -[![NuGet](https://img.shields.io/nuget/v/FluentNHibernate.svg)](https://www.nuget.org/packages/FluentNHibernate) - -## What is FluentNHibernate? -Fluent, XML-less, compile safe, automated, convention-based mappings for NHibernate. *Get your fluent on.* - -## Where can I get it? - -Install using the [FluentNHibernate NuGet package](https://www.nuget.org/packages/FluentNHibernate): - -``` -dotnet add package FluentNHibernate -``` - -## How do I use it? - -* Read the [introduction](https://github.com/FluentNHibernate/fluent-nhibernate/wiki/Getting-started). -* Get latest version from [NuGet](https://www.nuget.org/packages/FluentNHibernate) -* Create your [first project](https://github.com/FluentNHibernate/fluent-nhibernate/wiki/Getting-started#wiki-yourfirstproject). - -## Further reading - -Once you've followed the above, you can compare our [auto mapping](https://github.com/FluentNHibernate/fluent-nhibernate/wiki/Auto-mapping) to our [fluent interface](https://github.com/FluentNHibernate/fluent-nhibernate/wiki/Fluent-mapping) to see which suits your application, read through our [API documentation](https://github.com/FluentNHibernate/fluent-nhibernate/wiki/Fluent-configuration), or just see what's available for reading in our [wiki](https://github.com/FluentNHibernate/fluent-nhibernate/wiki). - -Contributors ---------------------------------------------- - -Fluent NHibernate wouldn't be possible without the time and effort of its contributors. The team comprises of [James Gregory](http://jagregory.com), [Paul Batum](http://www.paulbatum.com), Andrew Stewart, [Hudson Akridge](https://github.com/HudsonAkridge), [Gleb Chermennov](https://github.com/chester89) and [Jorge Rodríguez Galán](https://github.com/jrgcubano). - -**Our valued committers are:** Aaron Jensen, Alexander Gross, Andrew Stewart, Barry Dahlberg, Bobby Johnson, Brian Donahue, Cameron Harris, Chad Myers, Chris Chilvers, Craig Neuwirt, Dan Malcolm, Daniel Mirapalheta, David Archer, David Longnecker, David R. Longnecker, Derick Bailey, Erik Ojebo, Firo, Hudson Akridge, Ivan Zlatev, James Freiwirth, James Gregory, James Kovacs, Jeremy Skinner, Lee Henson, Louis DeJardin, Patric Forsgard, Paul Batum, Roelof Blom, Stuart Childs, Tom Janssens, Tuna Toksoz, U-BSOD\pruiz, di97mni, dschilling, felixg, jeremydmiller, kevm, leebrandt, maxild, robsosno, [Jorge Rodríguez Galán](https://github.com/jrgcubano) and many more.

- -Thanks goes to [Jeremy Miller](http://codebetter.com/blogs/jeremy.miller) for the original idea and implementation. - -Fluent NHibernate is © 2008-2018 [James Gregory](http://jagregory.com) and contributors under the [BSD license](https://github.com/nhibernate/fluent-nhibernate/blob/main/LICENSE) - diff --git a/packages/FluentNHibernate.3.4.0/lib/net461/FluentNHibernate.dll b/packages/FluentNHibernate.3.4.0/lib/net461/FluentNHibernate.dll deleted file mode 100644 index bdbac086d..000000000 Binary files a/packages/FluentNHibernate.3.4.0/lib/net461/FluentNHibernate.dll and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/lib/net461/FluentNHibernate.pdb b/packages/FluentNHibernate.3.4.0/lib/net461/FluentNHibernate.pdb deleted file mode 100644 index d7b71512d..000000000 Binary files a/packages/FluentNHibernate.3.4.0/lib/net461/FluentNHibernate.pdb and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/lib/netcoreapp2.0/FluentNHibernate.dll b/packages/FluentNHibernate.3.4.0/lib/netcoreapp2.0/FluentNHibernate.dll deleted file mode 100644 index b9eadace5..000000000 Binary files a/packages/FluentNHibernate.3.4.0/lib/netcoreapp2.0/FluentNHibernate.dll and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/lib/netcoreapp2.0/FluentNHibernate.pdb b/packages/FluentNHibernate.3.4.0/lib/netcoreapp2.0/FluentNHibernate.pdb deleted file mode 100644 index 8ce6c4639..000000000 Binary files a/packages/FluentNHibernate.3.4.0/lib/netcoreapp2.0/FluentNHibernate.pdb and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/lib/netstandard2.0/FluentNHibernate.dll b/packages/FluentNHibernate.3.4.0/lib/netstandard2.0/FluentNHibernate.dll deleted file mode 100644 index b2219d12f..000000000 Binary files a/packages/FluentNHibernate.3.4.0/lib/netstandard2.0/FluentNHibernate.dll and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/lib/netstandard2.0/FluentNHibernate.pdb b/packages/FluentNHibernate.3.4.0/lib/netstandard2.0/FluentNHibernate.pdb deleted file mode 100644 index 8472ef657..000000000 Binary files a/packages/FluentNHibernate.3.4.0/lib/netstandard2.0/FluentNHibernate.pdb and /dev/null differ diff --git a/packages/FluentNHibernate.3.4.0/logo-nuget.png b/packages/FluentNHibernate.3.4.0/logo-nuget.png deleted file mode 100644 index 8a4a59048..000000000 Binary files a/packages/FluentNHibernate.3.4.0/logo-nuget.png and /dev/null differ diff --git a/packages/Iesi.Collections.4.0.4/.signature.p7s b/packages/Iesi.Collections.4.0.4/.signature.p7s deleted file mode 100644 index fa0159dfa..000000000 Binary files a/packages/Iesi.Collections.4.0.4/.signature.p7s and /dev/null differ diff --git a/packages/Iesi.Collections.4.0.4/Iesi.Collections.4.0.4.nupkg b/packages/Iesi.Collections.4.0.4/Iesi.Collections.4.0.4.nupkg deleted file mode 100644 index 03c3a7879..000000000 Binary files a/packages/Iesi.Collections.4.0.4/Iesi.Collections.4.0.4.nupkg and /dev/null differ diff --git a/packages/Iesi.Collections.4.0.4/lib/net40/Iesi.Collections.dll b/packages/Iesi.Collections.4.0.4/lib/net40/Iesi.Collections.dll deleted file mode 100644 index 09c113639..000000000 Binary files a/packages/Iesi.Collections.4.0.4/lib/net40/Iesi.Collections.dll and /dev/null differ diff --git a/packages/Iesi.Collections.4.0.4/lib/net461/Iesi.Collections.dll b/packages/Iesi.Collections.4.0.4/lib/net461/Iesi.Collections.dll deleted file mode 100644 index c35d072fd..000000000 Binary files a/packages/Iesi.Collections.4.0.4/lib/net461/Iesi.Collections.dll and /dev/null differ diff --git a/packages/Iesi.Collections.4.0.4/lib/netstandard1.0/Iesi.Collections.dll b/packages/Iesi.Collections.4.0.4/lib/netstandard1.0/Iesi.Collections.dll deleted file mode 100644 index 4b4636376..000000000 Binary files a/packages/Iesi.Collections.4.0.4/lib/netstandard1.0/Iesi.Collections.dll and /dev/null differ diff --git a/packages/Iesi.Collections.4.0.4/lib/netstandard1.3/Iesi.Collections.dll b/packages/Iesi.Collections.4.0.4/lib/netstandard1.3/Iesi.Collections.dll deleted file mode 100644 index 4c21085cd..000000000 Binary files a/packages/Iesi.Collections.4.0.4/lib/netstandard1.3/Iesi.Collections.dll and /dev/null differ diff --git a/packages/NHibernate.5.5.2/.signature.p7s b/packages/NHibernate.5.5.2/.signature.p7s deleted file mode 100644 index 06405fb2d..000000000 Binary files a/packages/NHibernate.5.5.2/.signature.p7s and /dev/null differ diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/FireBird.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/FireBird.cfg.xml deleted file mode 100644 index 9e3c8e429..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/FireBird.cfg.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - NHibernate.Driver.FirebirdClientDriver - - DataSource=localhost; - Database=nhibernate; - User ID=SYSDBA;Password=masterkey; - MaxPoolSize=200; - charset=utf8; - - false - NHibernate.Dialect.FirebirdDialect - 60 - true 1, false 0, yes 1, no 0 - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/HANA.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/HANA.cfg.xml deleted file mode 100644 index f21314961..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/HANA.cfg.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - NHibernate.Driver.HanaColumnStoreDriver - - - Server=localhost:39015;UserID=nhibernate;Password=; - Enlist=false; - - NHibernate.Dialect.HanaColumnStoreDialect - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/MSSQL.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/MSSQL.cfg.xml deleted file mode 100644 index 8e5706a5c..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/MSSQL.cfg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - NHibernate.Driver.Sql2008ClientDriver - - Server=(local);initial catalog=nhibernate;Integrated Security=SSPI - - NHibernate.Dialect.MsSql2008Dialect - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/MySql.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/MySql.cfg.xml deleted file mode 100644 index 524deb631..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/MySql.cfg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - NHibernate.Driver.MySqlDataDriver - - Database=nhibernate;Data Source=localhost;User Id=nhibernate;Password=; - Old Guids=True; - - NHibernate.Dialect.MySQL5Dialect - - \ No newline at end of file diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/Oracle-Managed.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/Oracle-Managed.cfg.xml deleted file mode 100644 index efa6b51a5..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/Oracle-Managed.cfg.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - NHibernate.Driver.OracleManagedDataClientDriver - - User ID=nhibernate;Password=nhibernate;Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = ORCL))) - - false - NHibernate.Dialect.Oracle10gDialect - true 1, false 0, yes 'Y', no 'N' - - false - - - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/Oracle.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/Oracle.cfg.xml deleted file mode 100644 index 790f06f9c..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/Oracle.cfg.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - NHibernate.Driver.OracleClientDriver - - User ID=nhibernate;Password=nhibernate;Data Source=localhost - - false - NHibernate.Dialect.OracleDialect - true 1, false 0, yes 'Y', no 'N' - - false - - - - \ No newline at end of file diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/PostgreSQL.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/PostgreSQL.cfg.xml deleted file mode 100644 index 459543f2b..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/PostgreSQL.cfg.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - NHibernate.Driver.NpgsqlDriver - - Server=localhost;Database=nhibernate;User ID=nhibernate;Password=nhibernate;Enlist=true; - - NHibernate.Dialect.PostgreSQL83Dialect - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/SQLite.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/SQLite.cfg.xml deleted file mode 100644 index 50890aea5..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/SQLite.cfg.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - NHibernate.Driver.SQLite20Driver - - - Data Source=nhibernate.db; - DateTimeFormatString=yyyy-MM-dd HH:mm:ss.FFFFFFF; - - NHibernate.Dialect.SQLiteDialect - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/SapSQLAnywhere.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/SapSQLAnywhere.cfg.xml deleted file mode 100644 index 1ce5a50bb..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/SapSQLAnywhere.cfg.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - NHibernate.Driver.SapSQLAnywhere17Driver - - - UID=DBA;PWD=sql;Server=localhost;DBN=nhibernate;DBF=c:\nhibernate.db;ASTOP=No;Enlist=false; - - NHibernate.Dialect.SapSQLAnywhere17Dialect - true=1;false=0 - - diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/SqlServerCe.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/SqlServerCe.cfg.xml deleted file mode 100644 index c3b27bfda..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/SqlServerCe.cfg.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - 0 - NHibernate.Driver.SqlServerCeDriver - - Data Source=NHibernate.sdf - - NHibernate.Dialect.MsSqlCe40Dialect - - \ No newline at end of file diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/SybaseASE.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/SybaseASE.cfg.xml deleted file mode 100644 index 4f722b1f0..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/SybaseASE.cfg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - NHibernate.Driver.SybaseAseClientDriver - - Data Source=10.0.0.1;Port=5000;Database=nhibernate;User ID=nhibernate;Password=password - - NHibernate.Dialect.SybaseASE15Dialect - true=1;false=0 - - \ No newline at end of file diff --git a/packages/NHibernate.5.5.2/ConfigurationTemplates/SybaseSQLAnywhere.cfg.xml b/packages/NHibernate.5.5.2/ConfigurationTemplates/SybaseSQLAnywhere.cfg.xml deleted file mode 100644 index 04a929b7b..000000000 --- a/packages/NHibernate.5.5.2/ConfigurationTemplates/SybaseSQLAnywhere.cfg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - NHibernate.Driver.SybaseSQLAnywhereDriver - - UID=DBA;PWD=sql;Server=localhost;DBN=nhibernate;DBF=c:\nhibernate.db;ASTOP=No - - NHibernate.Dialect.SybaseSQLAnywhere12Dialect - true=1;false=0 - - \ No newline at end of file diff --git a/packages/NHibernate.5.5.2/NHibernate-NuGet.png b/packages/NHibernate.5.5.2/NHibernate-NuGet.png deleted file mode 100644 index 8a4a59048..000000000 Binary files a/packages/NHibernate.5.5.2/NHibernate-NuGet.png and /dev/null differ diff --git a/packages/NHibernate.5.5.2/NHibernate.5.5.2.nupkg b/packages/NHibernate.5.5.2/NHibernate.5.5.2.nupkg deleted file mode 100644 index b31ae0c9a..000000000 Binary files a/packages/NHibernate.5.5.2/NHibernate.5.5.2.nupkg and /dev/null differ diff --git a/packages/NHibernate.5.5.2/NHibernate.license.txt b/packages/NHibernate.5.5.2/NHibernate.license.txt deleted file mode 100644 index 866688dba..000000000 --- a/packages/NHibernate.5.5.2/NHibernate.license.txt +++ /dev/null @@ -1,460 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - diff --git a/packages/NHibernate.5.5.2/NHibernate.readme.md b/packages/NHibernate.5.5.2/NHibernate.readme.md deleted file mode 100644 index 6290ebbaa..000000000 --- a/packages/NHibernate.5.5.2/NHibernate.readme.md +++ /dev/null @@ -1,116 +0,0 @@ -Welcome to NHibernate -===================== - -NHibernate is a mature, open source object-relational mapper for the .NET framework. It is actively developed, -fully featured and used in thousands of successful projects. - -The NHibernate community website - - has a range of resources to help you get started, -including [howtos][A1], [blogs][A2] and [reference documentation][A3]. - -[A1]: https://nhibernate.info/doc/ -[A2]: https://nhibernate.info/blog/ -[A3]: https://nhibernate.info/doc/nh/en/index.html - -Latest Release Version --------------- - -The quickest way to get the latest release of NHibernate is to add it to your project using -NuGet (). - -Alternatively binaries are available from SourceForge at . - -You are encouraged to review the release notes ([releasenotes.txt](releasenotes.txt)), particularly when upgrading to a -later version. The release notes will generally document any breaking changes. - -Nightly Development Builds --------------------------- - -The quickest way to get the latest development build of NHibernate is to add it to your project using -NuGet from Cloudsmith feed (). - -In order to make life a little bit easier you can register the package source in the NuGet.Config -file in the top folder of your project, similar to the following. - -```xml - - - - - - -``` - -Package repository hosting is graciously provided by [Cloudsmith](https://cloudsmith.com). -Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that -enables your organization to create, store and share packages in any format, to any place, with total -confidence. - -[![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=flat-square)](https://cloudsmith.com) - -Community Forums ----------------- - -There are two official NHibernate community forums: - -* [NHibernate Users][B1] - a forum for users to find help using NHibernate -* [NHibernate Development][B2] - a forum for the developers of NHibernate - -[B1]: http://groups.google.com/group/nhusers -[B2]: http://groups.google.com/group/nhibernate-development - -Bug Reports ------------ - -If you find any bugs, please report them using the [GitHub issue tracker][C1]. A -test-case that demonstrates the issue is usually required. Instructions on providing a test-case -can be found in [contributing guidelines][C3] or [here][C2]. - -[C1]: https://github.com/nhibernate/nhibernate-core/issues -[C2]: https://nhibernate.info/blog/2008/10/04/the-best-way-to-solve-nhibernate-bugs-submit-good-unit-test.html -[C3]: CONTRIBUTING.md - -Licenses --------- - -- This software is distributed under the terms of the Free Software Foundation [Lesser GNU Public License (LGPL), version 2.1][D1] (see [LICENSE.txt][D2]). -- The documentation for this software is distributed under the terms of the Free Software Foundation [GNU Free Documentation License (GNU FDL), version 1.1][D3] (see [doc/LICENSE.txt][D4]). - -[D1]: http://www.gnu.org/licenses/lgpl-2.1-standalone.html -[D2]: LICENSE.txt -[D3]: http://www.gnu.org/licenses/old-licenses/fdl-1.1-standalone.html -[D4]: doc/LICENSE.txt - -Credits -------- - -Many thanks to the following individuals, organisations and projects whose work is so important to the success -of NHibernate (in no particular order): - -* [NUnit][] - unit-testing -* [Nant][] - build automation -* [CodeBetter][] - [TeamCity][] continuous integration and build management server hosting -* [GitHub][] and [SourceForge][] - source code hosting -* [Atlassian][] - JIRA bug tracker licence and hosting -* [Log4net][] - logging, by the [Apache Software Foundation][] -* [JetBrains][] - [ReSharper][] licences for NHibernate developers -* [LinFu][] - proxy implementation (Philip Laureano) -* Iesi.Collections - source code taken from an [article][] written by Jason Smith -* [Relinq][] - Linq provider for NHibernate -* [AsyncGenerator][] - Roslyn based async C# code generator by @maca88 - - -[NUnit]: http://www.nunit.org -[Nant]: http://nant.sourceforge.net -[CodeBetter]: http://www.codebetter.com -[TeamCity]: http://www.jetbrains.com/teamcity -[GitHub]: http://www.github.com -[SourceForge]: http://www.sourceforge.net -[Atlassian]: http://www.atlassian.com -[Log4net]: http://logging.apache.org/log4net -[Apache Software Foundation]: http://www.apache.org -[JetBrains]: http://www.jetbrains.com -[ReSharper]: http://www.jetbrains.com/resharper -[LinFu]: https://github.com/philiplaureano/LinFu -[article]: http://www.codeproject.com/KB/recipes/sets.aspx -[Relinq]: https://github.com/re-motion/Relinq -[AsyncGenerator]: http://github.com/maca88/AsyncGenerator diff --git a/packages/NHibernate.5.5.2/NHibernate.releasenotes.txt b/packages/NHibernate.5.5.2/NHibernate.releasenotes.txt deleted file mode 100644 index 024a2a306..000000000 --- a/packages/NHibernate.5.5.2/NHibernate.releasenotes.txt +++ /dev/null @@ -1,5495 +0,0 @@ -Build 5.5.2 -============================= - -Release notes - NHibernate - Version 5.5.2 - -3 issues were resolved in this release, including CVE CVE-2024-39677 through the merge of 5.4.9. - -** Bug - - * #3536 MemberwiseClone should be virtual error in dotnet 9 preview 3 - -** Task - - * #3578 Release 5.5.1 - * #3577 Merge 5.4.9 into 5.5.x - - -Build 5.5.1 -============================= - -Release notes - NHibernate - Version 5.5.1 - -3 issues were resolved in this release. - -** Bug - - * #3465 Invalid SQL created for some joins in a subquery - -** Task - - * #3509 Release 5.5.1 - * #3508 Merge 5.4.8 into 5.5.x - - -Build 5.5.0 -============================= - -Release notes - NHibernate - Version 5.5.0 - - ##### Possible Breaking Changes ##### - * `Object.Finalize` is no more proxified when the entity base class has a destructor. See #3205. - * Default not-found behavior now works correctly on many-to-many Criteria fetch. It now throws - ObjectNotFoundException exception for not found records. See #2687. - -62 issues were resolved in this release. - -** Bug - - * #3413 Downgrade dependency System.Data.SQLite.Core 1.0.118 -> 1.0.117 - * #3406 Fix orphan removal for detached one-to-one - * #3392 Partial fix fetching lazy property after Select in Linq - * #3360 Incorrect parameter length for char types in MicrosoftDataSqlClientDriver - * #3334 Exception executing HQL query with uncorrelated left joins in subselect - * #3327 HqlParser does not correctly negate EXISTS-nodes below an AND/OR - * #3325 Cascading orphan delete may not work on versioned entity - * #3311 NamedQuery ignores and any other - * #3264 Fix collection filter on subclass columns - * #3256 Invalid SQL is generated for string Enum used in conditional LINQ - * #3205 `Object.Finalize` should not be proxiable - * #2687 Use table group joins for many-to-many in Criteria and Entity loaders - * #1267 NH-3047 - Lazy=no-proxy ignores join fetch - -** New Feature - - * #3242 Linq: add enum Equals and object Equals support - * #3165 Add support for Firebird 4 - * #829 NH-3365 - Support for HasFlag method for enums with Flags attribute applied - -** Improvement - - * #3429 Explicit how to use advanced Redis strategies - * #3410 Remove redundant collection BeforeAssemble call from query cache - * #3398 Do not store mapping field in Configuration - * #3396 Get rid of select queries for each ManyToMany not found ignored element in Criteria and lazy loading - * #3395 Remove ConstantConverter - * #3394 Get rid of select queries for each ManyToMany not found ignored element in hql - * #3390 Enable Not node handling in HqlParser.NegateNode - * #3384 Improve path rule handling with reserved words in Hql.g - * #3377 Move HqlToken.PossibleId to HqlParser.IsPossibleId method and remove castings - * #3374 Simplify aggregateDistinctAll rule in Hql.g - * #3373 Refactor sequential select related members in AbstractEntityPersister - * #3341 Apply fromFragment processing only when required in ProcessDynamicFilterParameters - * #3340 SqlString.Trim should return the same instance for not modified string - * #3253 Do not throw for unknown type in hql case node - * #3230 Add cached boxed boolean values to BooleanType - * #3209 Allow custom query loader - -** Task - - * #3460 Merge 5.4.7 in master - * #3445 Release 5.5.0 - * #3440 Update NUnit to v3.14.0 - * #3423 Update actions/checkout action to v4 - * #3420 Merge 5.4.6 in master - * #3411 Remove ISessionFactoryImplementor parameter from TableGroupJoinHelper - * #3409 Merge 5.4.5 in master - * #3387 Merge 5.4.4 in master - * #3379 Remove NHibernate.Example.Web project - * #3362 Update dependency NUnit3TestAdapter to v4.5.0 - * #3361 Update dependency NUnit.Console to v3.16.3 - * #3353 Migrate renovate config - * #3351 Merge 5.4.3 in master - * #3284 Update NHibernate.Caches to v5.9.0 - * #3283 Update dependency NSubstitute to v5 - * #3280 Add tests for Microsoft.Data.SqlClient driver - * #3275 Migrate dev packages to Cloudsmith - * #3241 Exclude generated files from Deepsource analisys - * #3236 Add MySQL8Dialect and MySQL8InnoDBDialect - * #3223 Simplify GitHub Actions Tests DB initialization - * #3206 Update actions/setup-dotnet action to v3 - * #3202 Update dependency Npgsql to v7 - * #3129 [Security] Update Oracle.ManagedDataAccess - * #3122 Update dependency FirebirdSql.Data.FirebirdClient to v9 - * #3102 Update dependency Microsoft.Data.SqlClient to v3.1.3 - * #3099 [Security] Update dependency System.Linq.Dynamic.Core to v1.3.3 - * #3098 Update dependency System.Data.SQLite.Core to v1.0.118 - * #3092 Update dependency Microsoft.AspNetCore.OData to v7.7.0 - * #3088 Update NUnit to v3.13.3 - -** Tests - - * #3412 Revive hql ParsingFixture - - -Build 5.4.9 -============================= - -Release notes - NHibernate - Version 5.4.9 - -6 issues were resolved in this release, including CVE-2024-39677. - -** Bug - - * #3547 Handle SQL injection vulnerabilities within ObjectToSQLString - -** Task - - * #3576 Release 5.4.9 - * #3558 Migrate AppVeyor & TC builds to PostgreSQL 13 - * #3545 Upgrade Npgsql to a non vulnerable version - * #3544 Upgrade vulnerable test dependencies - * #3517 Obsolete vulnerable literal AddColumn - - -Build 5.4.8 -============================= - -Release notes - NHibernate - Version 5.4.8 - -2 issues were resolved in this release. - -** Bug - - * #3489 Inserting multiple associations of the same entity fails - -** Task - - * #3507 Release 5.4.8 - - -Build 5.4.7 -============================= - -Release notes - NHibernate - Version 5.4.7 - -3 issues were resolved in this release. - -** Task - - * #3459 Release 5.4.7 - * #3458 Merge 5.3.20 into 5.4.x - * #3453 Migrate appveyor build to MySql 8 - - -Build 5.4.6 -============================= - -Release notes - NHibernate - Version 5.4.6 - -2 issues were resolved in this release. - -** Bug - - * #3414 Reenable use of SelectClauseVisitor for subqueries - -** Task - - * #3419 Release 5.4.6 - - -Build 5.4.5 -============================= - -Release notes - NHibernate - Version 5.4.5 - -2 issues were resolved in this release. - -** Task - - * #3408 Release 5.4.5 - * #3407 Merge 5.3.19 in 5.4.x - - -Build 5.4.4 -============================= - -Release notes - NHibernate - Version 5.4.4 - -6 issues were resolved in this release. - -** Bug - - * #3359 2nd level cache GetMany ineffective for collections - * #3354 Invalid program generated by FieldInterceptorProxyBuilder for indexer property getter - * #3352 Fetch throws "could not resolve property" error for a property that is not mapped - -** Improvement - - * #3368 Allow internal entity classes/interfaces in .NET Standard 2.0 for field interceptor - -** Task - - * #3386 Release 5.4.4 - * #3367 Update readme with actual dev build information for 5.4 - - -Build 5.4.3 -============================= - -Release notes - NHibernate - Version 5.4.3 - -11 issues were resolved in this release. - -** Bug - - * #3317 Issue with components list lazy loading with not lazy association - * #3307 IsDirty performance hit since 5.4.0 - * #3295 C# 8/11 Static interface members support - * #3291 Npgsql 6+ issues with null DateTime parameter types - * #3290 Incorrect fetch of Many-to-Many relation - * #3289 Fetching lazy loaded component causes n + 1 query when querying a subclass abstraction - * #3288 NullReferenceException is thrown when using Fetch - -** Task - - * #3349 Release 5.4.3 - * #3348 Merge 5.3.18 in 5.4.x - * #3318 Merge 5.3.17 in 5.4.x - * #3302 Upgrade NUnit3TestAdapter to fix "Unknown framework version 7.0" - - -Build 5.4.2 -============================= - -Release notes - NHibernate - Version 5.4.2 - -6 issues were resolved in this release. - -** Bug - - * #3274 Improve LINQ Contains subquery parameter detection - * #3271 LINQ subqueries wrongly altered by SelectClauseVisitor - * #3263 Wrong alias in Where clause if using Fetch and scalar Select - * #3239 Incorrect SQL generated fetching many-to-many with subclasses - -** New Feature - - * #3251 MappingByCode: Support backfield property access - -** Task - - * #3281 Merge 5.3.16 in 5.4.x - * #3277 Release 5.4.2 - - -Build 5.4.1 -============================= - -Release notes - NHibernate - Version 5.4.1 - -5 issues were resolved in this release. - -** Bug - - * #3216 Enable one-to-one optimistic lock handling in mapping - * #3215 Count(Distinct ...) does not work - * #3203 Fix a wrong example in configuration documentation - -** Task - - * #3232 Release 5.4.1 - * #3227 Merge 5.3.15 in 5.4.x - -As part of releasing 5.4.1, a missing 5.4.0 possible breaking change has been added, about -one-to-one associations and optimistic locking. See 5.4.0 possible breaking changes. - - -Build 5.4.0 -============================= - -Release notes - NHibernate - Version 5.4.0 - -** Highlights - * NHibernate has gained three new target frameworks: .Net 6, .Net Framework 4.8 and .Net Standard 2.1. NHibernate NuGet package - provides them, along with the older targets, .Net Core 2.0, .Net Framework 4.6.1 and .Net Standard 2.0. These new targets allow - some NHibernate optimizations for applications using them. The same limitations apply for .Net 6 and .Net Standard 2.1 as for - .Net Core 2.0 and .Net Standard 2.0, see NHibernate 5.1.0 release notes. - * A new batching strategy is available, minimizing the batching memory footprint. See #2959. Using it may increase CPU usage. - * 201 issues were resolved in this release. - - ##### Possible Breaking Changes ##### - * One-to-one changes does now trigger a version increment, consistently with the default behavior of other kinds of - associations. See #3204. - * Linq and criteria queries on unmapped entities will throw instead of returning an empty result list. See #1106, #1095. - * The second level cache UpdateTimestampsCache does not use locks anymore. This may slightly increase the number of cases - where stale data is returned by the query cache. See #2742. - * Equality and hashcode access on uninitialized persistent collections will no more trigger their loading. See #2461. - * DB2CoreDriver now uses named parameters instead of positional ones. See #2546. - -** Bug - - * #3198 EntityUpdateAction increments version despite veto on update - * #3189 Support proxies of classes with init properties - * #3188 No way of detecting if AutoFlush performed in added AutoFlushEventListener - * #3176 Cached entity always fetches lazy properties with read-write concurrency strategy - * #3156 Evaluation failure when using `Nullable` without a value in LINQ - * #3150 LINQ query dynamic component by interface hangs the application - * #3109 Fix table group join issue with subclasses - * #3104 Inner Join fails with left Outer Join when referenced in Where clause - * #3076 Nested group by results in "A recognition error occured" - * #2968 Fix QueryStatistics.ExecutionAvgTime calculation - * #2827 Fix BadImageFormatException in dynamic proxies for abstract classes and interfaces - * #2822 "A recognition error ocurred" querying by a nullable component with more than N properties - * #2758 Fix AmbiguousMatchException in ClearPool with FirebirdClient 6.6.0 and above - * #2750 Using System.Transaction with IStatelessSession doesn't always flush batches to database - * #2738 Unused Left Join in LINQ throws exception - * #2717 MappingByCode discriminator column with string type throws exception - * #2675 Fix collection lazy loading with composite keys on subclass columns - * #2672 Linq query failure with left joins - * #2619 InvalidOperationException in ProxyGenerator for class with generic non-virtual method - * #2614 Obvious bug in two HQLQueryPlan classes with distinction Set - * #2594 Wrong SQL produced by DML LINQ when using a select clause for a property referencing the outer select - * #2555 Add spaces around concat operator - * #2552 One-to-one second level cache issue - * #2548 Mark DB2Dialect as not supporting null columns in unique constraint - * #2547 Fix paging in DB2Dialect - * #2540 Unable to use external predicate in subquery - * #2534 Fix asymmetrical SqlType.Equals - * #2454 ConditionalProjection containing the correlation to outer query fails to determine projection type - * #2330 join on multiple conditions - * #2201 Fetch Join generates incorrect SQL joins for the same entity type - * #2092 Projection and join fetch in hql leads to duplicated column aliases - * #1365 NH-3288 - Stale data checking does not work for one-to-one associations - * #1349 NH-3893 - HQL parse error of a query with 'left' or 'right' function - * #1326 NH-3622 - Fetching in query causes incorrect/missing joins in subquery - * #1316 NH-3530 - memory when using default_batch_fetch_size - * #1235 NH-2785 - StaleStateExceptions discarded on optional table - * #1215 NH-2208 - Error with filters on joined-subclass as many-to-one - * #1209 NH-2049 - Error with filters on joined-subclass as one-to-one - * #1180 NH-3847 - ConditionalProjection throws "Both true and false projections must return the same types" when the types are the same - * #1106 NH-2978 - LINQ: Queries for unmapped entity types return empty result set - * #1075 NH-2239 - Wrong OrderBy in generated SQL when using ICriteria, Eager fetching and order by clauses in collection mappings - * #1072 NH-2174 - Invalid SQL is generated for OneToMany collections - * #1062 NH-1893 - Trigger-Identity with Dynamic Insert throws ORA-01036 (10g) - -** New Feature - - * #2959 Support Dynamic BatchFetchStyle - * #2744 Set which entities classes should never be cached, even indirectly - * #2737 Add more left join support - * #2645 Allow specifying the size of the query plan cache - * #2641 Avoid InvalidCastException with Oracle number high precision values - * #2551 Add support for joining a subquery in hql - * #2545 Table group joins for subclasses in Criteria - * #2486 Add Projections.Select in Criteria - * #2361 Table group joins support in hql - -** Improvement - - * #3184 Support caching queries with autodiscovered types - * #3177 Disable default caching in tests - * #3160 Allow internal entity classess/interfaces in .NET Standard 2.0 - * #3133 Automatically generate async code on pull request - * #3127 Register IType CLR types as aliases - * #3116 Simplify SqlGenerator.FromFragmentSeparator - * #3114 Exclude generated async files from Deepsource analysis - * #3106 Skip table group join processing for implicit join - * #3091 Use GitReleaseManager dotnet tool - * #3083 Update SHFB in order to build documentation without MSBuild - * #3050 Add .NET Standard 2.1 target - * #3027 Avoid allocations on lock in SyncCacheLock - * #3000 Add .NET 6 and .NET Framework 4.8 targets - * #2990 Use inner join instead of implicit join for implied entity joins - * #2957 Avoid lambda compilation as much as possible - * #2948 Avoid lambda compilation for member access expressions in LINQ - * #2947 LINQ queries triggers JIT a bit too much - * #2920 Add parameter type to ADO exception - * #2804 Projections.Conditional for CASE expressions with multiple conditions - * #2752 Change cascade style for DefaultDirtyCheckEventListener to persist to avoid flushing the session - * #2742 Remove locks from UpdateTimestampsCache - * #2723 Avoid double param type guessing and better NULL parameter handling in LINQ - * #2706 Set the rolledBack flag when disposing active transactions - * #2700 Potential improvement to AliasToBeanResultTransformer - * #2621 Regression bug with enums used as parameter for string column - * #2571 Default value for CancellationToken in IQueryBatch.GetResultAsync - * #2568 Support internal entity classes by proxy factory - * #2556 Register right function for Firebird and PostgreSQL - * #2546 Enable named parameters on DB2CoreDriver - * #2539 Skip no longer needed moving ON condition to Where clause in LINQ - * #2538 Remove no longer needed alias substitution for filtered many-to-many collection in hql - * #2518 Support Aggregate subqueries with paging on MS SQL Server - * #2510 Remove OrderByClause from query models with Contains, All and Any result operators - * #2492 Replace casting with NodeType checks in Criteria ExpressionProcessor - * #2479 When using a paged sub-query in Linq, generates incorrect SQL - * #2461 Remove persistent collections Equals/GetHashCode overrides - * #2460 Simplify single alias retrieval for SimpleProjections - * #2448 Avoid lambda compilation for constant and member access expressions in Criteria - * #1285 NH-3249 - Cannot perform HQL with "COUNT(DISTINCT Date(s.Date))" - * #1244 NH-2868 - Generate method of ForeignGenerator fails with stateless sessions - * #1095 NH-2829 - QueryOver/Criteria should throw exception when querying against unmapped class - * #871 NH-3115 - Should de-duplicate joins when using fetching with where in LINQ query - * #869 NH-2952 - Setting the SqlCheck is not supported in the ByCode mapping - * #809 NH-2799 - Provide the CancelQuery() method in IStatelessSession - * #766 NH-3813 - Eager fetch on key-many-to-one relation adds inner joins to the query - * #715 NH-1040 - property-ref on joined-subclasses should work or error - -** Task - - * #3197 Update dependency System.Data.SqlClient to v4.8.5 - * #3195 Release NHibernate 5.4 - * #3161 Tell NuGet about the readme file - * #3147 Add `datetimex` keyword to SapSQLAnywhere17Dialect - * #3146 Run tests against Oracle XE 21c - * #3123 Update dependency Npgsql to v6 - * #3121 Update dependency Microsoft.NETFramework.ReferenceAssemblies to v1.0.3 - * #3119 Update actions/setup-dotnet action to v2 - * #3118 Update actions/checkout action to v3 - * #3117 Update dependency NSubstitute to v4.4.0 - * #3111 Update dependency log4net to v2.0.15 - * #3080 Replace Dependabot with Renovate - * #3063 Bump Oracle.ManagedDataAccess from 19.12.0 to 21.6.1 - * #3061 Bump Oracle.ManagedDataAccess.Core from 2.19.120 to 3.21.61 - * #3059 Bump log4net from 2.0.12 to 2.0.14 - * #3057 Run tests using .NET 4.8 - * #3017 Add deepsource.io code analysis - * #3002 Bump NUnit3TestAdapter from 4.1.0 to 4.2.1 - * #2987 Disable auto rebasing for depandabot PRs - * #2951 Run tests on .NET 6 - * #2946 Bump Microsoft.SourceLink.GitHub from 1.0.0 to 1.1.1 - * #2936 Bump System.Data.SQLite.Core from 1.0.114.3 to 1.0.115.5 - * #2911 Bump System.Data.SqlClient from 4.8.2 to 4.8.3 - * #2898 Bump FirebirdSql.Data.FirebirdClient from 6.6.0 to 8.5.2 - * #2887 Bump Oracle.ManagedDataAccess from 19.11.0 to 19.12.0 - * #2886 Bump Oracle.ManagedDataAccess.Core from 2.19.110 to 2.19.120 - * #2878 Bump System.Linq.Dynamic.Core from 1.2.10 to 1.2.12 - * #2870 Bump MySql.Data from 8.0.25 to 8.0.26 - * #2851 Cache Dialect in tests - * #2818 Bump Microsoft.Data.SqlClient from 2.1.3 to 3.0.0 - * #2800 Bump System.Data.SQLite.Core from 1.0.113.7 to 1.0.114.2 - * #2799 Bump Npgsql from 4.0.3 to 4.1.9 - * #2796 Bump System.Linq.Dynamic.Core from 1.2.9 to 1.2.10 - * #2790 Bump Microsoft.NET.Test.Sdk from 16.9.4 to 16.10.0 - * #2786 Bump Microsoft.Data.SqlClient from 2.1.2 to 2.1.3 - * #2771 Bump MySql.Data from 8.0.22 to 8.0.25 - * #2770 Bump System.Data.SQLite.Core from 1.0.109.2 to 1.0.113.7 - * #2765 Bump Microsoft.NETFramework.ReferenceAssemblies from 1.0.0 to 1.0.2 - * #2759 Enable dependabot - * #2756 Update dependencies - * #2607 Merge 5.3.5 - * #2605 Upgrade AsyncGenerator to 0.19.1 - * #2593 Merge 5.3.4 - * #2582 Remove no longer used code in QueryModelVisitor - * #2570 Update Relinq and LinFu links - * #2516 Suppress Codefactor single class per file rule for test project - * #2501 Upgrade MySql client and remove allowed failures on CI builds - -** Tests - - * #3024 Enable test accessing Component's Parent property in LINQ - * #2921 Fix test for SAP SQL Anywhere - * #2848 Add Oracle to GitHub Actions - * #2541 LINQ SELECT tests with WHERE subquery - * #2489 Improve CriteriaAssertFixture - * #2456 Test case for #1180 and improve NullableType.ToString - * #2242 Test case for NH-3972 - SQL error when selecting a column of a subclass when sibling classes have a column of the same name - - -Build 5.3.20 -============================= - -Release notes - NHibernate - Version 5.3.20 - -2 issues were resolved in this release. - -** Bug - - * #3438 DB2/400: ArgumentException Column 'SQL_TYPE_NAME' does not belong to table DataTypes - -** Task - - * #3454 Release 5.3.20 - - -Build 5.3.19 -============================= - -Release notes - NHibernate - Version 5.3.19 - -2 issues were resolved in this release. - -** Bug - - * #3397 GenerateSchemaCreationScript creates many identical dialect instances - -** Task - - * #3405 Release 5.3.19 - - -Build 5.3.18 -============================= - -Release notes - NHibernate - Version 5.3.18 - -3 issues were resolved in this release. - -** Bug - - * #3333 Lazy property with nosetter accessor remains uninitialized - * #3330 Linq with FetchLazyProperties() resets lazy property changes - -** Task - - * #3346 Release 5.3.18 - - -Build 5.3.17 -============================= - -Release notes - NHibernate - Version 5.3.17 - -5 issues were resolved in this release. - -** Bug - - * #3306 Invalid SQL when referencing nullable entity in correlated subquery - * #3304 Fix SetSnapShot CopyTo variance failure - * #3294 Undefined join type failure with cross joins and Informix - -** Task - - * #3315 Release 5.3.17 - * #3300 Backport handling of null DateTime parameters in Npgsql 6+ - - -Build 5.3.16 -============================= - -Release notes - NHibernate - Version 5.3.16 - -3 issues were resolved in this release. - -** Bug - - * #3269 "Or" clause in a "where" condition returns a wrong result with not-found-ignore - * #3210 Wrong name value for L2 read-only cache warning on mutable - -** Task - - * #3276 Release 5.3.16 - - -Build 5.3.15 -============================= - -Release notes - NHibernate - Version 5.3.15 - -4 issues were resolved in this release. - -** Bug - - * #3218 Failure of contains subquery with parameter - * #3187 Fix mixing implied implicit and left joins in HQL for v5.3 - -** Task - - * #3225 Release 5.3.15 - * #3222 Automatically generate async code on pull requests for 5.3 - - -Build 5.3.14 -============================= - -Release notes - NHibernate - Version 5.3.14 - -3 issues were resolved in this release. - -** Bug - - * #3169 InvalidOperationException: This transformer is not initialized by Cached Query - * #3164 Fetching a lazy loaded component regression - -** Task - - * #3183 Release 5.3.14 - - -Build 5.3.13 -============================= - -Release notes - NHibernate - Version 5.3.13 - -6 issues were resolved in this release. - -** Bug - - * #3134 ManyToMany - Tries to select not existing column in Mapping Table - * #3113 Join fails on Oracle9Dialect - * #3030 Memory leak named parameter holds entity references - -** Improvement - - * #3120 Guards against use of a disposed session factory - * #2994 Npgsql 6 is not compatible - -** Task - - * #3145 Release 5.3.13 - - -Build 5.3.12 -============================= - -Release notes - NHibernate - Version 5.3.12 - -5 issues were resolved in this release. - -** Bug - - * #3046 Regression for filters on entity joins with many-to-one disabled - * #3029 InvalidOperationException on proxies with explicit implementation of a generic method - -** Improvement - - * #3043 Improve exception for query on delayed id - -** Test - - * #3035 Support tests in VS 2022 - -** Task - - * #3044 Release 5.3.12 - -Build 5.3.11 -============================= - -Release notes - NHibernate - Version 5.3.11 - -12 issues were resolved in this release. - -** Bug - - * #3005 LINQ: Casting from object to TimeSpan throws - * #2988 Query issues when using not-found='ignore' in entity mapping - * #2965 Fix possible issue with logging for Linq Readonly tests - * #2963 Time is incompatible with bigint for TimeAsTimeSpanType - * #2937 NRE in linq processing of custom components - * #2928 Session.Refresh when entity is IFieldInterceptorAccessor throws a MappingException - * #2904 SQL query result not retrieved from second level cache - * #2876 Schema validation not working with NpgSql v5 - * #2862 NHibernate AsyncReaderWriterLock stalls under load - * #2727 The session.Load(obj, id) overload can't handle proxies - -** Task - - * #3019 Release 5.3.11 - * #2984 Bump AsyncGenerator to 0.18.3 for 5.3 branch with fix for .net 6 - -Build 5.3.10 -============================= - -Release notes - NHibernate - Version 5.3.10 - -11 issues were resolved in this release. - -** Bug - - * #2891 Fix nullable entity comparison with null and implicit/cross joins - * #2885 Do not serialize unnecessary members in SessionFactory - * #2882 Fix ArgumentNullException when provider is unable to open a connection - * #2871 If DbTransaction.Dispose throws an exception, the AdoTransaction is left in an inconsistent state - * #2860 Null reference when calling Trim() on interpolated string containing null property - * #2858 Casting to object and back to interface in Subquery causes incorrect SQL - * #2856 Distinct on Composite User Type property fails - * #2855 Error log from ReflectHelper.TypeFromAssembly() on Linq query - * #2611 One-to-zero-or-one relation not returning data when checking for null - * #1962 Failing Linq query on element index - -** Task - - * #2915 Release 5.3.10 - -Build 5.3.9 -============================= - -Release notes - NHibernate - Version 5.3.9 - -11 issues were resolved in this release. - -** Bug - - * #2835 Fix ExecuteWorkInIsolation ignores MultiTenancy configuration - * #2811 Remove session finalizer - * #2805 Model not mapped Exception - * #2802 ArgumentException on session Flush - * #2792 Arithmetic operations adding casts to SQLite that cause incorrect results - * #2791 Custom Equality Fails - * #2772 LINQ query returns NULL instead of expected result - -** Test - - * #2841 Fix possible test failure for SqlServer 2019 - * #2814 Fix intermittent Firebird test errors - * #2812 Replace Travis CI with GitHub Actions - -** Task - - * #2837 Release 5.3.9 - -Build 5.3.8 -============================= - -Release notes - NHibernate - Version 5.3.8 - -6 issues were resolved in this release. - -** Bug - - * #2710 Filtered Entity Dml Update Throws Collection was modified - * #2708 MappedAs throws when called on a Convert UnaryExpression - * #2707 Don't currently support idents of type X - * #2673 Exception when using BinaryFormatter to deserialize entities with initialized proxies in associations - * #1264 NH-3005 - NHibernate.Hql.Ast.HqlIdent..ctor throws Don't currently support idents of type Date - -** Task - - * #2721 Release 5.3.8 - -Build 5.3.7 -============================= - -Release notes - NHibernate - Version 5.3.7 - -5 issues were resolved in this release. - -** Bug - - * #2704 IEnhancedUserType from string to bool fails in some circumstances - * #2702 LINQ projection of nullable enum with list fails - * #2693 Invalid parameter conversion with group by - * #2688 NoViableAltException in a delete on a many-to-one id - -** Task - - * #2701 Release 5.3.7 - -Build 5.3.6 -============================= - -Release notes - NHibernate - Version 5.3.6 - -12 issues were resolved in this release. - -** Bug - - * #2659 IQueryable filter by subquery gives "Item with Same Key has already been added" - * #2649 Invalid parameter conversion for enums mapped in sub-classes - * #2646 Invalid generated sql with linq any in select and composite keys - * #2642 Linq expression parser removes required Convert nodes - * #2631 IndexOutOfRange exception with One-to-One mapping - * #2627 Null reference on Merge for detached unsaved entity - * #2626 WHERE IN SELECT uses wrong column - * #2608 Delay entity insert may fail with Merge - * #2544 Recognition error occurs using System.Linq.Queryable.Contains - -** Improvement - - * #2677 Missing ConfigureAwait in FutureEnumerable.GetEnumerableAsync - * #2656 Make sure dbcommand is disposed - -** Task - - * #2676 Release 5.3.6 - -As part of releasing 5.3.6, one missing 5.3.0 possible breaking change has been added, about -Merge no more triggering immediate generation of identifier. See 5.3.0 possible breaking changes. - -Build 5.3.5 -============================= - -Release notes - NHibernate - Version 5.3.5 - -2 issues were resolved in this release. - -** Bug - - * #2599 WrongClassException in Linq query - -** Task - - * #2606 Release 5.3.5 - -Build 5.3.4 -============================= - -Release notes - NHibernate - Version 5.3.4 - -6 issues were resolved in this release. - -** Bug - - * #2580 InvalidWithClauseException when join polymorphic entity - * #2559 Regression in caching linq query with ThenFetchMany statement. - * #2549 ApplyFilter does not work on join statements in LINQ - * #2537 Unable to cast "System.Linq.Expressions.UnaryExpression" to "System.Linq.Expressions.LambdaExpression". - -** Task - - * #2578 Add missing possible breaking changes for #2365 - * #2587 Release 5.3.4 - -As part of releasing 5.3.4, one missing 5.3.0 possible breaking change has been added, about -custom method generators for Linq. See 5.3.0 possible breaking changes. - -Build 5.3.3 -============================= - -Release notes - NHibernate - Version 5.3.3 - -16 issues were resolved in this release. - -** Bug - - * #2519 Fix parameter caching for Linq provider - * #2515 InvalidCastException for Linq query with subquery - * #2514 Entity with field interceptor are not correctly passed as Linq parameters - * #2512 Linq queries with a condition after a projection on a collection fail - * #2511 Linq Fetch over component after fetching a many-to-one throws exception - * #2508 OnPreUpdateCollection - Passed entity instance X is not of expected type Y - * #2499 Cast operation fails when an enum is mapped as an AnsiString - * #2490 Unnecessary cast in sql with Linq are causing performance issues - * #2488 Fix parameter detection for Equals and CompareTo methods for Linq provider - * #2485 Throw entity not mapped exception for entity join in hql if possible - * #2484 Entity Joins are not polymorphic in hql - * #2476 Hashset add returns true instead of false - * #2474 Fetch all lazy properties when entity is already loaded fails - * #2471 AsQueryable() on collection throws if applied after Where statement - -** Task - - * #2482 Add missing possible breaking changes for #2010 - * #2527 Release 5.3.3 - -As part of releasing 5.3.3, two missing 5.3.0 possible breaking changes have been added, about -uninitialized extra lazy collections and SQLite schema validation. See 5.3.0 possible breaking changes. - -Build 5.3.2 -============================= - -Release notes - NHibernate - Version 5.3.2 - -6 issues were resolved in this release. - -** Bug - - * #2468 Null reference at NHibernate.Util.AsyncReaderWriterLock.ReadLock() - * #2465 Linq contains on a value collection is failing - * #2463 Path expected for join - * #2458 Evaluatable expressions with parameters are no more pre-evaluated - * #2453 Fail to cast enum as nvarchar for Linq Contains - -** Task - - * #2472 Release 5.3.2 - -Build 5.3.1 -============================= - -Release notes - NHibernate - Version 5.3.1 - -7 issues were resolved in this release. - -** Bug - - * #2445 LINQ queries with a cast from int to uint fail - * #2440 InvalidCastException for Future Criteria with aliased fetches - * #2439 Invalid parameter conversion for enums - * #2437 Invalid cast on nullable custom type with Linq - -** Task - - * #2450 Release 5.3.1 - * #2436 Fix old http://nhibernate.info URIs - * #2435 Fix iconUrl warning - -Build 5.3.0 -============================= - -Release notes - NHibernate - Version 5.3.0 - -220 issues were resolved in this release. - - ##### Possible Breaking Changes ##### - * A distributed cache may hold conflicting timestamps after upgrade for as much as twelve hours. - Consider flushing a distributed cache after upgrade to avoid any issue. Do not share a distributed - cache with applications using an earlier version of NHibernate. - * The counter id generator may generate conflicting ids for as much as twelve hours after upgrade. - * `update` and `delete` statements will now take into account any enabled filter on the entities - they update or delete, while previously they were ignoring them. (`insert` statements will also take - them into account, but previously they were failing instead of ignoring enabled filters.) - * ISession.Persist and ISession.Merge will no more trigger immediate generation of identifier. - * Bags will no more be loaded with "null" entities, they will be filtered out. - * Setting the value of an uninitialized lazy property will no more trigger loading of all the lazy - properties of the entity. - * If an uninitialized lazy property has got its value set, without any other subsequent lazy property - load on the entity, a dynamic update will occur on flush, even if the entity has dynamic updates - disabled. This update will occur even if the set value is identical to the currently persisted - property value. - * Assigning an uninitialized proxy to a `no-proxy` property will no more trigger the proxy - initialization. Moreover, reading the property afterwards will no more unwrap the assigned proxy, - but will yield it. - * A class having an explicitly implemented interface declaring a member with the same name than the - class id will have its proxies trigger a lazy load if the interface "id" is accessed. - * SQLite: in order to avoid a floating point division bug losing the fractional part, decimal are now - stored as `REAL` instead of `NUMERIC`. Both are binary floating point types, excepted that `NUMERIC` - stores integral values as `INTEGER`. This change may cause big integral decimal values to lose more - precision in SQLite. - * SQLite: non supported SQL type names previously used by NHibernate, resulting in unexpected actual typing, - have been fixed. This causes databases generated by a previous NHibernate version to fail schema validation - by 5.3 or higher versions. See #2507 for more information. - * Custom dialects used for databases that do not support cross join will have to override - `SupportsCrossJoin` property and set it to `false`. - * `VisitorParameters.ConstantToParameterMap` may contain the same parameter for multiple constant - expressions. - * `ICache` caches yielded by the session factory will be `CacheBase` wrappers around the cache actually - provided by the cache provider, if it was not deriving from `CacheBase`. - * Calling `IList.RemoveAt` or `IList<>.RemoveAt` on an uninitialized list with a negative number - will now throw an `ArgumentOutOfRangeException`. - * Calling `IList.RemoveAt` or `IList<>.RemoveAt` on an uninitialized list mapped as `lazy="extra"` - with a number that is equal or higher that the current collection size will now throw an - `ArgumentOutOfRangeException`. - * Calling `IList.Insert` or `IList<>.Insert` on an uninitialized list with a negative number will - now throw an `ArgumentOutOfRangeException`. - * Calling `IList.Insert` or `IList<>.Insert` on an uninitialized list mapped as `lazy="extra"` - with a number that is higher that the current collection size will now throw an - `ArgumentOutOfRangeException`. - * Getting or setting a value with `IList.this[int index]` or `IList<>.this[int index]` on an uninitialized - list with a negative number will now throw an `ArgumentOutOfRangeException`. - * Setting a value with `IList.this[int index]` or `IList<>.this[int index]` on an uninitialized list - mapped as `lazy="extra"` with a number that is equal or higher that the current collection size will now - throw an `ArgumentOutOfRangeException`. - * Calling `IDictionary<,>.Add` or `ICollection<>.Add` on an uninitialized map mapped as `lazy="extra"` with - a key that already exists will now throw an `ArgumentException`. - * Calling `IDictionary<,>.Remove` or `ICollection<>.Remove` on an uninitialized map mapped as `lazy="extra"` - with a key that does not exist will now return false. - * Map dirtiness is now evaluated by `EqualityComparer.Default` when setting an existing key value - with `IDictionary<,>.this[]` on an initialized map. - * Calling `ISet<>.Add` on an uninitialized set mapped as `lazy="extra"` with a transient element that - already exists in the set will now return false. - * Calling `ISet<>.Add` or `ICollection<>.Add` on an uninitialized set mapped as `lazy="true"` with a - transient element that does not override `Equals` method will not initialize the collection. - * Linq custom generators deriving from `BaseHqlGeneratorForMethod` should override the - `TryGetCollectionParameter` method if they have to support parameter lists. - -** Bug - - * #2425 NRE with nullable subselect value in Linq - * #2421 Chapter 26: Best Practices, error about identifier recommendations - * #2410 Second level cache failures with CoreMemoryCaches - * #2380 OData NotSupportedException MemberInit on base class member - * #2365 Add Linq parameter type detection - * #2346 Fix SQLite typing - * #2336 Intermittent null reference exception on CloseConnection - * #2324 Update IIsEntityDecider to use ExpressionsHelper.TryGetMappedType - * #2319 Upgrade AsyncGenerator to 0.18.1 - * #2299 Proper query plan caching for DML LINQ queries - * #2286 Wrong sql if used joined-subclass with filters for key columns - * #2278 IInterceptor.OnPrepareStatement results not used in insert/update commands - * #2266 Fix comment for Restrictions.IsEmpty - * #2255 Fix a flaky test - * #2245 Add sqlite.binaryguid to configuration schema - * #2244 SelectMany Linq extension does not work correctly - subsequent FetchMany fails - * #2233 Fix possible issue with async code for delayed entity inserts - * #2231 Invalid alias name used in Linq Joins - * #2222 NHibernate query plan for Linq Dml is not cached - * #2219 Fix BuildTool output path - * #2215 Fix ShowBuildMenu.sh - * #2181 Skip null entities when bag is populated - * #2164 Do not call GC.SuppressFinalize from finalizer thread - * #2158 Proper support for IN clause for composite values in Criteria - * #2147 Improve async locking - * #2144 AdoTransaction memory leak (5.2.5) - * #2137 NullReferenceException in EntityEntry.GetLoadedValue on an update of a never loaded detached entity - * #2099 "Composite Index" not working with inheritance - * #2088 Fix cacheable CreateSQLQuery throws on query with AddJoin - * #2085 Duplicated methods generated in proxies - * #2067 Wrong proxy built for base class with interfaced sub-classes - * #2064 One-to-one properties not appearing in Select() projection result set - * #2053 Dml Style Update fails with static where sql in mapping - * #2038 Fix a typo on the memcached distributed cache description in the docs - * #2029 Incorrect SQL for cast inside an aggregate (MS SQL) - * #2019 Update symbol package format and add Sourcelink - * #2000 Fixed Equals method for transformers - * #1997 Fix criteria collection ordering - * #1994 Extra Select for every "outfiltered" Element - * #1993 InvalidCastException when merging a collection with a lazy property - * #1985 DateTime.xxxx are not supported in SelectGroup - * #1965 Fix code sample in docs, section 10.4.2 - * #1956 Fix lazy property caching - * #1921 DML insert fails when a filter is enabled - * #1738 Refresh of locally removed collection item crashes with "instance was not in a valid state" - * #1480 Fix cache build for honoring mapped concurrency - * #1368 NH-3778 - Crash when performing a Linq query on a one-to-one mapped reference - * #1341 NH-3848 - Child collection fetched using left outer join with on clause or where clause restrictions on fetched collection shouldn’t be stored in second level cache. - * #1319 NH-3549 - BasicFormatter throws exceptions for certain types of data containing "signal words" - * #1312 NH-3493 - Cannot use alias between more than 1 level of nested queries - * #1310 NH-3478 - StatefulPersistenceContext.RemoveEntity KeyNotFoundException on Evict - * #1309 NH-3469 - Impossible to load one-to-one association with LINQ for composite-id - * #1274 NH-3117 - Query on one-to-one property returns incorrect results - * #1263 NH-2991 - Criteria withClause doesn't work in case of many to many collections - * #1228 NH-2648 - HQL with joins in sub-select creates wrong SQL - * #1206 NH-1761 - Criteria query inserts an extra order by expression when using JoinType.LeftOuterJoin and Projections - * #1158 NH-3492 - SqlClientBatchingBatcher incorrectly ignoring per-SessionFactory Settings properties - * #1128 NH-3210 - NHibernate Linq Provider does cross join or left outer join and not inner join (even if outer-join=false on many-to-one mapping) - * #1124 NH-3155 - Linq subquery with group is not supported - * #1125 NH-3178 - Exception when using one-to-one properties in a criteria projections - * #1117 NH-3079 - Cannot use a sql custom loader with a composite ID - * #1107 NH-2983 - Coalesce in projection doesn't work if there is more than 1 Coalesce - * #1103 NH-2926 - CriteriaQuery - Unable to sort by composite-id - * #1100 NH-2892 - The columns containing reserved words are not quoted - * #1059 NH-1001 - Select statement issued for each not-found=ignore - * #1047 NH-3865 - Swallowed ArgumentNullException with dynamic composite id - * #1015 NH-2951 - Missing alias in hql update (select) statement with joined subclasses - * #1006 NH-2714 - Properties mapped inside a group are not set when retrieving object - -** New Feature - - * #2411 Add an option to register a custom pre-transformer for a Linq query - * #2392 Add locate support for SQLite - * #2362 Add support for lt, gt, le, ge oData operators on strings - * #2349 Add support for Oracle binary floating point types - * #2347 Support fetching individual lazy properties for Criteria EntityProjection - * #2327 Add cross join support for Hql and Linq query provider - * #2313 Add overloads to ISession.Get taking both an entityName and a lockMode - * #2259 Schema auto-update should throw errors - * #2221 Support MemberInit expression in group by - * #2216 Add a driver to support Microsoft.Data.SqlClient provider - * #2209 IN clause support in hql for composite keys on databases without row value constructor support - * #2156 Support basic arithmetic operations (+, -, *, /) in QueryOver - * #2135 Support OData GroupBy/Aggregate - * #2116 Ability to replace ConfigurationManager with a custom config provider - * #2108 Multi-Tenancy: Implement tenant per Database strategy - * #2107 Port Hibernate's Aggregate functions for subqueries - * #2106 Port Hibernate's support subqueries in HQL as CASE statement alternatives - * #2100 Allow to override default types with length or precision parameters - * #2097 Add support for fetching an individual lazy property with Criteria - * #2090 Add support for caching fetched relations with Criteria - * #2080 Add ability to set custom collection type as a string in mapping by code - * #2049 Fix property-ref ignoring not-found="exception" mapping - * #1949 Port Hibernate's lazy attribute fetch groups - * #1922 Add support for fetching an individual lazy property with hql and linq provider - * #1861 Lazy loading and Eager initialization for Component - * #1376 Composite id is incorrectly expanded in SQL - * #1195 NH-4078 - LINQ fetched collections aren't cached - * #981 NH-3873 - Explicit joins on unrelated classes - * #959 NH-4048 - Support non-deterministic/db-side-only methods in Linq - * #896 NH-1432 - Expression.Sql should support aliases other than {alias} - -** Improvement - - * #2404 Allow overriding default CastFunction - * #2401 Optimize JoinWalker.WhereString method - * #2399 Optimize PersistentGenericBag.EqualsSnapshot - * #2394 Optimize PersistentGenericSet snapshot - * #2352 Improve performance of ReflectHelper.GetMethod/Definition - * #2350 Optimize LINQ batch item processing for queries with overridden result type - * #2316 Add multiple arguments support for ISQLFunction - * #2315 Add SetFlushMode for QueryOver and Linq - * #2295 Optimize filter applying logic - * #2287 Allow customizing 'alias to bean' property not found behavior - * #2284 Make persistent collection classes implement the IReadOnly* interfaces - * #2270 IQueryOver is lacking some options - * #2254 Add dev build version suffix - * #2249 Improve handling of SqlCeParameter.SqlDbType - * #2248 Remove most RemoveAsAliasesFromSql usages - * #2241 Avoid duplicating parameters in LINQ query - * #2238 Call generic query.List from Linq queries - * #2235 Configure log4net from embedded resource log4net.xml in tests - * #2232 Use SqlStringBuilder for batching Future/QueryBatch queries - * #2226 Use DateTime.UtcNow for timestamps - * #2225 Avoid unnecessary locking via MethodImplOptions.Synchronized - * #2223 Short-Circuit SessionFactoryImpl.Close() when already closed - * #2214 Allow configuring auto-join transaction globally - * #2213 Add a shortcut to reduce Transaction.Current reads - * #2211 Port SupportsRowValueConstructorSyntaxInInList values - * #2182 Upgrade AsyncGenerator to 0.17.1 - * #2166 Optimize usages of SqlString.Append - * #2163 Add virtual DefaultQueryProvider.CreateWithOptions - * #2162 Use collection types for private members - * #2161 Optimize ToArray conversions - * #2159 Unify handling of composite values in hql and Criteria - * #2153 Use generic parameters in ActionQueue - * #2139 Add ability to set fetch for mapping in mapping by code - * #2131 Create Stopwatch only if stats is enabled - * #2126 Upgrade AsyncGenerator to 0.14.0 - * #2125 Skip logger default initialization logic when logger provided by user - * #2123 Use Assert.Throws instead of try-catch in tests - * #2119 Obsolete interfaces for Loquacios configuration and use config classes directly - * #2117 Replace array concatenation with hand written append - * #2115 Statefull Session commit performance issue when nothing changed and second level cache with query cache enabled - * #2091 Obsolete StringHelper.Join - * #2084 Improve one-to-one handling in queries - * #2082 Use entities prepared by Loader in hql select projections - * #2078 Avoid unnecessary join for entity comparisons in with clause - * #2071 Support subclass mapping with EntityName based base class mapping - * #2061 Reduce cast usage for COUNT aggregate and add support for Mssql count_big - * #2058 DB2 dialect enhancements - * #2056 Optimize GetOrphans and remove wrong checks from IsNotTransientSlow - * #2041 Hql entity join fixes - * #2039 Use generic CollectingNodeVisitor in hql parser - * #2036 Reduce cast usage for aggregate functions - * #2032 Allow using ON instead of WITH in hql - * #2024 Refactor to simplify netfx retargeting - * #2022 Make CancellationToken optional for async Linq DML queries - * #2010 Add new collection operation queue mechanism - * #2009 Add support for IDictionary to IQuery.SetProperties - * #2007 Dispose session in cascade tests - * #2006 Skip Topological sorting if not required - * #2003 Avoid some cases of Type -> string -> Type conversion in Mapping By Code - * #2002 Refactor DependentAlias handling logic in JoinWalker - * #1999 Optimize DistinctRootEntityResultTransformer - * #1989 Optimize ProxyCacheEntry equality for the same instance - * #1988 Improve exception on user types lacking some interfaces - * #1984 Reduce SessionIdLoggingContext creation - * #1981 Remove AbstractLazyInitializer unused field - * #1979 Refactor sequential select - * #1977 Obsolete IDeserializationCallback from EntityKey - * #1972 Port Hibernate's EntityKey optimization - * #1968 Optimize StaticProxyFactory GetProxy and GetFieldInterceptionProxy methods - * #1955 Optimize batchable cache calls for cached queries - * #1947 Partially port Hibernate's current field interceptor mechanism - * #1946 Port Hibernate's BytecodeEnhancementMetadata - * #1944 Extend IAccessOptimizer to support getting/setting single property value - * #1943 Skip initialization of lazy properties when setting one - * #1923 Obsolete StringHelper.Replace - * #1860 LINQ "==" operator generates OR with IS NULL - * #1754 Delay entity insert on Persist until session is flushed - * #1627 Refactored session List method for Criteria - * #913 NH-3704 - Allow Setting Dynamic Component Templates From Dictionary - * #864 NH-2379 - Add support of Left Joins to Linq Provider - * #803 NH-2521 - Session.EnableFilter method should work for HQL-DML statement - * #780 NH-1200 - Exception occurs when using criteria exist queries - * #767 NH-3892 - Add ability to coalesce using a property instead of a constant - * #722 NH-1953 - Support Future for collection filters - * #476 Eliminated double Persister resolution in Loader.InstanceNotYetLoaded flow - -** Task - - * #2433 Improve slightly mapping documentation - * #2432 Document the caches configuration providers - * #2430 Document cache.serializer setting of CoreDistributedCache - * #2397 Update GitReleaseManager - * #2391 Use latest Firebird for AppVeyor and Travis - * #2388 Release 5.3 - * #2382 Refactor debug logging in AbstractBatcher - * #2381 Use optimized Dictionary.Remove(key, out value) in .NET Core - * #2379 Simplify swap items logic in LINQ Visitors - * #2377 Use dotnet to push packages to nuget - * #2376 Add MyGet gallery link to readme - * #2368 Replace SafetyEnumerable with OfType where applicable - * #2363 Upgrade AsyncGenerator to 0.18.2 - * #2356 Obsolete IdentitySet class - * #2354 Do not require Mono to build on not Windows - * #2353 Update Microsoft.SourceLink.GitHub to 1.0.0 - * #2351 Get rid of JoinedEnumerable and SingletonEnumerable - * #2348 Use static ReferenceComparer for reference comparisons - * #2308 Merge 5.2.7 - * #2294 Add StackExchangeRedis cache provider documentation - * #2293 Update RtMemoryCache framework dependency - * #2265 Fix code style issues - * #2251 Publish development nightly builds on nuget - * #2205 Merge 5.2.6 - * #2171 Upgrade NUnit - * #2122 Update AsyncGenerator to 0.13.3 - * #2016 Avoid recursive calls in BatchFetchQueue - * #2014 Obsolete Environment.Properties - * #1973 Investigate licenseUrl deprecation - * #1971 Add SourceLink to allow NuGet package debugging - * #1940 Allow to provide dev specific properties in NHibernate.dev.props - * #1936 Upgrade AsyncGenerator to 0.13.1 - -** Tests - - * #2384 Tests to verify NH-2329 is obsolete - * #2360 Add OData test for single property $expand - * #2089 Bidirectional list fails if session only knows about child - * #2066 Tests for proxy interface handling - * #1966 Test duplicated join on some Linq queries - -Build 5.2.7 -============================= - -Release notes - NHibernate - Version 5.2.7 - -4 issues were resolved in this release. - -** Bug - - * #2302 Backport sqlite.binaryguid to configuration schema - * #2298 Dml Linq Update Produce Wrong Sql - * #2296 Missing Row Count in Debug Log for Future queries - -** Task - - * #2303 Release 5.2.7 - -Build 5.2.6 -============================= - -Release notes - NHibernate - Version 5.2.6 - -11 issues were resolved in this release. - -** Bug - - * #2190 Cannot instantiate a SessionFactory using Prevalence cache - * #2177 New Fetch() method in QueryOver returns IQueryOver<> instead of QueryOver<> - * #2172 Using DependentTransaction fails - * #2175 Subcriteria on component collection generates incorrect join alias - * #2173 Futures not batching correctly in NH 5.2.x - * #2141 Undefined call to Equals object in collection during flush just before commit - * #2127 StackExchangeRedisCache with PreferMultipleGet = true calls GetMany multiple times - * #2110 Wrong GUID to string conversion with SQLite BinaryGuid=False - -** Task - - * #2200 Release 5.2.6 - * #2199 Upgrade AsyncGenerator to 0.8.2.12 - -** Tests - - * #2132 Add GetMany for ReadWriteCache tests - -Build 5.2.5 -============================= - -Release notes - NHibernate - Version 5.2.5 - -5 issues were resolved in this release. - -** Bug - - * #2075 Missing cast when comparing a guid and string columns in SAP SQL Anywhere - * #2046 Fix nullable Guid ToString is not translated correctly on some dialects - * #2043 System.Reflection.TargetException when an interface is used as class mapping proxy definition - * #2040 Incorrect SQL when comparing a guid and string column in Sql Server - -** Task - - * #2086 Release 5.2.5 - -Build 5.2.4 -============================= - -Release notes - NHibernate - Version 5.2.4 - -3 issues were resolved in this release. The dialect change has the side effect of -re-enabling a hack used by NHibernate.Spatial, allowing Spatial users to upgrade -to NHibernate 5.2.x. See NHibernate.Spatial#104. - - ##### Possible Breaking Changes ##### - * Using DML on an entity collection was applying the changes without - filtering according to the entity. It will now throw a - NotSupportedException. - -** Bug - - * #2020 Throw for DML on filter - * #2011 Use a statically resolved dialect when building the session factory - -** Task - - * #2030 Release 5.2.4 - -As part of releasing 5.2.4, a missing 5.2.0 possible breaking change has been added about -property-ref on null values. See 5.2.0 possible breaking changes. - -Build 5.2.3 -============================= - -Release notes - NHibernate - Version 5.2.3 - -1 issue was resolved in this release. - -** Bug - - * #1964 Unable to serialize session because SerializationFieldInfo is not marked as serializable - -Build 5.2.2 -============================= - -Release notes - NHibernate - Version 5.2.2 - -3 issues were resolved in this release. - -** Bug - - * #1953 Query space invalidation doesn't work for bulk actions - * #1269 NH-3069 - Cannot use Session.Lock with Version column on abstract base class - -** Task - - * #1957 Release 5.2.2 - -Build 5.2.1 -============================= - -Release notes - NHibernate - Version 5.2.1 - -5 issues were resolved in this release. - -** Bug - - * #1928 JoinAlias on JoinQueryOver fails - * #1920 ISession.Get may fail with a null exception - * #1918 Property-ref on many-to-one with composite id fails - -** Task - - * #1932 Release 5.2.1 - * #1927 Add missing possible breaking change - -As part of releasing 5.2.1, a missing 5.2.0 possible breaking change has been added about duplicated columns -in mapping. See 5.2.0 possible breaking changes. - -Build 5.2.0 -============================= - -Release notes - NHibernate - Version 5.2.0 - -157 issues were resolved in this release. - - ##### Possible Breaking Changes ##### - * Entities having many non-readonly properties (including many-to-one) mapped to - the same column will no more silently ignore the trouble till an insert or update - is attempted. They will now cause the session factory built to fail. When - mapping many properties to the same column, all of them excepted at most one - should be mapped with `insert="false" update="false"`. - * Mappings mixing column elements and formula elements were taking into account - only the formula elements. They will now take into account all elements. - * Mappings mixing column elements and/or formula elements with a column attribute - or a formula attribute were silently ignoring the attribute. They will now throw. - * Mappings mixing a column attribute and a formula attribute were silently doing - some best effort logic, either considering this as a two columns mapping, the - second one being the formula (most cases), or only taking into account the - formula (case of the `` mapping). They will now throw. - * NHibernate StringType has gained case-sensitivity and culture parameters. - Previously it was ignoring parameters. This type may change its behavior - for any mapping having defined parameters for this type. See #1833. - * Mapping a dynamic component with a Hashtable property instead of an - IDictionary is no more supported. - * Querying a dynamic entity as a Hashtable instead of an IDictionary is no more - supported. - * A collection mapped with a `property-ref` will no more support being accessed - when the referenced property is null. It will throw. Previously, the collection - was not throwing but was always loaded empty. - * With PostgreSQL, a HQL query using the bitwise xor operator "^" or "bxor" - was exponentiating the arguments instead. It will now correctly apply the xor - operator. (# operator in PostgreSQL SQL.) - * Auto-generated constraint names will not be the same than the ones generated - with previous NHibernate versions under .Net Framework. (Under .Net Core those - names were anyway changing at each run.) The new ones will be the same - whatever the runtime used for generating them. - * Some generated PK names may change, if a table name has a quoting symbol at - precise 13th character. - * The WcfOperationSessionContext has been removed from .Net Core and .Net - Standard builds. See #1842. - * Some classes, which were not serializing the session factory, do now serialize it. - In case of cross-process serialization/deserialization, these session factories - will need to be properly named, by setting the session_factory_name setting in the - configuration used to build them. This may mainly affect users of a distributed - second level cache, if their cache implementation uses binary serialization. - Affected classes are: CacheKey, CollectionKey, EntityKey and EntityUniqueKey. - * Some types cache representations have changed. Out-of-process second level - caches should be cleared after upgrading NHibernate, if some of those types - were cached. The concerned types are: CultureInfoType, TypeType, UriType, - XDocType, XmlDocType. - * Dialect.GetIdentitySelectString was called by the entity persisters with - inverted parameter values: the table name in the column parameter, and the - column name in the table parameter. No built-in dialects were using the - parameter values. External dialects which were using it inverted (causing issues - to collection persisters, which have always supplied them correctly) needs - to be accordingly adjusted. - * Users providing through an IObjectFactory some custom logic for instantiating - value types will now need to supply their own result transformer if they were - using AliasToBeanResultTransformer with value types, or their own entity - tuplizer if they were using value types as entities. - * Users providing through an IObjectFactory some custom logic for instantiating - their custom session contexts will have to implement - ICurrentSessionContextWithFactory and add a parameterless public constructor - to their custom context, and move their custom instantiation logic from - IObjectsFactory.CreateInstance(Type, object[]) to - IObjectsFactory.CreateInstance(Type). - * Various *Binding classes of NHibernate will now always have their protected - dialect field null. (These classes are not expected to be derived by users, - as there is no way to use custom descendants with NHibernate.) - * AbstractPersistentCollection.AfterInitialize does no more perform queued - operations. Queued operations are now run by a later call to a new method, - ApplyPendingOperations. Concrete custom implementations relying on the queued - operations to be done by their base AfterInitialize will need to be changed - accordingly. - -** Bug - - * #1900 Do not generate FK on non-generated unique constraint - * #1888 Second level cache key mismatch - * #1886 Superfluous SQL casts generated in FirebirdClientDriver - * #1885 Process classes accordingly to inheritance path in mapping by code - * #1884 Fix attempt of static proxies to call base method for abstract classes - * #1874 Item in child collection not being removed - * #1872 Fix property ref handling - * #1870 Update build-menu options in documentation - * #1867 Fix registration of current_date for some dialects - * #1859 Fix filter & where fragment appended after lock hint - * #1855 Fix NotNullUnique not taken into account for single column - * #1849 Loquatious QueryCache constraint should be an IQueryCacheFactory constraint - * #1836 Cannot create configuration due to log4net loading failure - * #1824 property-ref on a component's property causes "wrong number of columns" error - * #1821 Allow using ICompositeUserType for collection element mappings in Mapping By Code - * #1818 Handle DbDataReaders that do not support GetSchemaTable - * #1812 Fix the handling without meta-values - * #1809 Update the mapping documentation - * #1799 Default value of 'proxyfactory.factory_class' in the documentation - * #1774 HQL and LINQ query by the type on with meta-type "string" fails - * #1769 Table mapping for UniqueColumn uses unstable GetHashCode() method - * #1764 Fix configuration schema forbidding custom bytecode provider - * #1760 Support formula on one-to-many map-key - * #1756 Fix unsaved-value for assigned identifiers - * #1753 Fix possible InvalidCastException in ActionQueue - * #1751 Avoid completing the same transaction twice - * #1748 Fix a bad setting naming about transaction scopes - * #1745 Remove obsoleted hibernate configuration prefix - * #1744 Reconnect lazy property proxy on deserialization - * #1737 Remove a binary breaking change introduced in #305 - * #1728 Generate a correct proxy for interfaces - * #1727 Fix a null-ref exception with no-proxy one-to-one - * #1726 Fix serialization exception when run on .NET Core 2.1 - * #1719 Cascade delete-orphan on no-proxy null association fails - * #1706 Entity Projection: Fixed AsEntity() for root entity - * #1704 GroupBy to custom class fails with ArgumentException - * #1696 Fixed CriteriaImpl.Clone for readonly query - * #1692 Update base_mapping.xml - * #1673 Bitwise xor treated as pow with PostgreSQL - * #1654 Fix the url to the quickstart of DocBook - * #1635 IdentitySelectString implementation is inconsistent - * #1612 Fix TypedValue not always using adequate comparer with SetParameterList - * #1609 Schema validation using SQLite and a specific schema fails - * #1366 NH-3506 - ICriteria/QueryOver create incorrect left join condition when table-per-hierarchy is used with filters - * #1358 NH-3992 - Intermediate inherited classes are not mapped correctly - * #1344 NH-3864 - Cacheable Multicriteria/Future'd query with aliased join throw exception - * #1339 NH-3823 - Initialization of Set with Lazy=Extra causes pending additions to disappear - * #1338 NH-3806 - Saving entities with proxy associations leads to fetching associated entities - * #1300 NH-3403 - Wrong parameter size in query with MsSql2000Dialect,MsSql2005Dialect and MsSql2008Dialect - * #1293 NH-3350 - Duplicate records using Future() - * #1278 NH-3189 - IManyToOneMapper lacks method to add columns AND formula into a single relationship - * #1214 NH-2180 - Many-To-Many with Property-ref fails to get subitems with FetchMode Join - * #1201 NH-1316 - PostgreSQL dialect use of lastval to retrieve last inserted "id" not safe with Triggers - * #1182 NH-3860 - Missing EntityName in IManyToOneMapper - * #1170 NH-3646 - Incorrect query when items removed from a collection of components contain null values - * #1163 NH-3545 - SchemaValidator fails for PostgreSql sequences - * #1151 NH-3426 - Wrong result when converting Guid to string - * #1121 NH-3095 - Cast from mapped long field to enum leads to 'Specified cast not valid' - * #1096 NH-2836 - SchemaValidator throws with SqlCe4 if db-schema set - * #1089 NH-2755 - LockMode hash differs in x86 and 64bit OS - * #1037 NH-3749 - Unnecessary comma in CREATE TABLE statement - * #1016 NH-3007 - Informix dialect generates incorrect boolean constants - * #1000 NH-2558 - NoViableAltException with boolean expression in OrderBy clause - * #990 NH-2016 - Duplicate Association Path when creating multiple aliases - * #460 Fix Criteria caching filtered collections - -** New Feature - - * #1892 Allow disabling Firebird driver parameter casting - * #1879 LINQ Coalesce and Conditional on Properties - * #1854 Add SQL Anywhere 17 support - * #1848 Add in ByCode support of all type mappings on Id - * #1833 Parametrize string type comparer - * #1830 Add a Linux build menu - * #1796 Support CacheMode in QueryBatch - * #1786 Document future results - * #1772 Support futures with stateless session - * #1752 Async ISynchronization - * #1742 Add new DB2CoreDriver to use with IBM.Data.DB2.Core provider - * #1693 Implement SurrogateSelector - * #1690 Bitwise xor not supported by SQLite - * #1682 Add support for System.MathF methods - * #1662 Add support for SAP HANA - * #1633 Added support for batching 2nd level cache operations when loading entities and collections - * #1631 Create UtcTicks and UtcDbTimestamp types - * #1599 Full control of entities fetching in Criteria - * #1381 NHibernate's IQuery is missing AddSynchronizedQuerySpace - * #968 NH-2285 - Support for LockMode in linq provider - * #920 NH-3991 - Support for Sybase ASE ADO.NET 4 Provider - * #897 NH-2187 - ElementAt LINQ extension method is not supported. - * #838 NH-3805 - Add support for string indexer property (get_Chars) - * #819 NH-3088 - Support the item operator [] on lists in linq queries - -** Improvement - - * #1908 Control over BeginTransaction in AdoTransaction - * #1905 Improve support of Npgsql 4 - * #1901 Add ability to use dynamic entities as C# dynamic - * #1890 Merge two logs in one - * #1875 Improve exception message in case of duplicated column - * #1869 Replace an O(n) lookup in LINQ query parsing by an O(1) one - * #1846 Remove dependency on System.Security.Permissions package for .NET Standard and .NET Core - * #1842 Remove WcfOperationSessionContext from .Net Core and .Net Standard - * #1838 Cannot add HqlJoin to HqlFrom - * #1827 Include the query in loader PostInstantiate QueryException - * #1819 Append the batched sql statement when StaleStateException occurs - * #1814 Mark proxy assembly with IgnoresAccessChecksToAttribute to allow implementing non public interfaces - * #1808 Support mixed formulas and columns - * #1792 Obsolete HolderInstantiator - * #1788 Implement multiple get and put for query cache and query batch - * #1785 Update user types documentation - * #1782 Refactor BugTestCase - * #1781 Clean-up IObjectsFactory usages - * #1778 Allow to use dynamic objects as dynamic components - * #1777 Replace ICache interface by a CacheBase class - * #1776 Make cache types serialization friendly - * #1775 Start/Stop required db-service for TeamCity - * #1770 Make obsolete abstract virtual - * #1767 Allow generic dictionaries for dynamic entities - * #1765 Provide cacheable representations for all NHibernate built-in types - * #1762 Remove duplicated and obsolete interceptor documentation - * #1761 Update mapping documentation - * #1759 Support mixed formulas and columns in By Code - * #1736 Remove excessive rowIdAlias parameter in Loader - * #1713 Update contributing guidelines - * #1712 Support IEquatable in LINQ provider - * #1710 Rationalize DateTimeOffset read and write - * #1709 Lazy properties static proxy - * #1703 Remove dialect instantiation in AddDeserializedMapping - * #1700 Single place to specify TargetFrameworks - * #1699 Add ability to load types from in-memory-only assemblies - * #1698 Document setting the logger factory programmatically - * #1694 Implement CollectionHelper.GetHashCode that accepts IEqualityComparer - * #1689 Purge more Invariant culture usages - * #1671 Decouple configuration of IObjectsFactory from BytecodeProvider - * #1666 Handle multi-queries support in FutureBatch - * #1656 Allow any cache.* property in NHibernate configuration - * #1641 Add cross platform build for full .NET Framework - * #1452 Async After-/BeforeTransactionCompletion - * #874 NH-3543 - Enhanced Db2 driver to support multi query - * #865 NH-2428 - Session.MultiCriteria and FlushMode.Auto inside transaction - * #840 NH-3835 - Future/MultiCriteria 2nd level caching - * #822 NH-3150 - Select Post Insert Generator Improvements - * #755 NH-3670 - Dynamic component should allow generic dictionary - * #752 NH-3541 - Future queries of Criteria API/QueryOver are batched separately from other query methods - * #696 Upgrade to ReLinq 2.2.0 - * #415 Add check to ensure that IUserCollectionType.Instantiate returns uninitialized collection - -** Task - - * #1863 Release 5.2.0 - * #1823 Run tests for SQLite on .NET Core - * #1783 Obsolete MultiQuery and MultiCriteria - * #1773 Obsolete unused version related methods of SByteType - * #1771 Obsolete unused "xml" type methods - * #1743 Merge 5.1.3 into master - * #1739 Upgrade to AsyncGenerator 0.8.2.7 - * #1688 Merge 5.1.2 into master - * #1687 Update NUnit to 3.10.1 - * #881 NH-3358 - Document all attributes for the element tag - -** Tests - - * #1887 Test ref and out methods with static proxy - * #1724 NH-2716 - Modify test case for discarding the alleged bug - * #1584 Test Parent property is not accessible in queries - * #1531 Test for Merging a bidirectional list creates unnecessary UPDATE statement - * #1440 Test case for ComposedId Entity with Lazy Property is not proxified - * #1414 Test ISession.IsDirty() should not trigger cascade saving - -As part of releasing 5.2.0, a misnamed setting in 5.0.0 release notes has been fixed: -transaction.use_connection_on_system_events correct name is transaction.use_connection_on_system_prepare - -Build 5.1.7 -============================= - -Release notes - NHibernate - Version 5.1.7 - -** Bug - * #2298 Dml Linq Update Produce Wrong Sql - -Build 5.1.6 -============================= - -Release notes - NHibernate - Version 5.1.6 - -** Bug - * #2172 Using DependentTransaction fails - -Build 5.1.5 -============================= - -Release notes - NHibernate - Version 5.1.5 - - ##### Possible Breaking Changes ##### - * Using DML on an entity collection was applying the changes without - filtering according to the entity. It will now throw a - NotSupportedException. - -** Bug - - * #2043 System.Reflection.TargetException when an interface is used as class mapping proxy definition - * #2020 Throw for DML on filter - -** Task - * #2074 Release 5.1.5 - -Build 5.1.4 -============================= - -Release notes - NHibernate - Version 5.1.4 - -** Bug - - * #1959 Backport Query space invalidation doesn't work for bulk actions - -Build 5.1.3 -============================= - -Release notes - NHibernate - Version 5.1.3 - -** Bug - - * #1741 Fix DbType.Binary registration in DB2Dialect - * #1732 Dictionary failure in Loader - * #1730 Query cache always missed in session having altered the entities - * #1711 Fix static proxy serialization - -** Task - - * #1716 Release 5.1.3 - - -Build 5.1.2 -============================= - -Release notes - NHibernate - Version 5.1.2 - -** Bug - - * #1680 RowCount not working with JoinEntityAlias - * #1672 Generated async methods do not correctly propagate OperationCanceledException - * #1667 Collection initializing with zero rows after update to NH5 - * #1660 Wrong CopyTo implementation - * #1650 Cannot use cache.use_sliding_expiration in hibernate.cfg.xml - * #1585 Hashset unsupported by SetParameterList - * #1355 NH-3928 - Random invalid SQL generated when using bitwise operators - -** Task - - * #1668 Merge 5.0.5 into 5.1.x - * #1664 Release 5.1.2 - * #1659 Merge 5.0.4 into 5.1.x - -As part of releasing 5.1.2, a missing 5.0.0 possible breaking change has been added about future queries with data -providers not actually supporting them. See 5.0.0 possible breaking changes. - - -Build 5.1.1 -============================= - -Release notes - NHibernate - Version 5.1.1 - -** Bug - - * #1645 One-to-one with property-ref triggers StackOverflow Exception - * #1643 TypeLoadException in StaticProxyFactory after upgrading to 5.1.0 - * #1640 Handle all overloads of String.Trim*() - * #1636 Fix api documentation assets path - * #1628 StackOverflowException for lazy proxied entities with explicit interface properties - * #1618 Fix NuGet push script - * #1149 NH-3391 - StatelessSession: one-to-one detail-object is always null - -** Improvement - - * #1646 Add a link to release notes in NuGet package - * #1639 Speedup access to SQL Server on Linux - * #1624 Add missing ids on documentation sections - * #1619 Document "entity join" and "entity projection" - -** Task - - * #1649 Release 5.1.1 - * #1622 Update cache documentation - * #1621 Upgrade Async Generator to a version compatible with VS 15.6.3 - - -Build 5.1.0 -============================= - -Release notes - NHibernate - Version 5.1.0 - -** Highlights - * NHibernate has gained two new target frameworks: .Net Core 2.0 and .Net Standard 2.0. NHibernate NuGet package - provides them, along with the .Net framework 4.6.1 build. - For these new frameworks, some additional specificities or limitations apply: - * Binary serialization is not supported - the user shall implement serialization surrogates for System.Type, - FieldInfo, PropertyInfo, MethodInfo, ConstructorInfo, Delegate, etc. - * SqlClient, Odbc, Oledb drivers are converted to ReflectionBasedDriver to avoid the extra dependencies. - * CallSessionContext uses a static AsyncLocal field to mimic the CallContext behavior. - * System transactions (transaction scopes) are untested, due to the lack of data providers supporting them. - * 114 issues were resolved in this release. - - ##### Possible Breaking Changes ##### - * Since Ingres9Dialect is now supporting sequences, the enhanced-sequence identifier generator will default to - using a sequence instead of a table. Revert to previous behavior by using its force_table_use parameter. - * Some overridable methods of the Dialect base class and of MsSql2000Dialect have been obsoleted in favor of - new methods. Dialects implementors need to override the replacing methods if they were overriding the - obsolete ones, which are: - * Dialect.GetIfNotExistsCreateConstraint(Table table, string name), replaced by - GetIfNotExistsCreateConstraint(string catalog, string schema, string table, string name). - * Dialect.GetIfNotExistsCreateConstraintEnd(Table table, string name), replaced by - GetIfNotExistsCreateConstraintEnd(string catalog, string schema, string table, string name). - * Dialect.GetIfExistsDropConstraint(Table table, string name), replaced by - GetIfExistsDropConstraint(string catalog, string schema, string table, string name). - * Dialect.GetIfExistsDropConstraintEnd(Table table, string name), replaced by - GetIfExistsDropConstraintEnd(string catalog, string schema, string table, string name). - * MsSql2000Dialect.GetSelectExistingObject(string name, Table table), replaced by - GetSelectExistingObject(string catalog, string schema, string table, string name). - -** Bug - - * #1606 NHibernate 5 precision maximum on decimal reduced vs. NHibernate 4 - * #1605 MySql batcher may attempt initiating a new batch without closing open reader first. - * #1604 MySql batcher disables db exception translation - * #1602 Preserve original snapshot mode. - * #1594 AsyncLocal leak in SystemTransactionContext - * #1587 Prevent substitute garbage collection - * #1565 For update with outer join fails with PostgreSQL - * #1562 Fix round registration - * #1559 Deep removal of Fetch result operators when Any is used - * #1556 Linq query with "Contains" on persistent collection fails - * #1551 Assert for a null reference in a flaky test. - * #1536 Avoid a null reference exception in ExpressionKeyVisitor - * #1535 Fix some HQL functions registration - * #1534 Fixed entity name retrieval for EntityProjection - * #1526 ExpressionKeyVisitor does not produce unique keys for anonymous types coming from different assemblies - * #1514 Fix exceptions serialization - * #1511 Test Unicode string. - * #1509 Add missing NHibernateLogLevel.Info in example web project - * #1507 NH-3119 - fix test not supporting optimization - * #1506 SQLite is bugged with distributed transactions: disable distributed tests - * #1505 Chaining scopes with ODBC is bugged: disabling the test. - * #1501 Fix NH-3023 test - * #1496 Fix ManyToOneType.IsModified to handle both object instance and identifier passed to the parameter “old”. - * #1491 Forgotten async generation for #1487 - * #1486 Fix IsModified so that a null equates empty components when using select-before-update. - * #1484 Fix default types - * #1478 Exception when using envers with the latest logging changes - * #1476 Fix GetQueryCache storing two different caches. - * #1468 Comparison with DateTime? produces wrong SQL - * #1463 Fix a null reference case in session context - * #1454 Fix ProxyFactory cache - * #1445 Upgrade AsyncGenerator to 0.6.2 and regenerate. - * #1442 Unable to use an entity with a `FieldInterceptor` property and a lazy loaded property - * #1436 StackOverflowException when merging an entity with a lazy property - * #1434 Replace remaining SetOptions with WithOptions - * #1385 SecondLevelCache CreateSQLQuery().UniqueResult() throws Exception Specified cast is not valid. - * #1372 NH-3982 - Simple query with Cacheable, Fetch and SingleOrDefault throws exception (regression from 3.3.0) - * #1371 NH-3898 - Configuring a property with generated="insert" turns "Property.IsUpdatable" into"false" even using update="true" in the xml mapping file. - * #1363 NH-2500 - NH 3.0 Linq provider uses query parameters from first call in subsequent calls. - * #1335 NH-3787 - Decimal truncation in Linq ternary expression - * #1330 NH-3673 - Closure variable values locked in from expressions in NHibernate LINQ provider - * #1226 NH-2534 - Join-fetching a many-to-one with property-ref results in select n+1 problem - * #1196 NH-4087 - Decimal truncation occurs after 5 digits - * #1119 NH-3084 - Class NHibernate.Loader.Loader logs SQL statement on INFO level - * #1052 NH-3976 - Inconsistent Decimal/NHibernateUtil.Currency handling causing runtime error when using Oracle.ManagedDataAccess - * #987 NH-1509 - MsSql2000Dialect does not use default schema when creating "if exists" statement - * #448 NH-1285 - Drop/Create script with default_schema/default_catalog fix(SqlServer) - -** New Feature - - * #1588 Add a generic batcher for insert/update/delete statements, usable with PostgreSQL and others - * #1545 Support to join not associated entities in Criteria (aka Entity Join) - * #1451 New StaticProxyFactoryFactory - * #1403 Add timeouts support to MultiCriteria - * #1377 Logging refactoring - * #954 NH-3807 - Support for .NET Core 2.0 - * #948 NH-3435 - Ability to select entities in Criteria projections - * #910 NH-3606 - Open a stateless session from a session - * #908 NH-3470 - Allow Linq Query to load entities as read-only - -** Improvement - - * #1600 Set MySqlClientBatchingBatcher as a default batcher for MySqlDataDriver - * #1597 Add support for single-argument truncate to dialects that do not support it natively - * #1569 Modernize test example - * #1567 Avoid Trim().Length as empty check and ToLowerInvariant() in string comparison - * #1561 NAnt refactoring - * #1558 Improved collection batch fetching - * #1557 Aggregate named queries validation exceptions. - * #1555 Catch practices: avoid losing catched exception information. - * #1552 Obsolete UnmodifiableDictionary - * #1549 Remove an override which was doing the same thing as the base - * #1548 Add a missing short circuit in query parameter expansion. - * #1547 Double query translation - * #1546 Remove a redundant argument in Linq provider ExecuteQuery. - * #1543 Various string manipulation optimizations - * #1541 Cache subclass entity aliases in Loader - * #1537 Avoid unnecessary persister lookup in Loader - * #1529 Lazy mapping schema loading - * #1521 Enable warning as error for all projects and configurations - * #1519 Reuse SchemaExport in CreateSchema/DropSchema in tests - * #1515 Make NHibernateUtil.Initialize / IsInitialized better reusable for sub-projects like Envers - * #1504 More reliable SQLite handling in tests. - * #1502 Upgrade Iesi to 4.0.3 in order to use a release assembly - * #1498 Cease throwing bare Exception - * #1494 Update to Oracle installation instructions. - * #1490 Optimize empty arrays usages - * #1483 Clean-up of TypeFactory - * #1482 Refactored DefaultEntityAliases to avoid unnecessary calculations - * #1477 Reuse the same generic EmptyMapClass instance across the project - * #1475 Document expiration constraint on UpdateTimestampsCache region. - * #1467 Reduce the number of calls to UpdateTimestampsCache - * #1466 Obsolete EqualsHelper - * #1465 Obsolete EnumerableExtensions - * #1464 Obsolete ISessionImplementor.Initialize method - * #1449 Document IsDirty potential side effects - * #1441 Normalize TargetInvocationException unwrapping - * #1417 Table counter for aliases should be stable - * #1412 Store Linq query options in a query provider instead of a queryable - * #1391 Performance regression in SessionIdLoggingContext - * #843 NH-3879 - SequenceHiLoGenerator Jumps 1 number each lo > maxLo - * #842 NH-3869 - Add a way of adding comments into LINQ queries - * #837 NH-3804 - Register CHR/CHAR, NCHAR, UNICODE, and ASCII standard functions to the dialect(s) - * #831 NH-3515 - Support for Decimal.Round, Decimal.Ceiling, Decimal.Floor and other static methods of Decimal class - * #768 NH-3921 - Support sequences in Ingres9Dialect - * #769 NH-3922 - The various timeout methods should indicate time unit - -** Task - - * #1610 Move MsSql constants from driver to dialect. - * #1608 Missing Async test for GH1594 - * #1603 Forgotten async generation of truncate test - * #1598 Upgrade IESI to 4.0.4 for having a bumped file version. - * #1589 Add framework info to example web project and enable .NET Core. - * #1574 Fix encoding in NorthwindDbCreator.cs - * #1563 Generate Async test for deep removal of fetch. - * #1527 Adjust ignore rules for not ignoring DebugHelpers folder and contents - * #1525 5.1.0 release - * #1524 Reduce breaking changes due to Ingres9 sequence support - * #1518 Upgrade to AsyncGenerator 0.8.1 - * #1512 Upgrade to NUnit 3.9 - * #1474 Upgrade AsyncGenerator to 0.7.0 - -** Tests - - * #1539 Add more tests for constants in LINQ queries - -As part of releasing 5.1.0, a missing 5.0.0 possible breaking change has been added about inequality semantic in LINQ -queries. See 5.0.0 possible breaking changes. - -Build 5.0.8 -============================= - -Release notes - NHibernate - Version 5.0.8 - -** Bug - * #2172 Using DependentTransaction fails - -Build 5.0.7 -============================= - -Release notes - NHibernate - Version 5.0.7 - - ##### Possible Breaking Changes ##### - * Using DML on an entity collection was applying the changes without - filtering according to the entity. It will now throw a - NotSupportedException. - -** Bug - - * #2043 System.Reflection.TargetException when an interface is used as class mapping proxy definition - * #2020 Throw for DML on filter - -** Task - * #2073 Release 5.0.7 - -Build 5.0.6 -============================= - -Release notes - NHibernate - Version 5.0.6 - -** Bug - * #1672 Generated async methods do not correctly propagate OperationCanceledException - * #1355 NH-3928 - Random invalid SQL generated when using bitwise operators - -** Task - * #1686 Release 5.0.6 - -Build 5.0.5 -============================= - -Release notes - NHibernate - Version 5.0.5 - -** Bug - * #1665 Have IFutureEnumerable.GetEnumerable executing immediatly the query - -Build 5.0.4 -============================= - -Release notes - NHibernate - Version 5.0.4 - -** Bug - * #1658 Add missing cache setting - -Build 5.0.3 -============================= - -Release notes - NHibernate - Version 5.0.3 - -** Bug - * #1462 Fix disposing SessionIdLoggingContext if CheckAndUpdateSessionStatus is failed - -Build 5.0.2 -============================= - -Release notes - NHibernate - Version 5.0.2 - -** Bug - * #1456 NH-4052 - Add missing serializable implementation - * #1455 Reduces check session and set context id redundant calls - * #1453 Eliminate unnecessary AsyncLocal allocation if SessionId isn't changed - -** Task - * #1457 Release 5.0.2 - -As part of releasing 5.0.2, a missing 5.0.0 possible breaking change has been added about Dialects requiring now -to be configured. See 5.0.0 possible breaking changes. - -Build 5.0.1 -============================= - -Release notes - NHibernate - Version 5.0.1 - -** Bug - * #1428 Insert underscore in combined parameter name - * #1424 Bad wording and example fixes in cache documentation. - * #1420 Fix #1419 - ISession.IsDirty() shouldn't throw exception for transient many-to-one object in a session - * #1419 ISession.IsDirty() shouldn't throw exception for transient many-to-one object in a session - * #1418 Column.GetAlias should account for other suffixes - * #1415 Correct MaxAliasLength for various dialects - * #1393 Fix Linq Future aggregates failures, fixes #1387 - * #1389 Add support for out/ref Nullable parameters of proxied methods - * #1387 Linq Sum() with ToFutureValue fails - * #1384 Fix a column spec causing missing col in pdf, fix a text overflow - * #1380 #750 - AliasToBean failure, test case and fix - * #1378 Fix #1362 - Running Unit tests against SQLite fails on datetime/UTC - * #1362 NH-4093 - Running Unit tests against SQLite fails on numerous (22) datetime/UTC related tests. - * #1357 NH-3983 - ToFuture throws ArgumentException at CreateCombinedQueryParameters - * #1179 NH-3840 - Wrong documentation of "cascade" in 5.1.11 (many-to-one) - * #1165 NH-3554 - Docs - bidirectional, indexed collections - * #983 Fix forgotten CDATA closure. - * #879 NH-4006 - Provide a correct MaxAliasLength for various dialects - * #750 Transformers.AliasToBean: Value cannot be null. Parameter name: key - * #712 NH-4092 - AsyncGenerator creates unused private static event handler in SQLite20Driver - -** Improvement - * #1410 Remove unused code in build scripts - * #1404 Use MsBuild for packing .nupkg files - * #1401 Clean up db tests dependencies - * #1395 Documentation fixes - * #1386 Lack of custom logging documentation - * #1382 Jira to GitHub: change issue naming in tests - * #1379 Documentation fixes - * #982 Back port doc fixes - * #824 NH-3208 - Document all possible settings in hibernate.cfg - * #823 NH-3179 - Documentation should note that OnDelete should set IsSaved to false in chapter 24.1 - * #788 NH-1947 - Undocumented attributes on sql-query element - * #713 Switch to GitHub issues - * #711 Switch doc generation to UTF-8. - -** Task - * #1431 Release 5.0.1 - * #1405 Remove unused and broken NHibernate.Setup WiX project - - -Build 5.0.0 -============================= - -** Highlights - * IO bound methods have gained an async counterpart. Not intended for parallelism, make sure to await each - call before further interacting with a session and its queries. - * Strongly typed DML operation (insert/update/delete) are now available as Linq extensions on queryables. - * Entities collections can be queried with .AsQueryable() Linq extension without being fully loaded. - * Reference documentation has been curated and completed, notably with a Linq section. - http://nhibernate.info/doc/nhibernate-reference/index.html - -** Known BREAKING CHANGES from NH4.1.1.GA to 5.0.0 - - NHibernate now targets .Net 4.6.1. - - Remotion.Linq and Antlr3 libraries are no more merged in the NHibernate library, - and must be deployed along NHibernate library. (NuGet will reference them.) - - Classes and members which were flagged as obsolete in the NHibernate 4.x series have been dropped. - Prior to upgrading, fix any obsolete warning according to its message. See NH-4075 and NH-3684 for a list. - - ##### Possible Breaking Changes ##### - * All members exposing some System.Data types have been changed for the corresponding System.Data.Common - types. (IDbCommand => DbCommand, ...) - * The Date NHibernate type will no more replace by null values below its base value (which was year 1753). - Its base value is now DateTime.MinValue. Its configuration parameter is obsolete. - * NHibernate type DateTimeType, which is the default for a .Net DateTime, does no longer cut fractional - seconds. Use DateTimeNoMsType if you wish to have fractional seconds cut. It applies to its Local/Utc - counterparts too. - * LocalDateTimeType and UtcDateTimeType do no more accept being set with a value having a non-matching kind, - they throw instead. - * DbTimestamp will now round the retrieved value according to Dialect.TimestampResolutionInTicks. - * When an object typed property is mapped to a NHibernate timestamp, setting an invalid object in the - property will now throw at flush instead of replacing it with DateTime.Now. - * Decimal type registration now correctly handles maximal precision. For most dialects, it is 28, matching - the .Net limit. Values in mappings above maximal precision will be reduced to maximal precision. - * Default cast types do no more resolve string to 255 length and decimal to its default precision/scale for - the dialect. They resolve to 4000 length string and (28, 10) precision/scale decimals by default, and are - trimmed down according to dialect. Those defaults can be overridden with query.default_cast_length, - query.default_cast_precision and query.default_cast_scale settings. - * Future queries with data provider not actually supporting them (not supporting mutliple queries in a single - SQL command) are no more immediately executed at the .Future call. They are executed only when directly - enumerated or when their IFutureEnumerable.GetEnumerable method is called. (This aligns them with the behavior - of FutureValue.) - * Dialects are now configurable. If you instantiate a dialect directly, make sure you call its Configure - method, with as argument the properties of a NHibernate Configuration object. You may use instead - Dialect.GetDialect methods, which configure the dialect before returning it. - * Transaction scopes handling has undergone a major rework. See NH-4011 for full details. - ** More transaction promotion to distributed may occur if you use the "flush on commit" feature with - transaction scopes. Explicitly flush your session instead. Ensure it does not occur by disabling - transaction.use_connection_on_system_prepare setting. - ** After transaction events no more allow using the connection when they are raised from a scope - completion. - ** Connection enlistment in an ambient transaction is now enforced by NHibernate by default. - ** The connection releasing is no more directly triggered by a scope completion, but by later - interactions with the session. - * AdoNetWithDistributedTransactionFactory has been renamed AdoNetWithSystemTransactionFactory. - * Subcriteria.UniqueResult for value types now return default(T) when result is null, as was - already doing CriteriaImpl.UniqueResult. - * AliasToBeanResultTransformer property/field resolution logic has changed for supporting members - which names differ only by case. See NH-3693 last comments for details. - * Linq inequality implementation has been changed for supporting null, meaning that a "a != b" expression - will now be considered matching if one side is null, while previously due to SQL null semantic it was - considered non-matching. See NH-3100. - * Linq extension methods marked with attribute LinqExtensionMethod will no more be evaluated - in-memory prior to query execution when they do not depend on query results, but will always be - translated to their corresponding SQL call. This can be changed with a parameter of the attribute. - * Linq Query methods are now native members of ISession and IStatelessSession instead of being - extension methods. - * Linq provider now use Remotion.Linq v2, which may break Linq provider extensions, mainly due to names - changes. See https://github.com/nhibernate/nhibernate-core/pull/568 changes to test files for examples. - * NHibernate Linq internals have undergone some minor changes which may break custom Linq providers due - to method signature changes and additional methods to implement. - * IMapping interface has an additional Dialect member. ISessionFactoryImplementor has lost it, since it - gains it back through IMapping. - * IDriver.ExpandQueryParameters and DriverBase.CloneParameter take an additional argument. - * NullableType, its descendent (notably all PrimitiveType) and IUserType value getters and setters now - take the session as an argument. This should mainly impact custom types implementors. - * EmitUtil is now internal and has been cleaned of unused members. - * ContraintOrderedTableKeyColumnClosure has been renamed ConstraintOrderedTableKeyColumnClosure. - * enabledFilter parameter has been removed from IProjection.ToSqlString and ICriterion.ToSqlString methods. - * Proxy factory and proxy cache now use TypeInfo instead of System.Type. This should be transparent for - most users. - * Exceptions which were based on ApplicationException are now based on Exception: HibernateException, - ParserException and AssertionFailure. The logger factory which could throw a bare ApplicationException - now throws an InstantiationException instead. - * ThreadSafeDictionary class has been removed. Use System.Collections.Concurrent.ConcurrentDictionary - instead. - * Entity mode switching capability, which had never been fully implemented, is dropped. - * BytecodeProviderImpl, intended for .Net Framework 1 and broken, is dropped. - * Sessions concrete classes constructors have been changed. (It is not expected for them to be used - directly.) - * Obsolete setting interceptors.beforetransactioncompletion_ignore_exceptions is dropped. - * SQL Server 2008+ dialects now use datetime2 instead of datetime for all date-time types, including - timestamp. This can be reverted with sql_types.keep_datetime setting. - * SQL Server 2008+ timestamp resolution is now 100ns in accordance with datetime2 capabilities, down from - 10ms previously. This can be reverted with sql_types.keep_datetime setting. - * Oracle 9g+ dialects now use timestamp(7) for all date time types, instead of timestamp(4). - * Oracle 9g+ timestamp resolution is now 100ns in accordance with timestamp(7) capabilities, down from - 100µs previously. - * Oracle: Hbm2dll will no-more choose N- prefixed types for typing Unicode string columns by default. - This can be changed with oracle.use_n_prefixed_types_for_unicode setting, which will furthermore - control DbCommand parameters typing accordingly. See NH-4062. - * SqlServerCe: the id generator "native" will now resolve as table-hilo instead of identity. - * Firebird: timestamp resolution is now 1ms. - * PostgreSQL: if Npgsql v3 or later is used, time DbParameters will be fetched as TimeSpan instead of - DateTime. - * DB2 & Oracle lite: decimal type registration was hardcoding precision as 19 and was using length as - scale. It now uses precision and scale from mapping when specified, and disregards length. - * Ingres & Sybase ASA: decimal type registration was hardcoding precision as 18 and was using length as - scale. It now uses precision and scale from mapping when specified, and disregards length. - * ODBC: String parameter length will no more be specified by the OdbcDriver. - - -Release notes - NHibernate - Version 5.0.0 - -** Sub-task - * [NH-3956] - Native SQL query plan may get wrong plan - * [NH-3957] - Second level query cache may yields wrong cache entry - * [NH-4001] - Remove ThreadSafeDictionary - -** Bug - * [NH-926] - Identity insert fails with SQL Ce dialect and aggressive connection release mode. - * [NH-1752] - NHibernate Date type converts to NULL - * [NH-1904] - Protected properties and public properties cannot have the same name with different case - * [NH-2029] - filter-def's use-many-to-one=false should take ON into consideration - * [NH-2145] - AssertionFailure exception at ISession.Save - * [NH-2176] - Consecutive TransactionScopes cannot be used in same NHibernate session - * [NH-2238] - "DTC transaction prepare phase failed" when UPDATE:ing in a promoted TransactionScope - * [NH-2241] - Batch Insert using stateless session when using second level cache throws exception when unable to determine transient status - * [NH-2928] - Connections can only be closed after the Transaction is completed - * [NH-3023] - Deadlocks may cause connection pool corruption when in a distributed transaction - * [NH-3078] - TimeAsTimeSpanType issue when using Sybase Advantage Database - * [NH-3100] - Problem in use if condition for nullable boolean in linq to NHibernate - * [NH-3114] - Collection inside Component cannot be mapped to a different table - * [NH-3227] - InvalidOperationException in AbstractBatcher when distributed transaction is aborted - * [NH-3247] - Char value gets 'cached' in Where-queries - * [NH-3374] - Session.Merge throws InvalidCastException when using a Lazy bytes[] property - * [NH-3600] - ISession.Save returns wrong Id - * [NH-3665] - FirstOrDefault() broken since 3.3.4 and 3.4.0 - * [NH-3693] - AliasToBeanResultTransformerFixture fails under Firebird - * [NH-3755] - Proxy exception for multiple joined-subclass - * [NH-3757] - Dynamic entity mapped with entity-name cannot have a component of a fixed class - * [NH-3793] - Attribute entity-name on is ignored, causing mapping exception - * [NH-3845] - OfType fails with polymorphism - * [NH-3850] - .Count(), .Any() and other aggregates return only first result on polymorphic queries - * [NH-3885] - ThreadSafeDictionary is not threadsafe - * [NH-3889] - Coalesce on entity in sub-select causes incorrect SQL - * [NH-3895] - Problem with DateTime fractional seconds on ODBC for MS SQL Server - * [NH-3911] - Reflection Optimizer tries to cast values to getter type in setter - * [NH-3913] - Component has bag of child components. Child property mapping ignored - * [NH-3931] - Invalid order of child inserts when using TPH inheritance - * [NH-3946] - Linq where "is base class" doesn't get subclasses - * [NH-3948] - CheckAndUpdateSessionStatus() called twice in CreateFilter method inside SessionImpl class - * [NH-3950] - FutureValue fails on Linq queries defining a PostExecuteTransformer - * [NH-3954] - Dynamic proxy cache may yield a wrong proxy - * [NH-3955] - Unreliable Equals implementation - * [NH-3961] - Invalid date parameter format with nullables and MappedAs - * [NH-3966] - Missing command set dispose in batchers - * [NH-3968] - Distributed transaction cannot be committed because AdoNetWithDistributedTransactionFactory tries to write data by using locked sqlConnection - * [NH-3969] - Firebird: TimestampResolutionInTicks should be 1ms - * [NH-3977] - Thread safety weaknesses of MapBasedSessionContext - * [NH-3981] - CollectionHelper.DictionaryEquals throws - * [NH-3985] - ObjectDisposedException is thrown when using a child session after having previously disposed of another child session. - * [NH-3998] - SqlServer CE: "The column aliases must be unique" exception is thrown in some tests - * [NH-4013] - SqlClientBatchingBatcher CloseCommands contract violated - * [NH-4022] - MsSql2012Dialect: Invalid drop sequence statement - * [NH-4024] - ODBC failures with time - * [NH-4027] - Missing disposals of enumerators - * [NH-4035] - Teardown failure should not prevent cleanup - * [NH-4038] - Mapping a TimeSpan in a collection component mapping maps as a BIGINT - * [NH-4046] - Default length too short for variable length types with SAP Anywhere / ASE - * [NH-4077] - Possible race condition in ActionQueue.ExecuteActions - * [NH-4083] - ODBC nvarchar parameter corruption - * [NH-4084] - DbTimestamp cause stale update exception - * [NH-4086] - TimeType may lose fractional seconds - * [NH-4088] - Dialect.GetCastTypeName is buggy - * [NH-4090] - Prepare SQL fails with time parameters and SQL Server 2008+ - * [NH-4091] - SQL Server CE allocates too much memory with blob and sql prepare - -** New Feature - * [NH-1530] - Add support for XmlDocType and XDocType for Oracle - * [NH-2319] - IQueryable support for persistent collections - * [NH-3488] - Strongly Typed Updates and Deletes - * [NH-3771] - Implement setting to enable Batch Update with Optimistic Locking control - * [NH-3905] - Support async: Blocking IO leads to ThreadPool starvation and limits scalability - * [NH-3934] - Add methods WhereNot(ICriterion) and AndNot(ICriterion) in QueryOver - * [NH-3951] - Support .All() result operator - * [NH-3996] - Postgres: add support for XmlDocType and XDocType - * [NH-4009] - Allow marking a Linq extension as db only - * [NH-4017] - Handle Time parameter conversion for newer Npgsql - * [NH-4018] - Port AutoJoinTransaction feature - * [NH-4028] - Support inconclusive tests in result comparison - * [NH-4031] - Add an AsyncLocalSessionContext - * [NH-4032] - Supports multiple factories with ThreadStaticSessionContext - * [NH-4062] - Properly handle Oracle Unicode support dual model - -** Task - * [NH-3683] - Fix Compilation Warnings - * [NH-3958] - Reference documentation: missing types - * [NH-3959] - Fix documentation typos - * [NH-3999] - Document effect of quoted identifier on case sensitivity - * [NH-4000] - Release 5.0 - * [NH-4004] - Restrict tests running on SQL CE - * [NH-4051] - Replace System.Linq.Dynamic with System.Linq.Dynamic.Core in tests - * [NH-4057] - Fix tests for MySql - * [NH-4058] - Fix Oracle managed failing tests - * [NH-4063] - Fix ODBC failing tests - -** Improvement - * [NH-1851] - Mapping a TimeSpan as TimeAsTimeSpan for MySQL - * [NH-2444] - Document linq provider - * [NH-3094] - Linq does not support unary plus and unary minus operators - * [NH-3370] - Remove warning about "NHibernate.Type.CustomType -- the custom type * is not serializable" - * [NH-3386] - Linq OrderBy NewID() - * [NH-3431] - Replace System.Data with System.Data.Common - * [NH-3578] - Subcriteria.UniqueResult for value types should return default(T), same as CriteriaImpl.UniqueResult when result is null - * [NH-3669] - Query should be instance method of ISession - * [NH-3723] - Some tests are failing when log level set to DEBUG - * [NH-3744] - Fixed spelling of ContraintOrderedTableKeyColumnClosure method - * [NH-3750] - Use NuGet to refer to Remotion.Linq (unmerge ReMotion.Linq) - * [NH-3877] - Target .NET 4.6.1 - * [NH-3900] - Upgrade to Nunit 3.x - * [NH-3919] - Clean up and harmonize datetime types with regards to different dialects - * [NH-3927] - Switch to SemVer version scheme - * [NH-3932] - Merge() may fire unnecessary updates if collection and version mapping exists - * [NH-3943] - Use NuGet to reference packages instead of local copies - * [NH-3944] - Upgrade to ReLinq 2 - * [NH-3945] - Update to Antlr 3.5.1 - * [NH-3952] - Cleanup EnumerableHelper usage - * [NH-3962] - Build with MSBuild Tools 2017 (15) - * [NH-3963] - More explicit error on MappedAs invalid usage. - * [NH-3964] - Refactor reflection patterns - * [NH-3970] - TestCase base class: avoid hiding test failure on tear-down - * [NH-3973] - Remove enabledFilter parameter from IProjection.ToSqlString and ICriterion.ToSqlString methods - * [NH-3975] - Synchronize some features dialect support properties - * [NH-3978] - Extract IDatabaseMetadata from DatabaseMetadata - * [NH-3987] - Re-implement NhQueryable options - * [NH-3988] - Replace ApplicationException base class with just Exception - * [NH-3990] - Upgrade to VS2017 Project structure - * [NH-3993] - Component Element Customizer Missing ability to map non-public parents and composite element relations - * [NH-3997] - SqlServer CE: Make native generator to be TableHiLoGenerator - * [NH-4003] - Refactor session constructor - * [NH-4010] - Visual Studio launcher still launches 2015 - * [NH-4014] - Update SQLite assembly for tests - * [NH-4015] - Update Npgsql driver and enable DTC for it in tests - * [NH-4019] - Pass assembly into log4net functions - * [NH-4020] - Use TypeBuilder.CreateTypeInfo() - * [NH-4021] - Track all opened session in tests - * [NH-4023] - Pass ISessionImplementor to all value setters and getters of nullable types - * [NH-4026] - Update Firebird driver and use server in tests - * [NH-4030] - Cleanup and xml doc of Linq Future extension - * [NH-4033] - Update MySql connector used in tests - * [NH-4034] - Flush all sessions participating in a transaction - * [NH-4043] - Complete keyword registration needs done in dialects. - * [NH-4049] - EmitUtil can be cleaned up - * [NH-4050] - Use Task.Run instead of BeginInvoke in tests - * [NH-4052] - Collect schema validation exceptions - * [NH-4064] - Unmerge Antrl3.Runtime - * [NH-4073] - Replace NHibernate.Web.Example with modern version - * [NH-4076] - Do not resurrect session - -** Remove Feature - * [NH-3684] - Remove