diff --git a/Results/DB.cs b/Results/DB.cs
index 1bc7a5d0f..23f06a0a2 100644
--- a/Results/DB.cs
+++ b/Results/DB.cs
@@ -11,6 +11,7 @@ using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using Common;
using Results.Entities;
+using Results.Entities.helpers;
namespace Results
{
@@ -107,7 +108,11 @@ namespace Results
throw new Exception("Connection string was not specified");
}
- if (SessionFactory == null) SessionFactory = CreateSessionFactory();
+ if (SessionFactory == null)
+ {
+ DatabaseMigrationHelper.EnsureSchema(dbType, connectionString);
+ SessionFactory = CreateSessionFactory();
+ }
return SessionFactory.OpenSession();
}
diff --git a/Results/Entities/MeterTestRslt.cs b/Results/Entities/MeterTestRslt.cs
index beb66d7c2..3ca3854a3 100644
--- a/Results/Entities/MeterTestRslt.cs
+++ b/Results/Entities/MeterTestRslt.cs
@@ -41,6 +41,7 @@ namespace Results.Entities
public virtual int CalibFactorLNA { get; set; }
public virtual int Q2CorrRL { get; set; }
public virtual int Q2CorrLR { get; set; }
+ public virtual int? FlipMode { get; set; } /// null=not recorded, 0=Constant, 1=Randomized
public virtual string ExtraDataPath { get; set; } /// Relative path to a file with opto-data/raw-data
public virtual float X1 { get; set; }
public virtual float X2 { get; set; }
@@ -207,6 +208,7 @@ namespace Results.Entities
CalibFactorLNA = src.CalibFactorLNA;
Q2CorrRL = src.Q2CorrRL;
Q2CorrLR = src.Q2CorrLR;
+ FlipMode = src.FlipMode;
ExtraDataPath = src.ExtraDataPath;
X1 = src.X1;
X2 = src.X2;
diff --git a/Results/Entities/helpers/DatabaseMigrationHelper.cs b/Results/Entities/helpers/DatabaseMigrationHelper.cs
new file mode 100644
index 000000000..6481ed596
--- /dev/null
+++ b/Results/Entities/helpers/DatabaseMigrationHelper.cs
@@ -0,0 +1,144 @@
+using System;
+using MySql.Data.MySqlClient;
+using Common;
+
+namespace Results.Entities.helpers
+{
+ ///
+ /// Applies small, explicit and backwards-compatible results DB migrations
+ /// before NHibernate creates its first session factory.
+ ///
+ public static class DatabaseMigrationHelper
+ {
+ public static void EnsureSchema(DBType dbType, string connectionString)
+ {
+ switch (dbType)
+ {
+ case DBType.MySql:
+ EnsureMySqlSchema(connectionString);
+ break;
+
+ case DBType.SQLite:
+ EnsureSQLiteSchema(connectionString);
+ break;
+ }
+ }
+
+ private static void EnsureMySqlSchema(string connectionString)
+ {
+ using (var conn = new MySqlConnection(connectionString))
+ {
+ conn.Open();
+
+ // Q3Channel migrations from develop/SLM-PT50_genesisDirectDecode_special_2.
+ // Kept as a visible template only; the related Q3 logic is not part of this change.
+ // EnsureColumnMySql(conn, "WaterMeterData", "Q3Channel", "INT NOT NULL DEFAULT 0");
+ // EnsureColumnMySql(conn, "WaterMeter", "Q3Channel", "INT NOT NULL DEFAULT 0");
+ // EnsureColumnMySql(conn, "MeterTestRslt", "Q3Channel", "INT NOT NULL DEFAULT 0");
+
+ EnsureColumnMySql(conn, "MeterTestRslt", "FlipMode", "INT NULL");
+ }
+ }
+
+ private static void EnsureColumnMySql(
+ MySqlConnection conn,
+ string tableName,
+ string columnName,
+ string columnDefinition)
+ {
+ using (var transaction = conn.BeginTransaction())
+ {
+ try
+ {
+ bool exists;
+
+ using (var cmd = conn.CreateCommand())
+ {
+ cmd.Transaction = transaction;
+ cmd.CommandText = @"
+ SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = @tableName
+ AND COLUMN_NAME = @columnName";
+
+ cmd.Parameters.AddWithValue("@tableName", tableName);
+ cmd.Parameters.AddWithValue("@columnName", columnName);
+ exists = Convert.ToInt32(cmd.ExecuteScalar()) > 0;
+ }
+
+ if (!exists)
+ {
+ using (var alter = conn.CreateCommand())
+ {
+ alter.Transaction = transaction;
+ alter.CommandText = "ALTER TABLE `" + tableName + "` ADD COLUMN `" +
+ columnName + "` " + columnDefinition;
+ alter.ExecuteNonQuery();
+ }
+ }
+
+ transaction.Commit();
+ }
+ catch
+ {
+ transaction.Rollback();
+ throw;
+ }
+ }
+ }
+
+ private static void EnsureSQLiteSchema(string databaseFile)
+ {
+ using (var conn = new System.Data.SQLite.SQLiteConnection("Data Source=" + databaseFile))
+ {
+ conn.Open();
+
+ // Q3Channel migrations from develop/SLM-PT50_genesisDirectDecode_special_2.
+ // Kept as a visible template only; the related Q3 logic is not part of this change.
+ // EnsureColumnSQLite(conn, "WaterMeterData", "Q3Channel", "INTEGER NOT NULL DEFAULT 0");
+ // EnsureColumnSQLite(conn, "WaterMeter", "Q3Channel", "INTEGER NOT NULL DEFAULT 0");
+ // EnsureColumnSQLite(conn, "MeterTestRslt", "Q3Channel", "INTEGER NOT NULL DEFAULT 0");
+
+ EnsureColumnSQLite(conn, "MeterTestRslt", "FlipMode", "INTEGER NULL");
+ }
+ }
+
+ private static void EnsureColumnSQLite(
+ System.Data.SQLite.SQLiteConnection conn,
+ string tableName,
+ string columnName,
+ string columnDefinition)
+ {
+ bool exists = false;
+
+ using (var cmd = conn.CreateCommand())
+ {
+ cmd.CommandText = "PRAGMA table_info(" + tableName + ")";
+
+ using (var reader = cmd.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ if (string.Equals(reader["name"].ToString(), columnName,
+ StringComparison.OrdinalIgnoreCase))
+ {
+ exists = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!exists)
+ {
+ using (var alter = conn.CreateCommand())
+ {
+ alter.CommandText = "ALTER TABLE " + tableName + " ADD COLUMN " +
+ columnName + " " + columnDefinition;
+ alter.ExecuteNonQuery();
+ }
+ }
+ }
+ }
+}
diff --git a/Results/ItemID.cs b/Results/ItemID.cs
index 131e957db..62840ffad 100644
--- a/Results/ItemID.cs
+++ b/Results/ItemID.cs
@@ -361,6 +361,7 @@ namespace Results
Unit_per_pulse_Read, /// 305
Pulses_per_unit, /// 306
+ FlipMode, /// 307 iPerl mode used for this meter test result
Count,
}
}
diff --git a/Results/Mappings/MeterTestRsltMap.cs b/Results/Mappings/MeterTestRsltMap.cs
index 9789b4608..603babf17 100644
--- a/Results/Mappings/MeterTestRsltMap.cs
+++ b/Results/Mappings/MeterTestRsltMap.cs
@@ -33,6 +33,7 @@ namespace Results.Mappings
Map(x => x.PassedMass);
Map(x => x.QuantityUnits);
#if IPERL
+ Map(x => x.FlipMode);
Map(x => x.ExtraDataPath);
Map(x => x.X1);
Map(x => x.X2);
diff --git a/Results/Results.csproj b/Results/Results.csproj
index c19b74969..b03ba382b 100644
--- a/Results/Results.csproj
+++ b/Results/Results.csproj
@@ -53,6 +53,9 @@
..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll
+
+ ..\packages\System.Data.SQLite.2.0.3\lib\net471\System.Data.SQLite.dll
+
@@ -69,6 +72,7 @@
+
diff --git a/Results/WMeterRsltItemSpec.cs b/Results/WMeterRsltItemSpec.cs
index df0c1893c..9c3e3f0d7 100644
--- a/Results/WMeterRsltItemSpec.cs
+++ b/Results/WMeterRsltItemSpec.cs
@@ -136,6 +136,26 @@ namespace Results
///
AllItems.Add(new WMeterRsltItemSpec(ItemID.RR_Quantity, "RR Quantity", "", Quantity.RegisterReader, ItemCategory.Other, (w,t,u,f,p) => (w.GetMeterTestRslt(t) != null) ? FormatStr(f, w.GetMeterTestRslt(t).GetQuantityFromUnits()) : string.Empty));
AllItems.Add(new WMeterRsltItemSpec(ItemID.RR_Units, "RR Units", "", Quantity.RegisterReader, ItemCategory.Other, (w,t,u,f,p) => (w.GetMeterTestRslt(t) != null) ? FormatStr(f, w.GetMeterTestRslt(t).QuantityUnits) : string.Empty));
+#if IPERL
+ AllItems.Add(new WMeterRsltItemSpec( ItemID.FlipMode, "iPerl Flip mode ()", "Flip mode used by this water meter during the selected test",
+ Quantity.RegisterReader,
+ ItemCategory.MeterResult,
+ (w,t,u,f,p) =>
+ {
+ MeterTestRslt meterResult = w.GetMeterTestRslt(t);
+ if (meterResult == null || !meterResult.FlipMode.HasValue)
+ return string.Empty;
+
+ string value;
+ switch (meterResult.FlipMode.Value)
+ {
+ case 0: value = "Constant"; break;
+ case 1: value = "Randomized"; break;
+ default: value = string.Format("Unknown ({0})", meterResult.FlipMode.Value); break;
+ }
+ return FormatStr(f, value);
+ }));
+#endif
/// Common
AllItems.Add(new WMeterRsltItemSpec(ItemID.Test_name, Strings.Test + "()", Quantity.String, ItemCategory.TestData, (w,t,u,f,p) => FormatStr(f, (w.GetTestRslt(t) == null) ? "" : w.GetTestRslt(t).Name())));
diff --git a/TBF/Rig/TestMethods/DiverterTest/DiverterTestSeq.cs b/TBF/Rig/TestMethods/DiverterTest/DiverterTestSeq.cs
index 0ef808421..0205c7c41 100644
--- a/TBF/Rig/TestMethods/DiverterTest/DiverterTestSeq.cs
+++ b/TBF/Rig/TestMethods/DiverterTest/DiverterTestSeq.cs
@@ -731,6 +731,9 @@ namespace TBF.Rig.TestMethods.DiverterTest
meterRslt.WaterMeter.ResultCode |= iPerl.ResultCode;
}
#if IPERL
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
#endif
iPerl.LastTestResult2 = iPerl.LastTestResult; /// Save shift previous test result
diff --git a/TBF/Rig/TestMethods/Endurance/EnduranceSeq.cs b/TBF/Rig/TestMethods/Endurance/EnduranceSeq.cs
index 5369ddfd7..5ecf91c35 100644
--- a/TBF/Rig/TestMethods/Endurance/EnduranceSeq.cs
+++ b/TBF/Rig/TestMethods/Endurance/EnduranceSeq.cs
@@ -461,6 +461,11 @@ namespace TBF.Rig.TestMethods.Endurance
{
meterRslt.WaterMeter.ResultCode |= iPerl.ResultCode;
}
+#if IPERL
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
+#endif
iPerl.LastTestResult2 = iPerl.LastTestResult; /// Save shift previous test result
iPerl.LastTestResult = meterRslt; /// Save this test result
diff --git a/TBF/Rig/TestMethods/FlyingStart/FlyingStartSeq.cs b/TBF/Rig/TestMethods/FlyingStart/FlyingStartSeq.cs
index 8b81c2ce5..b4e75deb3 100644
--- a/TBF/Rig/TestMethods/FlyingStart/FlyingStartSeq.cs
+++ b/TBF/Rig/TestMethods/FlyingStart/FlyingStartSeq.cs
@@ -737,6 +737,9 @@ namespace TBF.Rig.TestMethods.FlyingStart
}
#if IPERL
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
meterRslt.ExtraDataPath = iPerl.ExtraDataPath;
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 1)
meterRslt.X1 = iPerl.X[0];
diff --git a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/FlyingStartFirstRepetWithMassCollSeq.cs b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/FlyingStartFirstRepetWithMassCollSeq.cs
index e1e6ecc10..2df168498 100644
--- a/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/FlyingStartFirstRepetWithMassCollSeq.cs
+++ b/TBF/Rig/TestMethods/FlyingStartFirstRepetWithMassColl/FlyingStartFirstRepetWithMassCollSeq.cs
@@ -942,6 +942,9 @@ namespace TBF.Rig.TestMethods.FlyingStartFirstRepetWithMassColl
}
#if IPERL
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
#endif
iPerl.LastTestResult2 = iPerl.LastTestResult; /// Save shift previous test result
iPerl.LastTestResult = meterRslt; /// Save this test result
diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/FlyingStartMassCollComparativeSeq.cs b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/FlyingStartMassCollComparativeSeq.cs
index b92cdc938..bbb37c6a1 100644
--- a/TBF/Rig/TestMethods/FlyingStartMassCollComparative/FlyingStartMassCollComparativeSeq.cs
+++ b/TBF/Rig/TestMethods/FlyingStartMassCollComparative/FlyingStartMassCollComparativeSeq.cs
@@ -989,6 +989,9 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollComparative
meterRslt.WaterMeter.ResultCode |= iPerl.ResultCode;
}
#if IPERL
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
#endif
iPerl.LastTestResult2 = iPerl.LastTestResult; /// Save shift previous test result
diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/FlyingStartMassCollProlongedSeq.cs b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/FlyingStartMassCollProlongedSeq.cs
index bd7235132..c0be7ca24 100644
--- a/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/FlyingStartMassCollProlongedSeq.cs
+++ b/TBF/Rig/TestMethods/FlyingStartMassCollProlonged/FlyingStartMassCollProlongedSeq.cs
@@ -874,6 +874,9 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollProlonged
}
#if IPERL
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
meterRslt.ExtraDataPath = iPerl.ExtraDataPath;
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 1) meterRslt.X1 = iPerl.X[0];
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 2) meterRslt.X2 = iPerl.X[1];
diff --git a/TBF/Rig/TestMethods/FlyingStartMassCollection/FlyingStartMassCollectionSeq.cs b/TBF/Rig/TestMethods/FlyingStartMassCollection/FlyingStartMassCollectionSeq.cs
index a5e6054df..6655064f3 100644
--- a/TBF/Rig/TestMethods/FlyingStartMassCollection/FlyingStartMassCollectionSeq.cs
+++ b/TBF/Rig/TestMethods/FlyingStartMassCollection/FlyingStartMassCollectionSeq.cs
@@ -1179,6 +1179,9 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
}
#if IPERL
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
meterRslt.ExtraDataPath = iPerl.ExtraDataPath;
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 1) meterRslt.X1 = iPerl.X[0];
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 2) meterRslt.X2 = iPerl.X[1];
diff --git a/TBF/Rig/TestMethods/FlyingStartTankCollection/FlyingStartTankCollectionSeq.cs b/TBF/Rig/TestMethods/FlyingStartTankCollection/FlyingStartTankCollectionSeq.cs
index 01e9ed488..80ef616e1 100644
--- a/TBF/Rig/TestMethods/FlyingStartTankCollection/FlyingStartTankCollectionSeq.cs
+++ b/TBF/Rig/TestMethods/FlyingStartTankCollection/FlyingStartTankCollectionSeq.cs
@@ -633,6 +633,9 @@ namespace TBF.Rig.TestMethods.FlyingStartTankCollection
meterRslt.WaterMeter.ResultCode |= iPerl.ResultCode;
}
#if IPERL
+ meterRslt.FlipMode = iPerl.ConfigStruct != null && iPerl.ConfigStruct.FlipMode.HasValue
+ ? (int?)iPerl.ConfigStruct.FlipMode.Value
+ : null;
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
#endif
iPerl.LastTestResult2 = iPerl.LastTestResult; /// Save shift previous test result
diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs
index 05223a3c1..94dc7e846 100644
--- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs
+++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs
@@ -1214,12 +1214,6 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
config.ReadingUnits.Value.ToString();
}
- if (config.FlipMode.HasValue)
- {
- wm.RadioAddress =
- config.FlipMode.Value.ToString();
- }
-
if (config.Calibration != null)
{
wm.CalibFactor =
@@ -1231,7 +1225,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
"FWVersion={0}, ReadingUnits={1}, FlipMode={2}, CalibFactor={3}",
wm.FWVersion,
wm.SerialNrAux,
- wm.RadioAddress,
+ config.FlipMode.HasValue ? config.FlipMode.Value.ToString() : "",
wm.CalibFactor);
}
else